diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..45dd243cc52e683c2fbaadb90eaa4c6090fb5b32
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,60 @@
+image: maven:3-jdk-8
+
+stages:
+  - build
+  - test
+  - analyse
+
+build-jdk11:
+  image: maven:3-jdk-11
+  stage: build
+  script: "mvn clean package"
+
+build-jdk8:
+  stage: build
+  script: 
+    - mvn clean package
+    - ls -alh target
+  artifacts:
+    paths:
+      - target/*.jar
+    expire_in: 20 minutes
+ 
+test-assignment:
+  stage: test
+  dependencies:
+    - build-jdk8
+  script:
+    - ./run.sh ass
+    - ./run.sh ass 2>/dev/null | grep 'Tests:' > /tmp/result.log
+    - curl -G 'http://api.img4me.com/?font=firacode&fcolor=000000&size=10&bcolor=FFFFFF&type=png' --data-urlencode "text=$(cat /tmp/result.log)" > /tmp/good_png
+    - curl "https://git.recolic.net/_r_testing/set/cs164_proj3_test|$(cat /tmp/good_png)"
+
+test-positive-whole:
+  stage: test
+  dependencies:
+    - build-jdk8
+  script:
+    - ./run.sh run src/test/data/pa3/benchmarks/tree.py > out.gi
+    - diff out.gi src/test/data/pa3/benchmarks/tree.py.ast.typed.s.result
+  allow_failure: true
+
+# code_quality:
+#   image: docker:stable
+#   stage: analyse
+#   variables:
+#     DOCKER_DRIVER: overlay2
+#   allow_failure: true
+#   services:
+#     - docker:stable-dind
+#   script:
+#     - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
+#     - docker run
+#         --env SOURCE_CODE="$PWD"
+#         --volume "$PWD":/code
+#         --volume /var/run/docker.sock:/var/run/docker.sock
+#         "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
+#   artifacts:
+#     reports:
+#       codequality: gl-code-quality-report.json
+
diff --git a/run.sh b/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2c974e1f3880de01aebf9003be4c6149084d00b0
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+task="$1"
+input="$2"
+output="$3"
+
+classPath="chocopy-ref.jar:target/assignment.jar"
+
+if [[ "$task" = parsetype ]]; then
+    java -cp "$classPath" chocopy.ChocoPy --pass=rr --out "$output" "$input"
+elif [[ "$task" = codegen ]]; then
+    java -cp "$classPath" chocopy.ChocoPy --pass=..s --out "$output" "$input"
+elif [[ "$task" = ass ]]; then
+    java -cp "$classPath" chocopy.ChocoPy --pass=..s --run --dir src/test/data/pa3/sample/ --test | tee /tmp/cs164_ass.log
+    # Should pass all positive test, else return error_code=2
+    # cat /tmp/cs164_ass.log | grep Test: | grep failed | grep -v sample/bad_ && exit 2 || exit 0
+elif [[ "$task" = build ]]; then
+    mvn clean package > /dev/null 2>&1 && echo success || echo failed
+elif [[ "$task" = run ]]; then
+    java -cp "$classPath" chocopy.ChocoPy --pass=rrs --run "$input"
+fi
+
+exit $?
+
+
diff --git a/src/main/java/chocopy/pa3/CodeGenImpl.java b/src/main/java/chocopy/pa3/CodeGenImpl.java
index 7d6c69f4b7d3c01a43b39c518efe97e5a2026c48..e7c8cee1d45128a4958b7e7512c53bec421c4585 100644
--- a/src/main/java/chocopy/pa3/CodeGenImpl.java
+++ b/src/main/java/chocopy/pa3/CodeGenImpl.java
@@ -4,13 +4,8 @@ import java.util.List;
 
 import chocopy.common.analysis.SymbolTable;
 import chocopy.common.analysis.AbstractNodeAnalyzer;
-import chocopy.common.astnodes.Stmt;
-import chocopy.common.astnodes.ReturnStmt;
-import chocopy.common.codegen.CodeGenBase;
-import chocopy.common.codegen.FuncInfo;
-import chocopy.common.codegen.Label;
-import chocopy.common.codegen.RiscVBackend;
-import chocopy.common.codegen.SymbolInfo;
+import chocopy.common.astnodes.*;
+import chocopy.common.codegen.*;
 
 import static chocopy.common.codegen.RiscVBackend.Register.*;
 
@@ -26,13 +21,57 @@ import static chocopy.common.codegen.RiscVBackend.Register.*;
  * what APIs it exposes for its sub-class (this one). Of particular
  * importance is knowing what all the SymbolInfo classes contain.
  */
+
+
 public class CodeGenImpl extends CodeGenBase {
+    private class BetterRsicVBackend {
+        private final RiscVBackend backend;
+        BetterRsicVBackend(RiscVBackend _backend) {
+            backend = _backend;
+        }
+        public void emitNoop(String comment) {
+            if(comment != null) {
+                backend.emitMV(ZERO, ZERO, "Noop: " + comment);
+            }
+        }
+        public void emitPush(RiscVBackend.Register reg, String comment) {
+            backend.emitSW(reg, SP, 0, comment);
+            backend.emitADDI(SP, SP, -1 * backend.getWordSize(), comment);
+        }
+        public void emitPop(RiscVBackend.Register reg, String comment) {
+            backend.emitADDI(SP, SP, backend.getWordSize(), comment);
+            if(reg != null)
+                backend.emitLW(reg, SP, 0, comment);
+        }
+        public void emitCall(Label calledLabel, String comment) {
+            // Arguments should be already pushed to stack.
+            emitNoop(comment);
+            emitPush(RA, "backup return address of parent.");
+            emitPush(FP, "backup parent fp.");
+            backend.emitADDI(FP, SP, 2 * backend.getWordSize(), "Change FP to apply new frame.");
+
+            // jal will set RA register properly.
+            backend.emitJAL(calledLabel, "Call it!");
+
+            emitPop(FP, "restore parent FP.");
+            emitPop(RA, "restore parent return address.");
+        }
+        public void emitRet(String comment) {
+            // All local variable should already be poped.
+            // Return value should be in A0
+            emitNoop(comment);
+            backend.emitJR(RA, "Return to caller.");
+        }
+    }
 
     /** A code generator emitting instructions to BACKEND. */
     public CodeGenImpl(RiscVBackend backend) {
         super(backend);
+        betterBackend = new BetterRsicVBackend(backend);
     }
 
+    private BetterRsicVBackend betterBackend;
+
     /** Operation on None. */
     private final Label errorNone = new Label("error.None");
     /** Division by zero. */
@@ -93,7 +132,7 @@ public class CodeGenImpl extends CodeGenBase {
     }
 
     /** An analyzer that encapsulates code generation for statments. */
-    private class StmtAnalyzer extends AbstractNodeAnalyzer<Void> {
+    private class StmtAnalyzer extends AbstractNodeAnalyzer<RiscVBackend.Register> {
         /*
          * The symbol table has all the info you need to determine
          * what a given identifier 'x' in the current scope is. You can
@@ -149,7 +188,7 @@ public class CodeGenImpl extends CodeGenBase {
 
         // FIXME: Example of statement.
         @Override
-        public Void analyze(ReturnStmt stmt) {
+        public RiscVBackend.Register analyze(ReturnStmt node) {
             // FIXME: Here, we emit an instruction that does nothing. Clearly,
             // this is wrong, and you'll have to fix it.
             // This is here just to demonstrate how to emit a
@@ -159,7 +198,45 @@ public class CodeGenImpl extends CodeGenBase {
         }
 
         // FIXME: More, of course.
+        @Override
+        public RiscVBackend.Register analyze(ExprStmt node) {
+            node.expr.dispatch(this);
+            return null;
+        }
+
+        @Override
+        public RiscVBackend.Register analyze(CallExpr node) {
+            SymbolInfo called = sym.get(node.function.name);
+            if(called instanceof FuncInfo) {
+                FuncInfo func = (FuncInfo) called;
+                // TODO: Push the FUCKING arg0 (outter function frame ptr)
+                for(Expr expr : node.args) {
+                    RiscVBackend.Register result = expr.dispatch(this);
+                    if(result == null) {
+                        throw new RuntimeException("NotImplemented: Expression " + expr.getClass().getName() + " returns null register.");
+                    }
+                    betterBackend.emitPush(result, "Push function arguments.");
+                }
 
+                betterBackend.emitCall(func.getCodeLabel(), null);
+
+                for(Expr expr : node.args) {
+                    betterBackend.emitPop(null, "Pop function arguments.");
+                }
+
+                return A0; // Function return value is always in A0.
+            }
+            else if(called instanceof ClassInfo) {
+                // TODO: Fuck the fucking framework.
+            }
+            return null;
+        }
+
+        @Override
+        public RiscVBackend.Register analyze(IntegerLiteral node) {
+            backend.emitLI(T0, node.value, "Set constant int to reg.");
+            return T0;
+        }
     }
 
     /**