diff --git a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
index 8a135a4e8a1cfa868ac3b62a8a6dfd1b555ffbee..aa8724ad6eabf9c0c52c471a9e424ee04fd8f3d7 100644
--- a/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
+++ b/src/main/java/chocopy/pa2/DeclarationAnalyzer.java
@@ -82,6 +82,10 @@ public class DeclarationAnalyzer extends AbstractNodeAnalyzer<SymbolType> {
             sym.put(name, type);
         }
 
+        // function scope ends.. backtracking...
+        sym = sym.getParent();
+        if(sym == null)
+            throw new RuntimeException("logic error: sym parent is null while returning..");
         return new FuncType(ValueType.annotationToValueType(funcDef.returnType));
     }
 
diff --git a/src/main/java/chocopy/pa2/TypeChecker.java b/src/main/java/chocopy/pa2/TypeChecker.java
index 3aeb45c44ad88bb26a7220bf9d1b9c64ec6516bf..1bf1afa15c6f20ea29ce007f6d557d9e36676706 100644
--- a/src/main/java/chocopy/pa2/TypeChecker.java
+++ b/src/main/java/chocopy/pa2/TypeChecker.java
@@ -2,17 +2,14 @@ package chocopy.pa2;
 
 import chocopy.common.analysis.AbstractNodeAnalyzer;
 import chocopy.common.analysis.SymbolTable;
+import chocopy.common.analysis.types.FuncType;
+import chocopy.common.analysis.types.ListValueType;
 import chocopy.common.analysis.types.SymbolType;
 import chocopy.common.analysis.types.ValueType;
-import chocopy.common.astnodes.BinaryExpr;
-import chocopy.common.astnodes.Declaration;
-import chocopy.common.astnodes.Errors;
-import chocopy.common.astnodes.ExprStmt;
-import chocopy.common.astnodes.Identifier;
-import chocopy.common.astnodes.IntegerLiteral;
-import chocopy.common.astnodes.Node;
-import chocopy.common.astnodes.Program;
-import chocopy.common.astnodes.Stmt;
+import chocopy.common.astnodes.*;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
 
 import static chocopy.common.analysis.types.SymbolType.INT_TYPE;
 import static chocopy.common.analysis.types.SymbolType.OBJECT_TYPE;
@@ -63,6 +60,48 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     public SymbolType analyze(IntegerLiteral i) {
         return i.setInferredType(SymbolType.INT_TYPE);
     }
+    @Override
+    public SymbolType analyze(StringLiteral node) {
+        return node.setInferredType(SymbolType.STR_TYPE);
+    }
+    @Override
+    public SymbolType analyze(NoneLiteral node) {
+        return node.setInferredType(SymbolType.NONE_TYPE);
+    }
+    @Override
+    public SymbolType analyze(BooleanLiteral node) {
+        return node.setInferredType(SymbolType.BOOL_TYPE);
+    }
+
+    @Override
+    public SymbolType analyze(AssignStmt node) {
+        SymbolType right_type = node.value.dispatch(this);
+        if(right_type == null)
+            right_type = ValueType.NONE_TYPE;
+        if(node.targets.size() == 1) {
+            String target = node.targets.get(0).toString();
+            System.out.println("debug: assign to target " + target);
+            SymbolType left_type = sym.get(target);
+            if(left_type == null) {
+                err(node, "Syntax error: assign to non-declared variable.");
+                return OBJECT_TYPE;
+            }
+            if(!left_type.equals(right_type)) {
+                err(node, "Syntax error: implicit type convertion not allowed.");
+            }
+            return right_type;
+        }
+        else {
+            if(!right_type.isListType()) {
+                err(node, "Syntax error: assign non-list type to list targets");
+                return OBJECT_TYPE;
+            }
+            ListValueType right_ls_type = (ListValueType) right_type;
+            // TODO: assign list to list
+            err(node, "Not implemented error: assign list to list");
+            return OBJECT_TYPE;
+        }
+    }
 
     @Override
     public SymbolType analyze(BinaryExpr node) {
@@ -70,23 +109,6 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
         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 "*":
@@ -96,26 +118,31 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
             case "<":
             case ">=":
             case "<=":
-                if(left_type != ValueType.INT_TYPE || right_type != ValueType.INT_TYPE)
+                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)
+                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())
+                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())
+                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.");
+                return OBJECT_TYPE;
         }
 
         // Now set target type.
@@ -146,6 +173,28 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
         return node.setInferredType(result_type);
     }
 
+    @Override
+    public SymbolType analyze(CallExpr node) {
+        SymbolType funcType = sym.get(node.function.name);
+        if(funcType == null) {
+            err(node, "calling undeclared function " + node.function.name);
+            return OBJECT_TYPE;
+        }
+        if(!funcType.isFuncType()) {
+            err(node, "calling non-function variable " + node.function.name);
+            return OBJECT_TYPE;
+        }
+        FuncType fType = (FuncType)funcType;
+        List<SymbolType> args_type = new ArrayList<SymbolType>();
+        for(Expr arg : node.args) {
+            args_type.add(arg.dispatch(this));
+        }
+        if(!fType.parameters.equals(args_type)) {
+            err(node, "function parameter type list mismatch: " + node.function.name + ". Expected " + fType.parameters.toString() + ", got " + args_type.toString());
+        }
+        return node.setInferredType(fType.returnType);
+    }
+
     @Override
     public SymbolType analyze(Identifier id) {
         String varName = id.name;