diff --git a/run.sh b/run.sh
index e42c38753af62fcadf5b338dac66de68550a8658..d99c3395294356fac7a81b696461e7a2ca64c89b 100755
--- a/run.sh
+++ b/run.sh
@@ -4,12 +4,15 @@ task="$1"
 input="$2"
 output="$3"
 
+# recolic: I edited class FuncDef so place target/assignment.jar before chocopy-ref.jar!
+classPath="target/assignment.jar:chocopy-ref.jar"
+
 if [[ "$task" = parse ]]; then
-    java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy --pass=r --out "$output" "$input"
+    java -cp "$classPath" chocopy.ChocoPy --pass=r --out "$output" "$input"
 elif [[ "$task" = type ]]; then
-    java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy --pass=.s --out "$output" "$input"
+    java -cp "$classPath" chocopy.ChocoPy --pass=.s --out "$output" "$input"
 elif [[ "$task" = ass ]]; then
-    java -cp "chocopy-ref.jar:target/assignment.jar" chocopy.ChocoPy --pass=.s --dir src/test/data/pa2/sample --test
+    java -cp "$classPath" chocopy.ChocoPy --pass=.s --dir src/test/data/pa2/sample --test
 fi
 
 exit $?
diff --git a/src/main/java/chocopy/common/analysis/SymbolTable.java b/src/main/java/chocopy/common/analysis/SymbolTable.java
index da10666416d6bf6b4afe0298346c21cb7d65fd2e..930ea9da597d163b60dccee3317d89c7144c773b 100644
--- a/src/main/java/chocopy/common/analysis/SymbolTable.java
+++ b/src/main/java/chocopy/common/analysis/SymbolTable.java
@@ -62,4 +62,8 @@ public class SymbolTable<T> {
         return this.parent;
     }
 
+    public boolean isEmpty() {
+        return tab.isEmpty();
+    }
+
 }
diff --git a/src/main/java/chocopy/common/astnodes/FuncDef.java b/src/main/java/chocopy/common/astnodes/FuncDef.java
index 35070d32f27bbbd61d720b89b641bedf9b16e8ef..8913791e3889754bad12dca6a6bf4465b08bcc4f 100644
--- a/src/main/java/chocopy/common/astnodes/FuncDef.java
+++ b/src/main/java/chocopy/common/astnodes/FuncDef.java
@@ -21,7 +21,7 @@ public class FuncDef extends Declaration {
     /** Other statements. */
     public final List<Stmt> statements;
 
-    // Recolic
+    // recolic
     public SymbolTable<SymbolType> symTable = null;
 
     /** The AST for
diff --git a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
index 1130fe7626dfa10b5394ba1e4a2155fef51387aa..839bf960b6013de6f9d49bddab13c254eaa4a4d6 100644
--- a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
+++ b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
@@ -66,9 +66,9 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<SymbolType> {
 
     @Override
     public SymbolType analyze(FuncDef funcDef) {
-        System.out.println("debug: start funcDef");
+        System.out.println("debug: start funcDef: " + funcDef.getClass().getName());
         assert funcDef.symTable == null;
-        sym = funcDef.symTable = new SymbolTable<>(sym);
+        sym = funcDef.symTable = new SymbolTable<SymbolType>(sym);
 
         // Func parameter list
         for(TypedVar param : funcDef.params) {
diff --git a/src/main/java/chocopy/pa2/TypeChecker.java b/src/main/java/chocopy/pa2/TypeChecker.java
index 7f3f77c16a973c5621de82471fd9f86f6821a88d..3aeb45c44ad88bb26a7220bf9d1b9c64ec6516bf 100644
--- a/src/main/java/chocopy/pa2/TypeChecker.java
+++ b/src/main/java/chocopy/pa2/TypeChecker.java
@@ -65,26 +65,85 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     }
 
     @Override
-    public SymbolType analyze(BinaryExpr e) {
-        SymbolType t1 = e.left.dispatch(this);
-        SymbolType t2 = e.right.dispatch(this);
-
-        switch (e.operator) {
-        case "-":
-        case "*":
-        case "//":
-        case "%":
-            if (INT_TYPE.equals(t1) && INT_TYPE.equals(t2)) {
-                return e.setInferredType(INT_TYPE);
-            } else {
-                err(e, "Cannot apply operator `%s` on types `%s` and `%s`",
-                    e.operator, t1, t2);
-                return e.setInferredType(INT_TYPE);
-            }
-        default:
-            return e.setInferredType(OBJECT_TYPE);
+    public SymbolType analyze(BinaryExpr node) {
+        String op = node.operator;
+        SymbolType left_type = node.left.dispatch(this);
+        SymbolType right_type = node.right.dispatch(this);
+
+        //switch (e.operator) {
+        //case "-":
+        //case "*":
+        //case "//":
+        //case "%":
+        //    if (INT_TYPE.equals(t1) && INT_TYPE.equals(t2)) {
+        //        return e.setInferredType(INT_TYPE);
+        //    } else {
+        //        err(e, "Cannot apply operator `%s` on types `%s` and `%s`",
+        //            e.operator, t1, t2);
+        //        return e.setInferredType(INT_TYPE);
+        //    }
+        //default:
+        //    return e.setInferredType(OBJECT_TYPE);
+        //}
+
+
+        switch(op) {
+            case "-":
+            case "*":
+            case "//":
+            case "%":
+            case ">":
+            case "<":
+            case ">=":
+            case "<=":
+                if(left_type != ValueType.INT_TYPE || right_type != ValueType.INT_TYPE)
+                    err(node, "Syntax Error: operand should be INT");
+                break;
+            case "and":
+            case "or":
+                if(left_type != ValueType.BOOL_TYPE || right_type != ValueType.BOOL_TYPE)
+                    err(node, "Syntax Error: operand should be BOOL");
+                break;
+            case "+":
+                if(left_type != ValueType.INT_TYPE && left_type != ValueType.STR_TYPE && ! left_type.isListType())
+                    err(node, "Syntax Error: operand of + should be INT or STR or LIST");
+                // fallthrough
+            case "==":
+            case "!=":
+            case "is":
+                if(node.left.getInferredType() != node.right.getInferredType())
+                    err(node, "Syntax Error: binary operator operand type mismatch");
+                break;
+            default:
+                err(node, "Syntax Error: binary operator operand type not supported.");
         }
 
+        // Now set target type.
+        SymbolType result_type = ValueType.NONE_TYPE;
+        switch(op) {
+            case "-":
+            case "*":
+            case "//":
+            case "%":
+            case "and":
+            case "or":
+            case "+":
+                result_type = left_type;
+                break;
+            case ">":
+            case "<":
+            case ">=":
+            case "<=":
+            case "==":
+            case "!=":
+            case "is":
+                result_type = ValueType.BOOL_TYPE;
+                break;
+            default:
+                throw new RuntimeException("Logic error");
+        }
+
+        return node.setInferredType(result_type);
     }
 
     @Override