diff --git a/run.sh b/run.sh
index d99c3395294356fac7a81b696461e7a2ca64c89b..3dcbe1dd40dc36886846dea85820453abc3561fb 100755
--- a/run.sh
+++ b/run.sh
@@ -13,6 +13,8 @@ elif [[ "$task" = type ]]; then
     java -cp "$classPath" chocopy.ChocoPy --pass=.s --out "$output" "$input"
 elif [[ "$task" = ass ]]; then
     java -cp "$classPath" chocopy.ChocoPy --pass=.s --dir src/test/data/pa2/sample --test
+elif [[ "$task" = build ]]; then
+    mvn clean package > /dev/null 2>&1 && echo success || echo failed
 fi
 
 exit $?
diff --git a/src/main/java/chocopy/pa2/StudentAnalysis.java b/src/main/java/chocopy/pa2/StudentAnalysis.java
index 40aef9b4fe56066b1922726ba26ba30ae6e7bff9..0676798f61e5783947f0db46bfcc50698ab622e9 100644
--- a/src/main/java/chocopy/pa2/StudentAnalysis.java
+++ b/src/main/java/chocopy/pa2/StudentAnalysis.java
@@ -15,11 +15,12 @@ public class StudentAnalysis {
             return program;
         }
 
-        DeclarationAnalyzer declarationAnalyzer =
-            new DeclarationAnalyzer(program.errors);
-        program.dispatch(declarationAnalyzer);
-        SymbolTable<SymbolType> globalSym =
-            declarationAnalyzer.getGlobals();
+        //DeclarationAnalyzer declarationAnalyzer =
+        //    new DeclarationAnalyzer(program.errors);
+        //program.dispatch(declarationAnalyzer);
+        //SymbolTable<SymbolType> globalSym =
+        //    declarationAnalyzer.getGlobals();
+        SymbolTable<SymbolType> globalSym = new SymbolTable<>();
 
         if (!program.hasErrors()) {
             TypeChecker typeChecker =
diff --git a/src/main/java/chocopy/pa2/TypeChecker.java b/src/main/java/chocopy/pa2/TypeChecker.java
index 3a915a3df6e4d5c04dbacf5d00240ea8ad027824..8f97c7f25cb505f0ee899d62c6e16c678cd0b02d 100644
--- a/src/main/java/chocopy/pa2/TypeChecker.java
+++ b/src/main/java/chocopy/pa2/TypeChecker.java
@@ -15,11 +15,15 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
 
     /** The current symbol table (changes depending on the function
      *  being analyzed). */
-    private SymbolTable<SymbolType> sym;
+//    private SymbolTable<SymbolType> sym;
+
+    /** Current symbol table.  Changes with new declarative region. */
+    private SymbolTable<SymbolType> sym = new SymbolTable<>();
+    /** Global symbol table. */
+    private final SymbolTable<SymbolType> globals = sym;
     /** Collector for errors. */
     private Errors errors;
 
-
     /** Creates a type checker using GLOBALSYMBOLS for the initial global
      *  symbol table and ERRORS0 to receive semantic errors. */
     public TypeChecker(SymbolTable<SymbolType> globalSymbols, Errors errors0) {
@@ -34,10 +38,112 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
         errors.semError(node, message, args);
     }
 
+    @Override
+    public SymbolType analyze(VarDef varDef) {
+        SymbolType lType = varDef.value.dispatch(this);
+        SymbolType vType = varDef.var.dispatch(this);
+        if(!vType.equals(lType))
+            err(varDef, "incorrect initialization type");
+        return lType;
+    }
+
+    @Override
+    public SymbolType analyze(ClassDef classDef) {
+        assert classDef.memberMap == null;
+        classDef.memberMap = new HashMap<>();
+        assert classDef.memberMap != null;
+
+        ClassValueType result_type = new ClassValueType(classDef.name.name);
+        SymbolTable<SymbolType> symLayer = new SymbolTable<>(sym);
+        symLayer.put("self", result_type);
+        sym = symLayer;
+
+        for(Declaration decl : classDef.declarations) {
+            String name = decl.getIdentifier().name;
+            SymbolType type = decl.dispatch(this);
+            classDef.memberMap.put(name, type);
+        }
+
+        sym = sym.getParent();
+        return new ClassValueType(classDef.name.name);
+    }
+
+    @Override
+    public SymbolType analyze(FuncDef funcDef) {
+        System.out.println("debug: start funcDef: " + funcDef.getClass().getName());
+        assert funcDef.symTable == null;
+        sym = funcDef.symTable = new SymbolTable<SymbolType>(sym);
+        assert funcDef.symTable != null; // may suck if partial-compiling happens...
+
+        // Func parameter list
+        List<ValueType> args = new ArrayList<>();
+        for(TypedVar param : funcDef.params) {
+            String name = param.identifier.name;
+            ValueType type = ValueType.annotationToValueType(param.type);
+            sym.put(name, type);
+            args.add(type);
+        }
+
+        for(Declaration decl : funcDef.declarations) {
+            String name = decl.getIdentifier().name;
+            SymbolType type = decl.dispatch(this);
+            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..");
+        FuncType funcT = new FuncType(args, ValueType.annotationToValueType(funcDef.returnType));
+        return funcT;
+    }
+
+    @Override
+    public SymbolType analyze(GlobalDecl globalDecl) {
+        String name = globalDecl.variable.name;
+        SymbolType T = globals.get(name);
+        if(T == null)
+            errors.semError(globalDecl, "global id '" + name + "' not found in global scope..");
+        if(sym == globals) // ref equal
+            errors.semError(globalDecl, "global declaration '" + name + "' not allowed in global scope.");
+        //sym.put(name, T);
+        return T;
+    }
+
+    @Override
+    public SymbolType analyze(NonLocalDecl nonLocalDecl) {
+        String name = nonLocalDecl.variable.name;
+        SymbolType T = sym.get(name); // auto-iterate through the tree.
+        if(T == null)
+            errors.semError(nonLocalDecl, "nonlocal id '" + name + "' not found in parent scope..");
+        if(sym == globals)
+            errors.semError(nonLocalDecl, "nonlocal declaration '" + name + "' not allowed in global scope.");
+        return T;
+    }
+
+    // Just a helper..
+    @Override
+    public SymbolType analyze(TypedVar node) {
+        return ValueType.annotationToValueType(node.type);
+    }
+
+    ///////// end
+
     @Override
     public SymbolType analyze(Program program) {
         for (Declaration decl : program.declarations) {
-            decl.dispatch(this);
+            String name = decl.getIdentifier().name;
+
+            SymbolType type = decl.dispatch(this);
+            System.out.println("decl type " + type.toString());
+
+            // recolic: what's the teacher willing to do???
+            if (type == null) {
+                continue;
+            }
+
+            // TODO: DO NOT throw on duplicate id. generate a compiler error.
+            sym.put(name, type);
         }
         for (Stmt stmt : program.statements) {
             stmt.dispatch(this);
@@ -52,12 +158,12 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     }
 
     @Override
-    public SymbolType analyze(IntegerLiteral i) {
-        return i.setInferredType(SymbolType.INT_TYPE);
+    public SymbolType analyze(IntegerLiteral node) {
+        return node.setInferredType(INT_TYPE);
     }
     @Override
     public SymbolType analyze(StringLiteral node) {
-        return node.setInferredType(SymbolType.STR_TYPE);
+        return node.setInferredType(STR_TYPE);
     }
     @Override
     public SymbolType analyze(NoneLiteral node) {
@@ -65,7 +171,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     }
     @Override
     public SymbolType analyze(BooleanLiteral node) {
-        return node.setInferredType(SymbolType.BOOL_TYPE);
+        return node.setInferredType(BOOL_TYPE);
     }
 
     @Override
@@ -117,18 +223,19 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
             case "<":
             case ">=":
             case "<=":
-                if(left_type != ValueType.INT_TYPE || right_type != ValueType.INT_TYPE) {
+                if(!(left_type.equals(INT_TYPE) && right_type.equals(INT_TYPE))) {
+                    System.out.println("debug: left=" + left_type.toString() + ", right=" + right_type.toString());
                     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.equals(BOOL_TYPE) && right_type.equals(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.equals(INT_TYPE) || left_type.equals(STR_TYPE) || left_type.isListType())) {
                     err(node, "Syntax Error: operand of + should be INT or STR or LIST");
                 }
                 // fallthrough: do left-right match check.
@@ -233,10 +340,10 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     public SymbolType analyze(IndexExpr node) {
         SymbolType list_type = node.list.dispatch(this);
         SymbolType index_type = node.index.dispatch(this);
-        if(index_type != INT_TYPE) {
+        if(!index_type.equals(INT_TYPE)) {
             err(node, "index_type should be int.");
         }
-        if(list_type == STR_TYPE) {
+        if(list_type.equals(STR_TYPE)) {
             return node.setInferredType(STR_TYPE);
         }
         else if(list_type.isListType()) {
@@ -256,7 +363,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
             SymbolType this_type = expr.dispatch(this);
             if(elementType == null)
                 elementType = this_type;
-            if(this_type != elementType)
+            if(!this_type.equals(elementType))
                 err(node, "list elements must have the same type.");
         }
         ListValueType resultType = new ListValueType(elementType);
@@ -299,6 +406,7 @@ public class TypeChecker extends AbstractNodeAnalyzer<SymbolType> {
     public SymbolType analyze(Identifier id) {
         String varName = id.name;
         SymbolType varType = sym.get(varName);
+        System.out.println("var " + varName + "->" + varType.toString());
 
         if (varType != null && varType.isValueType()) {
             return id.setInferredType(varType);