diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..861fe91
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,19 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+
+
+ {
+ "type": "java",
+ "name": "Launch Current File",
+ "request": "launch",
+ "classPaths": ["chocopy-ref.jar:target/assignment.jar"],
+ "mainClass": "chocopy.ChocoPy",
+ "args": [ "--pass=rrs", "--test","--dir", "src/test/data/pa3/sample/list_set_element_oob_1.py"],
+ "sourcePaths": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..c5f3f6b
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "java.configuration.updateBuildConfiguration": "interactive"
+}
\ No newline at end of file
diff --git a/src/main/java/chocopy/pa3/CodeGenImpl.java b/src/main/java/chocopy/pa3/CodeGenImpl.java
index 0006f80..2879bed 100644
--- a/src/main/java/chocopy/pa3/CodeGenImpl.java
+++ b/src/main/java/chocopy/pa3/CodeGenImpl.java
@@ -1,5 +1,16 @@
package chocopy.pa3;
+import static chocopy.common.codegen.RiscVBackend.Register.A0;
+import static chocopy.common.codegen.RiscVBackend.Register.A1;
+import static chocopy.common.codegen.RiscVBackend.Register.FP;
+import static chocopy.common.codegen.RiscVBackend.Register.RA;
+import static chocopy.common.codegen.RiscVBackend.Register.SP;
+import static chocopy.common.codegen.RiscVBackend.Register.ZERO;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import chocopy.common.analysis.AbstractNodeAnalyzer;
import chocopy.common.analysis.SymbolTable;
import chocopy.common.astnodes.AssignStmt;
@@ -34,29 +45,40 @@ import chocopy.common.astnodes.TypedVar;
import chocopy.common.astnodes.UnaryExpr;
import chocopy.common.astnodes.VarDef;
import chocopy.common.astnodes.WhileStmt;
+import chocopy.common.astnodes.*;
+import chocopy.common.analysis.types.*;
import chocopy.common.codegen.*;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+
import com.fasterxml.jackson.core.JsonProcessingException;
-
import static chocopy.common.codegen.RiscVBackend.Register.*;
+import chocopy.common.codegen.RiscVBackend.Register;
+
/**
* This is where the main implementation of PA3 will live.
*
- *
A large part of the functionality has already been implemented in the base class, CodeGenBase.
- * Make sure to read through that class, since you will want to use many of its fields and utility
- * methods in this class when emitting code.
+ *
+ * A large part of the functionality has already been implemented in the base
+ * class, CodeGenBase. Make sure to read through that class, since you will want
+ * to use many of its fields and utility methods in this class when emitting
+ * code.
*
- *
Also read the PDF spec for details on what the base class does and what APIs it exposes for
- * its sub-class (this one). Of particular importance is knowing what all the SymbolInfo classes
- * contain.
+ *
+ * Also read the PDF spec for details on what the base class does and 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 {
+public class CodeGenImpl extends CodeGenBase
+{
/** A code generator emitting instructions to BACKEND. */
- public CodeGenImpl(RiscVBackend backend) {
+ public CodeGenImpl(RiscVBackend backend)
+ {
super(backend);
}
@@ -66,26 +88,30 @@ public class CodeGenImpl extends CodeGenBase {
private final Label errorDiv = new Label("error.Div");
/** Index out of bounds. */
private final Label errorOob = new Label("error.OOB");
-
+
/**
* Emits the top level of the program.
*
- *
This method is invoked exactly once, and is surrounded by some boilerplate code that: (1)
- * initializes the heap before the top-level begins and (2) exits after the top-level ends.
+ *
+ * This method is invoked exactly once, and is surrounded by some boilerplate
+ * code that: (1) initializes the heap before the top-level begins and (2) exits
+ * after the top-level ends.
*
- *
You only need to generate code for statements.
+ *
+ * You only need to generate code for statements.
*
* @param statements top level statements
*/
- protected void emitTopLevel(List statements) {
+ protected void emitTopLevel(List statements)
+ {
StmtAnalyzer stmtAnalyzer = new StmtAnalyzer(null);
- backend.emitADDI(
- SP, SP, -2 * backend.getWordSize(), "Saved FP and saved RA (unused at top level).");
+ backend.emitADDI(SP, SP, -2 * backend.getWordSize(), "Saved FP and saved RA (unused at top level).");
backend.emitSW(ZERO, SP, 0, "Top saved FP is 0.");
backend.emitSW(ZERO, SP, 4, "Top saved RA is 0.");
backend.emitADDI(FP, SP, 2 * backend.getWordSize(), "Set FP to previous SP.");
- for (Stmt stmt : statements) {
+ for (Stmt stmt : statements)
+ {
stmt.dispatch(stmtAnalyzer);
}
backend.emitLI(A0, EXIT_ECALL, "Code for ecall: exit");
@@ -95,12 +121,14 @@ public class CodeGenImpl extends CodeGenBase {
/**
* Emits the code for a function described by FUNCINFO.
*
- * This method is invoked once per function and method definition. At the code generation
- * stage, nested functions are emitted as separate functions of their own. So if function `bar`
- * is nested within function `foo`, you only emit `foo`'s code for `foo` and only emit `bar`'s
- * code for `bar`.
+ *
+ * This method is invoked once per function and method definition. At the code
+ * generation stage, nested functions are emitted as separate functions of their
+ * own. So if function `bar` is nested within function `foo`, you only emit
+ * `foo`'s code for `foo` and only emit `bar`'s code for `bar`.
*/
- protected void emitUserDefinedFunction(FuncInfo funcInfo) {
+ protected void emitUserDefinedFunction(FuncInfo funcInfo)
+ {
backend.emitGlobalLabel(funcInfo.getCodeLabel());
@@ -143,36 +171,32 @@ public class CodeGenImpl extends CodeGenBase {
}
/** An analyzer that encapsulates code generation for statements. */
- private class StmtAnalyzer extends AbstractNodeAnalyzer {
+ private class StmtAnalyzer extends AbstractNodeAnalyzer {
/*
- * The symbol table has all the info you need to determine
- * what a given identifier 'x' in the current scope is. You can
- * use it as follows:
- * SymbolInfo x = sym.get("x");
+ * The symbol table has all the info you need to determine what a given
+ * identifier 'x' in the current scope is. You can use it as follows: SymbolInfo
+ * x = sym.get("x");
*
- * A SymbolInfo can be one the following:
- * - ClassInfo: a descriptor for classes
- * - FuncInfo: a descriptor for functions/methods
- * - AttrInfo: a descriptor for attributes
- * - GlobalVarInfo: a descriptor for global variables
- * - StackVarInfo: a descriptor for variables allocated on the stack,
- * such as locals and parameters
+ * A SymbolInfo can be one the following: - ClassInfo: a descriptor for classes
+ * - FuncInfo: a descriptor for functions/methods - AttrInfo: a descriptor for
+ * attributes - GlobalVarInfo: a descriptor for global variables - StackVarInfo:
+ * a descriptor for variables allocated on the stack, such as locals and
+ * parameters
*
- * Since the input program is assumed to be semantically
- * valid and well-typed at this stage, you can always assume that
- * the symbol table contains valid information. For example, in
- * an expression `foo()` you KNOW that sym.get("foo") will either be
- * a FuncInfo or ClassInfo, but not any of the other infos
- * and never null.
+ * Since the input program is assumed to be semantically valid and well-typed at
+ * this stage, you can always assume that the symbol table contains valid
+ * information. For example, in an expression `foo()` you KNOW that
+ * sym.get("foo") will either be a FuncInfo or ClassInfo, but not any of the
+ * other infos and never null.
*
- * The symbol table in funcInfo has already been populated in
- * the base class: CodeGenBase. You do not need to add anything to
- * the symbol table. Simply query it with an identifier name to
- * get a descriptor for a function, class, variable, etc.
+ * The symbol table in funcInfo has already been populated in the base class:
+ * CodeGenBase. You do not need to add anything to the symbol table. Simply
+ * query it with an identifier name to get a descriptor for a function, class,
+ * variable, etc.
*
- * The symbol table also maps nonlocal and global vars, so you
- * only need to lookup one symbol table and it will fetch the
- * appropriate info for the var that is currently in scope.
+ * The symbol table also maps nonlocal and global vars, so you only need to
+ * lookup one symbol table and it will fetch the appropriate info for the var
+ * that is currently in scope.
*/
/** Symbol table for my statements. */
@@ -184,298 +208,452 @@ public class CodeGenImpl extends CodeGenBase {
/** The descriptor for the current function, or null at the top level. */
private final FuncInfo funcInfo;
- /** An analyzer for the function described by FUNCINFO0, which is null for the top level. */
+ /** Label of code that exits from block. */
+ protected Label elseBlock;
+
+ /** Variable to keep track of offsets of stored variables */
+ private Map offsetMap = new HashMap<>();
+ private final String size_label;
+ /** Variable to store offset from frame pointer to identify next
+ * empty space on stack frame to store variable*/
+ private int sp_off;
+ /** Variable to store maximum possible offset depending on stack size.*/
+ private int max_sp;
+
+ /**
+ * An analyzer for the function described by FUNCINFO0, which is null for the
+ * top level.
+ */
StmtAnalyzer(FuncInfo funcInfo0) {
funcInfo = funcInfo0;
if (funcInfo == null) {
sym = globalSymbols;
+ sp_off = max_sp = 2;
+ size_label = "@..main.size";
} else {
sym = funcInfo.getSymbolTable();
+ sp_off = max_sp = funcInfo0.getLocals().size() + 2;
+ size_label = "@"+funcInfo0.getFuncName()+".size";
}
epilogue = generateLocalLabel();
}
+ private void incSp(int i){
+ sp_off+=i+1;
+ max_sp = max_sp >= sp_off?max_sp:sp_off;
+ }
+
+
+
+
+ // *********** functions start ***********
+
+ public Register analyze(CallExpr node) {
+ SymbolInfo Ty = globalSymbols.get(node.function.name);
+ if(Ty instanceof ClassInfo){
+ //object create
+ ClassInfo cls = (ClassInfo) Ty;
+ /**
+ la a0, $DoublingVector$prototype # Load pointer to prototype of: DoublingVector
+ jal alloc # Allocate new object in A0
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: DoublingVector.__init__
+ jalr a1 # Invoke method: DoublingVector.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Pop stack slot 3
+ */
+ backend.emitLA(A0, cls.getPrototypeLabel(),
+ String.format("Load pointer to prototype of: %s", cls.getClassName()));
+ backend.emitJAL(objectAllocLabel, "Allocate new object in A0");
+ backend.emitSW(A0, FP, -sp_off*wordSize, String.format("Push on stack slot %d", sp_off));
+ incSp(0);
+ backend.emitSW(A0, FP, -sp_off*wordSize, "Push argument 0 from last.");
+ backend.emitADDI(SP, FP, sp_off, "Set SP to last argument.");
+ backend.emitLW(A1, A0, getDispatchTableOffset(), "Load address of object's dispatch table");
+ backend.emitLW(A1, A1, getMethodOffset(cls, "__init__"), String.format("Load address of method: %s.__init__", cls.getClassName()));
+ backend.emitJALR(A1, String.format("Invoke method: %s.__init", cls.getClassName()));
+ backend.emitADDI(SP, FP, "-"+size_label, "Set SP to stack frame top.");
+ -- sp_off;
+ backend.emitLW(A0, FP, -sp_off*wordSize, String.format("Pop stack slot %d", sp_off));
+ } else {
+ System.out.println("*** CallExpr");
+ backend.emitLW(T6, FP, 0, "Inside CallExpr: " + node.function.name);
+
+ // function
+ Identifier functionId = node.function;
+
+ List args = node.args;
+ int spaceRequiredForArgs = (args.size() + 1)*4;
+ //backend.emitSW(A0, SP, -4, "Put static link");
+ for (int i = 0; i < args.size(); i++) {
+ int argNum = i + 1;
+ int slotNum = argNum + 1; // We have extra slot for static link
+ Expr expr = args.get(i);
+ expr.dispatch(this);
+ // All expressions should save their end result in A0
+ // So, once expr is evaluated add value inside A0 onto stack as an argument
+ backend.emitSW(A0, SP, -4*slotNum, "Push argument " + argNum + " from left");
+ }
+
+ backend.emitADDI(SP, SP, -spaceRequiredForArgs, "Set SP to last argument.");
+ backend.emitJAL(new Label("$"+functionId.name), "Invoke function: " + functionId.name);
+ backend.emitADDI(SP, SP, spaceRequiredForArgs, "Set SP to stack frame top.");
+ }
+ return A0;
+ }
+
+
+//
+//
+// @Override
+// public Void analyze(FuncDef node) {
+// System.out.println("*** FuncDef");
+// backend.emitLW(T6, FP, 0, "Inside FuncDef");
+// // function
+// return null;
+// }
+//
+//
+//
+// @Override
+// public Void analyze(GlobalDecl node) {
+// System.out.println("*** GlobalDecl");
+// backend.emitLW(T6, FP, 0, "Inside GlobalDecl");
+// // function
+// return defaultAction(node);
+// }
+//
+//
+//
+// @Override
+// public Void analyze(NonLocalDecl node) {
+// System.out.println("*** NonLocalDecl");
+// backend.emitLW(T6, FP, 0, "Inside NonLocalDecl");
+// // function
+// return defaultAction(node);
+// }
+
+
+
+ public Register analyze(MethodCallExpr node)
+ {
+ Register obj = node.method.object.dispatch(this);
+ int n_args = node.args.size();
+
+ Label label = generateLocalLabel();
+ backend.emitBNEZ(obj, label, "Ensure not None");
+ backend.emitJ(errorNone, "Go to error handler");
+ backend.emitLocalLabel(label, "Not None");
+ incSp(n_args+1);
+ backend.emitSW(obj, FP, (n_args - sp_off) *wordSize, String.format("Push argument %d from last.", n_args));
+
+ for (int i = 0; i < n_args; ++i)
+ backend.emitSW(node.args.get(i).dispatch(this), FP, (n_args - i - 1 - sp_off) * wordSize,
+ String.format("Push argument %d from last.", n_args - i - 1));
+
+ backend.emitLW(A0, FP, (n_args- sp_off) * wordSize, String.format("Peek stack slot %d", sp_off - (n_args + 1)));
+ ClassInfo objectClass = (ClassInfo)sym.get(((Identifier)node.method.object).name);
+
+ backend.emitLW(A1, A0, getDispatchTableOffset(), "Load address of object's dispatch table");
+ backend.emitLW(A1, A1, getMethodOffset(objectClass, node.method.member.name),
+ String.format("Load address of method: %s.%s", objectClass.getClassName(), node.method.member.name));
+ backend.emitADDI(SP, FP, -sp_off * wordSize, "Set SP to last argument.");
+ backend.emitJALR(A1, String.format("Invoke method: %s.%s", objectClass.getClassName(), node.method.member.name));
+ backend.emitInsn(String.format("addi sp, fp, -%s", size_label), "Set SP to stack frame top.");
+ sp_off -= n_args+1;
+
+ return A0;
+ }
@Override
- public Void analyze(ReturnStmt stmt) {
+ public Register analyze(ReturnStmt stmt) {
System.out.println("*** ReturnStmt");
backend.emitLW(T6, FP, 0, "Inside ReturnStmt");
// Expr expr = stmt.value;
// // All expressions should save their end result in A0
// expr.dispatch(this);
backend.emitLW(A0, FP, 0, "Load var: " + "last");
- return null;
+ return A0;
}
+
+
+ // *********** functions end ***********
+
+ @Override
+ public Register analyze(NoneLiteral node)
+ {
+ backend.emitMV(Register.A0, Register.ZERO, "Load none");
+ return Register.A0;
+ }
@Override
- public Void analyze(CallExpr node) {
- System.out.println("*** CallExpr");
- backend.emitLW(T6, FP, 0, "Inside CallExpr: " + node.function.name);
-
- // function
- Identifier functionId = node.function;
-
- List args = node.args;
- int spaceRequiredForArgs = (args.size() + 1)*4;
- //backend.emitSW(A0, SP, -4, "Put static link");
- for (int i = 0; i < args.size(); i++) {
- int argNum = i + 1;
- int slotNum = argNum + 1; // We have extra slot for static link
- Expr expr = args.get(i);
- expr.dispatch(this);
- // All expressions should save their end result in A0
- // So, once expr is evaluated add value inside A0 onto stack as an argument
- backend.emitSW(A0, SP, -4*slotNum, "Push argument " + argNum + " from left");
- }
-
- backend.emitADDI(SP, SP, -spaceRequiredForArgs, "Set SP to last argument.");
- backend.emitJAL(new Label("$"+functionId.name), "Invoke function: " + functionId.name);
- backend.emitADDI(SP, SP, spaceRequiredForArgs, "Set SP to stack frame top.");
+ public Register analyze(StringLiteral node)
+ {
+ Label l = constants.getStrConstant(node.value);
+ backend.emitLA(Register.A0, l, "Load string literal");
+ return Register.A0;
+ }
+
+ @Override
+ public Register analyze(IntegerLiteral node)
+ {
+ backend.emitLI(Register.A0, node.value, "Load integer literal "+node.value);
+ return Register.A0;
+ }
+
+ @Override
+ public Register analyze(BooleanLiteral node)
+ {
+ if(node.value==true)
+ backend.emitLI(Register.A0, 1, "Load boolean literal: true ");
+ else
+ backend.emitLI(Register.A0, 0, "Load boolean literal: false ");
+ return Register.A0;
+ }
+
+ @Override
+ public Register analyze(AssignStmt node)
+ {
+ Type t = node.value.getInferredType();
+ if(t.isSpecialType() || t.isListType())
+ {
+ node.value.dispatch(this);
+ if (sym.getParent() == null)
+ {
+ for(Expr target: node.targets)
+ {
+ GlobalVarInfo gvi=(GlobalVarInfo)sym.get(((Identifier)target).name);
+ backend.emitSW(Register.A0, gvi.getLabel(), Register.T0, "Assign global: "+gvi.getVarName()+"(using tmp register)");
+ }
+ }
+ else
+ {
+ for(Expr target: node.targets)
+ {
+ StackVarInfo svi = (StackVarInfo) sym.get(((Identifier)target).name);
+ int loc = offsetMap.get(svi);
+ backend.emitSW(Register.A0, Register.FP, -loc*4, "Load local variable: "+svi.getVarName());
+ }
+ }
+ }
+ else
+ {//TODO: Object Assignment
+
+ }
+ return Register.A0;
+ }
+
+ @Override
+ public Register analyze(ExprStmt node)
+ {
+ node.expr.dispatch(this);
return null;
}
-
-
@Override
- public Void analyze(MethodCallExpr node) {
- System.out.println("*** MethodCallExpr");
- backend.emitLW(T6, FP, 0, "Inside MethodCallExpr");
- // function
- return defaultAction(node);
+ public Register analyze(IfExpr node)
+ {
+ node.condition.dispatch(this);
+ Label ln = generateLocalLabel();
+ node.thenExpr.dispatch(this);
+ backend.emitJ(ln, "Jump to end of if expression");
+ backend.emitLocalLabel(elseBlock, "Else part of if expression");
+ node.elseExpr.dispatch(this);
+ backend.emitLocalLabel(ln, "End of if expression");
+ return null;
}
-
-
@Override
- public Void analyze(FuncDef node) {
- System.out.println("*** FuncDef");
- backend.emitLW(T6, FP, 0, "Inside FuncDef");
- // function
- return defaultAction(node);
+ public Register analyze(IfStmt node)
+ {
+ node.condition.dispatch(this);
+ Label ln = generateLocalLabel();
+ for(Stmt s:node.thenBody)
+ s.dispatch(this);
+ backend.emitJ(ln, "Jump to end of if statement");
+ backend.emitLocalLabel(elseBlock, "Else part of if statement");
+ for(Stmt s:node.elseBody)
+ s.dispatch(this);
+ backend.emitLocalLabel(ln, "End of if statement");
+ return null;
}
-
-
@Override
- public Void analyze(GlobalDecl node) {
- System.out.println("*** GlobalDecl");
- backend.emitLW(T6, FP, 0, "Inside GlobalDecl");
- // function
- return defaultAction(node);
+ public Register analyze(BinaryExpr node)
+ {
+ node.left.dispatch(this);
+ backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Push on stack slot "+sp_off);
+ sp_off++;
+ node.right.dispatch(this);
+ sp_off--;
+ backend.emitLW(Register.T0, Register.FP, -sp_off*wordSize, "Pop stack slot "+sp_off);
+ // Arithmetic Operators
+ if(node.operator.equals("+"))
+ backend.emitADD(Register.A0, Register.A0, Register.T0, "Add operation");
+ else if(node.operator.equals("-"))
+ backend.emitSUB(Register.A0, Register.A0, Register.T0, "Sub operation");
+ else if(node.operator.equals("*"))
+ backend.emitMUL(Register.A0, Register.A0, Register.T0, "Mul operation");
+ else if(node.operator.equals("/"))
+ backend.emitDIV(Register.A0, Register.A0, Register.T0, "Div operation");
+ else
+ { // Comparison operators
+ elseBlock = generateLocalLabel();
+ String comment="Branch on not "+node.operator;
+ if(node.operator.equals("=="))
+ backend.emitBNE(Register.A0, Register.T0,elseBlock, comment);
+ else if(node.operator.equals("!="))
+ backend.emitBEQ(Register.A0, Register.T0,elseBlock, comment);
+ else if(node.operator.equals("<"))
+ backend.emitBGE(Register.A0, Register.T0,elseBlock, comment);
+ else if(node.operator.equals(">"))
+ {
+ backend.emitBLT(Register.A0, Register.T0,elseBlock, comment);
+ backend.emitBEQ(Register.A0, Register.T0,elseBlock, comment);
+ }
+ else if(node.operator.equals(">="))
+ backend.emitBLT(Register.A0, Register.T0,elseBlock, comment);
+ else if(node.operator.equals("<="))
+ {
+ Label temp = generateLocalLabel();
+ backend.emitBEQ(Register.A0, Register.T0,temp, "Branch on "+node.operator);
+ backend.emitBGE(Register.A0, Register.T0,elseBlock, comment);
+ backend.emitLocalLabel(temp, "True part of if check");
+ }
+ }
+ return null;
}
-
-
@Override
- public Void analyze(NonLocalDecl node) {
- System.out.println("*** NonLocalDecl");
- backend.emitLW(T6, FP, 0, "Inside NonLocalDecl");
- // function
- return defaultAction(node);
+ public Register analyze(UnaryExpr node)
+ {
+ node.operand.dispatch(this);
+ if(node.operator.equals("-"))
+ {
+ backend.emitLI(Register.T0, -1, "Set value of Register T0 to -1");
+ backend.emitMUL(Register.A0, Register.A0, Register.T0, "Multiply by -1");
+ }
+ return Register.A0;
}
+ @Override
+ public Register analyze(Identifier node)
+ {
+ if (sym.getParent() == null)
+ {
+ GlobalVarInfo gvi=(GlobalVarInfo) sym.get(node.name);
+ backend.emitLW(Register.A0, gvi.getLabel(), "Load global: "+gvi.getVarName());
+ }
+ else
+ {
+ StackVarInfo svi = (StackVarInfo) sym.get(node.name);
+ int loc = offsetMap.get(svi);
+ backend.emitLW(Register.A0, Register.FP, -loc*4, "Load local variable: "+svi.getVarName());
+ }
+ return null;
+ }
-
-
-
-
-
-
-
- // methods below are only for testing, remove or comment them when merging
@Override
- public Void analyze(AssignStmt node) {
- System.out.println("+++ Inside AssignStmt");
- backend.emitLW(T6, FP, 0, "Inside AssignStmt");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(BinaryExpr node) {
- System.out.println("+++ Inside BinaryExpr");
- backend.emitLW(T6, FP, 0, "Inside BinaryExpr");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(BooleanLiteral node) {
- System.out.println("+++ Inside BooleanLiteral");
- backend.emitLW(T6, FP, 0, "Inside BooleanLiteral");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(ClassDef node) {
- System.out.println("+++ Inside ClassDef");
- backend.emitLW(T6, FP, 0, "Inside ClassDef");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(ClassType node) {
- System.out.println("+++ Inside ClassType");
- backend.emitLW(T6, FP, 0, "Inside ClassType");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(CompilerError node) {
- System.out.println("+++ Inside CompilerError");
- backend.emitLW(T6, FP, 0, "Inside CompilerError");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(Errors node) {
- System.out.println("+++ Inside Errors");
- backend.emitLW(T6, FP, 0, "Inside Errors");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(ExprStmt node) {
- System.out.println("+++ Inside ExprStmt");
- backend.emitLW(T6, FP, 0, "Inside ExprStmt: " + node.expr.kind);
- node.expr.dispatch(this);
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(ForStmt node) {
- System.out.println("+++ Inside ForStmt");
- backend.emitLW(T6, FP, 0, "Inside ForStmt");
- return defaultAction(node);
- }
-
-
-
- @Override
- public Void analyze(Identifier node) {
- System.out.println("+++ Inside Identifier");
-// List params = funcInfo.getParams();
-// int i = 0;
-// for (i = 0; i < params.size(); i++) {
-// if (params.get(i).equals(node.name)) break;
-// }
-// backend.emitLW(A0, SP, ((i+1)-params.size())*4, "Load param " + (i+1) + " from left");
- backend.emitLW(T6, FP, 0, "Inside Identifier: " + node.name);
+ public Register analyze(VarDef node)
+ {
+ StackVarInfo svi = (StackVarInfo) sym.get(node.var.identifier.name);
+ node.value.dispatch(this);
+ backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Store variable "+node.var.identifier.name+" value in Stack");
+ offsetMap.put(svi, sp_off);
+ sp_off++;
return null;
}
@Override
- public Void analyze(IfExpr node) {
- System.out.println("+++ Inside IfExpr");
- backend.emitLW(T6, FP, 0, "Inside IfExpr");
- return defaultAction(node);
- }
+ public Register analyze(WhileStmt node)
+ {
+ Label startLoop = generateLocalLabel();
+ backend.emitLocalLabel(startLoop, "Beginning of while loop");
+ node.condition.dispatch(this);
+ Label endLoop = elseBlock;
+ for(Stmt stmt:node.body)
+ stmt.dispatch(this);
+ backend.emitJ(startLoop, "Jump to beginning of loop");
+ backend.emitLocalLabel(endLoop, "End of while loop");
- @Override
- public Void analyze(IfStmt node) {
- System.out.println("+++ Inside IfStmt");
- backend.emitLW(T6, FP, 0, "Inside IfStmt");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(IndexExpr node) {
- System.out.println("+++ Inside IndexExpr");
- backend.emitLW(T6, FP, 0, "Inside IndexExpr");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(IntegerLiteral node) {
- System.out.println("+++ Inside IntegerLiteral");
- backend.emitLA(A0, new Label("$int$prototype"), "Load prototype");
- backend.emitJAL(new Label("ra, alloc"), "");
- backend.emitLI(T0, node.value, "Load integer " + node.value);
- backend.emitSW(T0, A0, "@.__int__", null);
- backend.emitLW(T6, FP, 0, "Inside IntegerLiteral");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(ListExpr node) {
- System.out.println("+++ Inside ListExpr");
- backend.emitLW(T6, FP, 0, "Inside ListExpr");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(ListType node) {
- System.out.println("+++ Inside ListType");
- backend.emitLW(T6, FP, 0, "Inside ListType");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(MemberExpr node) {
- System.out.println("+++ Inside MemberExpr");
- backend.emitLW(T6, FP, 0, "Inside MemberExpr");
- return defaultAction(node);
- }
-
-
-
- @Override
- public Void analyze(NoneLiteral node) {
- System.out.println("+++ Inside NoneLiteral");
- backend.emitLW(T6, FP, 0, "Inside NoneLiteral");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(Program node) {
- System.out.println("+++ Inside Program");
- backend.emitLW(T6, FP, 0, "Inside Program");
- return defaultAction(node);
- }
-
-
- @Override
- public Void analyze(StringLiteral node) {
- System.out.println("+++ Inside StringLiteral");
- backend.emitLW(T6, FP, 0, "Inside StringLiteral");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(TypedVar node) {
- System.out.println("+++ Inside TypedVar");
- backend.emitLW(T6, FP, 0, "Inside TypedVar");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(UnaryExpr node) {
- System.out.println("+++ Inside UnaryExpr");
- backend.emitLW(T6, FP, 0, "Inside UnaryExpr");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(VarDef node) {
- System.out.println("+++ Inside VarDef");
- backend.emitLW(T6, FP, 0, "Inside VarDef");
- return defaultAction(node);
- }
-
- @Override
- public Void analyze(WhileStmt node) {
- System.out.println("+++ Inside WhileStmt");
- backend.emitLW(T6, FP, 0, "Inside WhileStmt");
- return defaultAction(node);
+ return null;
}
+ @Override
+ public Register analyze(ListExpr node) {
+ int l = node.elements.size();
+ int i = l;
+ for(Expr exp:node.elements)
+ {
+ Register r = exp.dispatch(this);
+ backend.emitSW(r,Register.FP,-sp_off*wordSize,"Push argument "+i+" from last.");
+ sp_off++;
+ i--;
+ }
+ backend.emitLI(Register.A0, l, "Pass list length");
+ backend.emitSW(Register.A0, Register.FP, -sp_off*wordSize, "Push argument "+i+" from last.");
+ sp_off++;
+ backend.emitADDI(Register.SP, Register.SP, -sp_off*wordSize, "Set SP to last argument.");
+ //TODO: Store reference to variable
+ return Register.A0;
+ }
+
+
+
+// @Override
+// public Void analyze(IntegerLiteral node) {
+// System.out.println("+++ Inside IntegerLiteral");
+// backend.emitLA(A0, new Label("$int$prototype"), "Load prototype");
+// backend.emitJAL(new Label("ra, alloc"), "");
+// backend.emitLI(T0, node.value, "Load integer " + node.value);
+// backend.emitSW(T0, A0, "@.__int__", null);
+// backend.emitLW(T6, FP, 0, "Inside IntegerLiteral");
+// return defaultAction(node);
+// }
+
-
-
-
-
- // extras end here
-
+ @Override
+ public Register analyze(ForStmt node) {
+ System.out.println(node);
+ /*
+ node.
+ Label startLoop = generateLocalLabel();
+ backend.emitLocalLabel(startLoop, "Beginning of while loop");
+ node.condition.dispatch(this);
+ Label endLoop = elseBlock;
+ for(Stmt stmt:node.body)
+ stmt.dispatch(this);
+ backend.emitJ(startLoop, "Jump to beginning of loop");
+ backend.emitLocalLabel(endLoop, "End of while loop");*/
+ return null;
+
+ }
+
+ @Override
+ public Register analyze(IndexExpr node)
+ {
+ System.out.println(node);
+ return defaultAction(node);
+ }
+
+ public Register analyze(MemberExpr node)
+ {
+ ClassInfo objectClass = (ClassInfo) globalSymbols.get(node.object.getInferredType().className());
+ Label label = generateLocalLabel();
+ Register obj = node.object.dispatch(this);
+
+ backend.emitBNEZ(obj, label, "Ensure not None");
+ backend.emitJ(errorNone, "Go to error handler");
+ backend.emitLocalLabel(label, "Not None");
+ backend.emitLW(A0, obj, getAttrOffset(objectClass, node.member.name),
+ String.format("Get attribute: %s.%s", objectClass.getClassName(), node.member.name));
+ return A0;
+ }
}
/**
diff --git a/src/test/data/pa3/benchmarks/exp.py.ast.typed.s b/src/test/data/pa3/benchmarks/exp.py.ast.typed.s
new file mode 100644
index 0000000..98d8973
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/exp.py.ast.typed.s
@@ -0,0 +1,795 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $n
+$n:
+ .word 42 # Initial value of global var: n
+
+.globl $i
+$i:
+ .word 0 # Initial value of global var: i
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ j label_2 # Jump to loop test
+label_1: # Top of while loop
+ li a0, 2 # Load integer literal 2
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $i # Load global: i
+ sw a0, -36(fp) # Push on stack slot 9
+ li a0, 31 # Load integer literal 31
+ lw t0, -36(fp) # Pop stack slot 9
+ bnez a0, label_3 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_3: # Divisor is non-zero
+ rem t2, t0, a0 # Operator rem
+ beqz t2, label_4 # If no remainder, no adjustment
+ xor t3, t2, a0 # Check for differing signs.
+ bgez t3, label_4 # Don't adjust if signs equal.
+ add a0, t2, a0 # Adjust
+ j label_5
+label_4: # Store result
+ mv a0, t2
+label_5: # End of %
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $exp # Invoke function: exp
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, $i, t0 # Assign global: i (using tmp register)
+label_2: # Test loop condition
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $n # Load global: n
+ lw t0, -12(fp) # Pop stack slot 3
+ bge a0, t0, label_1 # Branch on <=
+ .equiv @..main.size, 48
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $exp.f.geta
+$exp.f.geta:
+ addi sp, sp, -@exp.f.geta.size # Reserve space for stack frame.
+ sw ra, @exp.f.geta.size-4(sp) # return address
+ sw fp, @exp.f.geta.size-8(sp) # control link
+ addi fp, sp, @exp.f.geta.size # New fp is at old SP.
+ lw t0, 0(fp) # Load static link from exp.f.geta to exp.f
+ lw t0, 4(t0) # Load static link from exp.f to exp
+ lw a0, -12(t0) # Load var: exp.a
+ j label_7 # Go to return
+ mv a0, zero # Load None
+ j label_7 # Jump to function epilogue
+label_7: # Epilogue
+ .equiv @exp.f.geta.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @exp.f.geta.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $exp.f
+$exp.f:
+ addi sp, sp, -@exp.f.size # Reserve space for stack frame.
+ sw ra, @exp.f.size-4(sp) # return address
+ sw fp, @exp.f.size-8(sp) # control link
+ addi fp, sp, @exp.f.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: exp.f.i
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 0 # Load integer literal 0
+ lw t0, -12(fp) # Pop stack slot 3
+ blt a0, t0, label_11 # Branch on not <=
+ mv t0, fp # Get static link to exp.f
+ sw t0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $exp.f.geta # Invoke function: exp.f.geta
+ addi sp, fp, -@exp.f.size # Set SP to stack frame top.
+ j label_9 # Go to return
+ j label_10 # Then body complete; jump to end-if
+label_11: # Else body
+ lw t0, 4(fp) # Load static link from exp.f to exp
+ lw a0, -12(t0) # Load var: exp.a
+ sw a0, -12(fp) # Push on stack slot 3
+ lw t0, 4(fp) # Load static link from exp.f to exp
+ lw a0, 4(t0) # Load var: exp.x
+ lw t0, -12(fp) # Pop stack slot 3
+ mul a0, t0, a0 # Operator *
+ lw t0, 4(fp) # Load static link from exp.f to exp
+ sw a0, -12(t0) # Assign var: exp.a
+ mv t0, fp # Get static link to exp.f
+ lw t0, 4(t0) # Get static link to exp
+ sw t0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: exp.f.i
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load integer literal 1
+ lw t0, -20(fp) # Pop stack slot 5
+ sub a0, t0, a0 # Operator -
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $exp.f # Invoke function: exp.f
+ addi sp, fp, -@exp.f.size # Set SP to stack frame top.
+ j label_9 # Go to return
+label_10: # End of if-else statement
+ mv a0, zero # Load None
+ j label_9 # Jump to function epilogue
+label_9: # Epilogue
+ .equiv @exp.f.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @exp.f.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $exp
+$exp:
+ addi sp, sp, -@exp.size # Reserve space for stack frame.
+ sw ra, @exp.size-4(sp) # return address
+ sw fp, @exp.size-8(sp) # control link
+ addi fp, sp, @exp.size # New fp is at old SP.
+ li a0, 0 # Load integer literal 0
+ sw a0, -12(fp) # local variable a
+ li a0, 1 # Load integer literal 1
+ sw a0, -12(fp) # Assign var: exp.a
+ mv t0, fp # Get static link to exp
+ sw t0, -28(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: exp.y
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $exp.f # Invoke function: exp.f
+ addi sp, fp, -@exp.size # Set SP to stack frame top.
+ j label_13 # Go to return
+ mv a0, zero # Load None
+ j label_13 # Jump to function epilogue
+label_13: # Epilogue
+ .equiv @exp.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @exp.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/benchmarks/prime.py.ast.typed.s b/src/test/data/pa3/benchmarks/prime.py.ast.typed.s
new file mode 100644
index 0000000..95e6a74
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/prime.py.ast.typed.s
@@ -0,0 +1,789 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $n
+$n:
+ .word 15 # Initial value of global var: n
+
+.globl $i
+$i:
+ .word 1 # Initial value of global var: i
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ j label_2 # Jump to loop test
+label_1: # Top of while loop
+ lw a0, $i # Load global: i
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $get_prime # Invoke function: get_prime
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, $i, t0 # Assign global: i (using tmp register)
+label_2: # Test loop condition
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $n # Load global: n
+ lw t0, -12(fp) # Pop stack slot 3
+ bge a0, t0, label_1 # Branch on <=
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $get_prime
+$get_prime:
+ addi sp, sp, -@get_prime.size # Reserve space for stack frame.
+ sw ra, @get_prime.size-4(sp) # return address
+ sw fp, @get_prime.size-8(sp) # control link
+ addi fp, sp, @get_prime.size # New fp is at old SP.
+ li a0, 2 # Load integer literal 2
+ sw a0, -12(fp) # local variable candidate
+ li a0, 0 # Load integer literal 0
+ sw a0, -16(fp) # local variable found
+ j label_6 # Jump to loop test
+label_5: # Top of while loop
+ lw a0, -12(fp) # Load var: get_prime.candidate
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $is_prime # Invoke function: is_prime
+ addi sp, fp, -@get_prime.size # Set SP to stack frame top.
+ beqz a0, label_7 # Branch on false.
+ lw a0, -16(fp) # Load var: get_prime.found
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load integer literal 1
+ lw t0, -20(fp) # Pop stack slot 5
+ add a0, t0, a0 # Operator +
+ sw a0, -16(fp) # Assign var: get_prime.found
+ lw a0, -16(fp) # Load var: get_prime.found
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, 0(fp) # Load var: get_prime.n
+ lw t0, -20(fp) # Pop stack slot 5
+ bne t0, a0, label_8 # Branch on not ==
+ lw a0, -12(fp) # Load var: get_prime.candidate
+ j label_4 # Go to return
+label_8: # End of if-else statement
+label_7: # End of if-else statement
+ lw a0, -12(fp) # Load var: get_prime.candidate
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load integer literal 1
+ lw t0, -20(fp) # Pop stack slot 5
+ add a0, t0, a0 # Operator +
+ sw a0, -12(fp) # Assign var: get_prime.candidate
+label_6: # Test loop condition
+ j label_5 # Branch on true.
+ li a0, 0 # Load integer literal 0
+ j label_4 # Go to return
+ mv a0, zero # Load None
+ j label_4 # Jump to function epilogue
+label_4: # Epilogue
+ .equiv @get_prime.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @get_prime.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $is_prime
+$is_prime:
+ addi sp, sp, -@is_prime.size # Reserve space for stack frame.
+ sw ra, @is_prime.size-4(sp) # return address
+ sw fp, @is_prime.size-8(sp) # control link
+ addi fp, sp, @is_prime.size # New fp is at old SP.
+ li a0, 2 # Load integer literal 2
+ sw a0, -12(fp) # local variable div
+ j label_12 # Jump to loop test
+label_11: # Top of while loop
+ lw a0, 0(fp) # Load var: is_prime.x
+ sw a0, -16(fp) # Push on stack slot 4
+ lw a0, -12(fp) # Load var: is_prime.div
+ lw t0, -16(fp) # Pop stack slot 4
+ bnez a0, label_14 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_14: # Divisor is non-zero
+ rem t2, t0, a0 # Operator rem
+ beqz t2, label_15 # If no remainder, no adjustment
+ xor t3, t2, a0 # Check for differing signs.
+ bgez t3, label_15 # Don't adjust if signs equal.
+ add a0, t2, a0 # Adjust
+ j label_16
+label_15: # Store result
+ mv a0, t2
+label_16: # End of %
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 0 # Load integer literal 0
+ lw t0, -16(fp) # Pop stack slot 4
+ bne t0, a0, label_13 # Branch on not ==
+ li a0, 0 # Load boolean literal: false
+ j label_10 # Go to return
+label_13: # End of if-else statement
+ lw a0, -12(fp) # Load var: is_prime.div
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 1 # Load integer literal 1
+ lw t0, -16(fp) # Pop stack slot 4
+ add a0, t0, a0 # Operator +
+ sw a0, -12(fp) # Assign var: is_prime.div
+label_12: # Test loop condition
+ lw a0, -12(fp) # Load var: is_prime.div
+ sw a0, -16(fp) # Push on stack slot 4
+ lw a0, 0(fp) # Load var: is_prime.x
+ lw t0, -16(fp) # Pop stack slot 4
+ blt t0, a0, label_11 # Branch on <
+ li a0, 1 # Load boolean literal: true
+ j label_10 # Go to return
+ mv a0, zero # Load None
+ j label_10 # Jump to function epilogue
+label_10: # Epilogue
+ .equiv @is_prime.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @is_prime.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/benchmarks/sieve.py.ast.typed.s b/src/test/data/pa3/benchmarks/sieve.py.ast.typed.s
new file mode 100644
index 0000000..2805e7b
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/sieve.py.ast.typed.s
@@ -0,0 +1,1492 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $Vector$prototype
+$Vector$prototype:
+ .word 4 # Type tag for class: Vector
+ .word 5 # Object size
+ .word $Vector$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: items
+ .word 0 # Initial value of attribute: size
+ .align 2
+
+.globl $DoublingVector$prototype
+$DoublingVector$prototype:
+ .word 5 # Type tag for class: DoublingVector
+ .word 6 # Object size
+ .word $DoublingVector$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: items
+ .word 0 # Initial value of attribute: size
+ .word 1000 # Initial value of attribute: doubling_limit
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $Vector$dispatchTable
+$Vector$dispatchTable:
+ .word $Vector.__init__ # Implementation for method: Vector.__init__
+ .word $Vector.capacity # Implementation for method: Vector.capacity
+ .word $Vector.increase_capacity # Implementation for method: Vector.increase_capacity
+ .word $Vector.append # Implementation for method: Vector.append
+ .word $Vector.append_all # Implementation for method: Vector.append_all
+ .word $Vector.remove_at # Implementation for method: Vector.remove_at
+ .word $Vector.get # Implementation for method: Vector.get
+ .word $Vector.length # Implementation for method: Vector.length
+
+.globl $DoublingVector$dispatchTable
+$DoublingVector$dispatchTable:
+ .word $Vector.__init__ # Implementation for method: DoublingVector.__init__
+ .word $Vector.capacity # Implementation for method: DoublingVector.capacity
+ .word $DoublingVector.increase_capacity # Implementation for method: DoublingVector.increase_capacity
+ .word $Vector.append # Implementation for method: DoublingVector.append
+ .word $Vector.append_all # Implementation for method: DoublingVector.append_all
+ .word $Vector.remove_at # Implementation for method: DoublingVector.remove_at
+ .word $Vector.get # Implementation for method: DoublingVector.get
+ .word $Vector.length # Implementation for method: DoublingVector.length
+
+.globl $n
+$n:
+ .word 50 # Initial value of global var: n
+
+.globl $v
+$v:
+ .word 0 # Initial value of global var: v
+
+.globl $i
+$i:
+ .word 0 # Initial value of global var: i
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 2 # Load integer literal 2
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, $n # Load global: n
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $vrange # Invoke function: vrange
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $v, t0 # Assign global: v (using tmp register)
+ lw a0, $v # Load global: v
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $sieve # Invoke function: sieve
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_2 # Jump to loop test
+label_1: # Top of while loop
+ lw a0, $v # Load global: v
+ bnez a0, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $i # Load global: i
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -28(fp) # Peek stack slot 6
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 24(a1) # Load address of method: Vector.get
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.get
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, $i, t0 # Assign global: i (using tmp register)
+label_2: # Test loop condition
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $v # Load global: v
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -16(fp) # Peek stack slot 3
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 28(a1) # Load address of method: Vector.length
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.length
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw t0, -12(fp) # Pop stack slot 3
+ blt t0, a0, label_1 # Branch on <
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $Vector.__init__
+$Vector.__init__:
+ addi sp, sp, -@Vector.__init__.size # Reserve space for stack frame.
+ sw ra, @Vector.__init__.size-4(sp) # return address
+ sw fp, @Vector.__init__.size-8(sp) # control link
+ addi fp, sp, @Vector.__init__.size # New fp is at old SP.
+ li a0, 0 # Load integer literal 0
+ sw a0, -12(fp) # Push argument 1 from last.
+ li a0, 1 # Pass list length
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@Vector.__init__.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: Vector.__init__.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_7 # Ensure not None
+ j error.None # Go to error handler
+label_7: # Not None
+ sw a0, 12(a1) # Set attribute: Vector.items
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @Vector.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @Vector.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $Vector.capacity
+$Vector.capacity:
+ addi sp, sp, -@Vector.capacity.size # Reserve space for stack frame.
+ sw ra, @Vector.capacity.size-4(sp) # return address
+ sw fp, @Vector.capacity.size-8(sp) # control link
+ addi fp, sp, @Vector.capacity.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: Vector.capacity.self
+ bnez a0, label_10 # Ensure not None
+ j error.None # Go to error handler
+label_10: # Not None
+ lw a0, 12(a0) # Get attribute: Vector.items
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@Vector.capacity.size # Set SP to stack frame top.
+ j label_9 # Go to return
+ mv a0, zero # Load None
+ j label_9 # Jump to function epilogue
+label_9: # Epilogue
+ .equiv @Vector.capacity.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @Vector.capacity.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $Vector.increase_capacity
+$Vector.increase_capacity:
+ addi sp, sp, -@Vector.increase_capacity.size # Reserve space for stack frame.
+ sw ra, @Vector.increase_capacity.size-4(sp) # return address
+ sw fp, @Vector.increase_capacity.size-8(sp) # control link
+ addi fp, sp, @Vector.increase_capacity.size # New fp is at old SP.
+ la t0, noconv # Identity conversion
+ sw t0, -20(fp) # Push argument 3 from last.
+ la t0, noconv # Identity conversion
+ sw t0, -24(fp) # Push argument 2 from last.
+ lw a0, 0(fp) # Load var: Vector.increase_capacity.self
+ bnez a0, label_13 # Ensure not None
+ j error.None # Go to error handler
+label_13: # Not None
+ lw a0, 12(a0) # Get attribute: Vector.items
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 0 # Load integer literal 0
+ sw a0, -44(fp) # Push argument 1 from last.
+ li a0, 1 # Pass list length
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@Vector.increase_capacity.size # Set SP to stack frame top.
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal concat # Call runtime concatenation routine.
+ addi sp, fp, -@Vector.increase_capacity.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: Vector.increase_capacity.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_14 # Ensure not None
+ j error.None # Go to error handler
+label_14: # Not None
+ sw a0, 12(a1) # Set attribute: Vector.items
+ lw a0, 0(fp) # Load var: Vector.increase_capacity.self
+ bnez a0, label_15 # Ensure not None
+ j error.None # Go to error handler
+label_15: # Not None
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -16(fp) # Peek stack slot 3
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: Vector.capacity
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.capacity
+ addi sp, fp, -@Vector.increase_capacity.size # Set SP to stack frame top.
+ j label_12 # Go to return
+ mv a0, zero # Load None
+ j label_12 # Jump to function epilogue
+label_12: # Epilogue
+ .equiv @Vector.increase_capacity.size, 48
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @Vector.increase_capacity.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $Vector.append
+$Vector.append:
+ addi sp, sp, -@Vector.append.size # Reserve space for stack frame.
+ sw ra, @Vector.append.size-4(sp) # return address
+ sw fp, @Vector.append.size-8(sp) # control link
+ addi fp, sp, @Vector.append.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: Vector.append.self
+ bnez a0, label_19 # Ensure not None
+ j error.None # Go to error handler
+label_19: # Not None
+ lw a0, 16(a0) # Get attribute: Vector.size
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: Vector.append.self
+ bnez a0, label_20 # Ensure not None
+ j error.None # Go to error handler
+label_20: # Not None
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -16(fp) # Peek stack slot 3
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: Vector.capacity
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.capacity
+ addi sp, fp, -@Vector.append.size # Set SP to stack frame top.
+ lw t0, -12(fp) # Pop stack slot 3
+ bne t0, a0, label_18 # Branch on not ==
+ lw a0, 4(fp) # Load var: Vector.append.self
+ bnez a0, label_21 # Ensure not None
+ j error.None # Go to error handler
+label_21: # Not None
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -16(fp) # Peek stack slot 3
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 8(a1) # Load address of method: Vector.increase_capacity
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.increase_capacity
+ addi sp, fp, -@Vector.append.size # Set SP to stack frame top.
+label_18: # End of if-else statement
+ lw a0, 0(fp) # Load var: Vector.append.item
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: Vector.append.self
+ bnez a0, label_22 # Ensure not None
+ j error.None # Go to error handler
+label_22: # Not None
+ lw a0, 12(a0) # Get attribute: Vector.items
+ sw a0, -16(fp) # Push on stack slot 4
+ lw a0, 4(fp) # Load var: Vector.append.self
+ bnez a0, label_23 # Ensure not None
+ j error.None # Go to error handler
+label_23: # Not None
+ lw a0, 16(a0) # Get attribute: Vector.size
+ lw t0, -16(fp) # Pop stack slot 4
+ lw t1, -12(fp) # Pop stack slot 3
+ bnez t0, label_24 # Ensure not None
+ j error.None # Go to error handler
+label_24: # Not None
+ lw t2, 12(t0) # Load attribute: __len__
+ bltu a0, t2, label_25 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_25: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul a0, a0, t2 # Compute list element offset in bytes
+ add a0, t0, a0 # Pointer to list element
+ sw t1, 0(a0) # Set list element
+ lw a0, 4(fp) # Load var: Vector.append.self
+ bnez a0, label_26 # Ensure not None
+ j error.None # Go to error handler
+label_26: # Not None
+ lw a0, 16(a0) # Get attribute: Vector.size
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: Vector.append.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_27 # Ensure not None
+ j error.None # Go to error handler
+label_27: # Not None
+ sw a0, 16(a1) # Set attribute: Vector.size
+ mv a0, zero # Load None
+ j label_17 # Jump to function epilogue
+label_17: # Epilogue
+ .equiv @Vector.append.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @Vector.append.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $Vector.append_all
+$Vector.append_all:
+ addi sp, sp, -@Vector.append_all.size # Reserve space for stack frame.
+ sw ra, @Vector.append_all.size-4(sp) # return address
+ sw fp, @Vector.append_all.size-8(sp) # control link
+ addi fp, sp, @Vector.append_all.size # New fp is at old SP.
+ li a0, 0 # Load integer literal 0
+ sw a0, -12(fp) # local variable item
+ lw a0, 0(fp) # Load var: Vector.append_all.new_items
+ bnez a0, label_30 # Ensure not None
+ j error.None # Go to error handler
+label_30: # Not None
+ sw a0, -16(fp) # Push on stack slot 4
+ mv t1, zero # Initialize for-loop index
+ sw t1, -20(fp) # Push on stack slot 5
+label_31: # for-loop header
+ lw t1, -20(fp) # Pop stack slot 5
+ lw t0, -16(fp) # Peek stack slot 3
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_32 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -20(fp) # Push on stack slot 5
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, -12(fp) # Assign var: Vector.append_all.item
+ lw a0, 4(fp) # Load var: Vector.append_all.self
+ bnez a0, label_33 # Ensure not None
+ j error.None # Go to error handler
+label_33: # Not None
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, -12(fp) # Load var: Vector.append_all.item
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -28(fp) # Peek stack slot 6
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 12(a1) # Load address of method: Vector.append
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.append
+ addi sp, fp, -@Vector.append_all.size # Set SP to stack frame top.
+ j label_31 # Loop back to header
+label_32: # for-loop footer
+ mv a0, zero # Load None
+ j label_29 # Jump to function epilogue
+label_29: # Epilogue
+ .equiv @Vector.append_all.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @Vector.append_all.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $Vector.remove_at
+$Vector.remove_at:
+ addi sp, sp, -@Vector.remove_at.size # Reserve space for stack frame.
+ sw ra, @Vector.remove_at.size-4(sp) # return address
+ sw fp, @Vector.remove_at.size-8(sp) # control link
+ addi fp, sp, @Vector.remove_at.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: Vector.remove_at.idx
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 0 # Load integer literal 0
+ lw t0, -12(fp) # Pop stack slot 3
+ bge t0, a0, label_36 # Branch on not <
+ mv a0, zero # Returning None implicitly
+ j label_35 # Go to return
+label_36: # End of if-else statement
+ j label_38 # Jump to loop test
+label_37: # Top of while loop
+ lw a0, 4(fp) # Load var: Vector.remove_at.self
+ bnez a0, label_39 # Ensure not None
+ j error.None # Go to error handler
+label_39: # Not None
+ lw a0, 12(a0) # Get attribute: Vector.items
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: Vector.remove_at.idx
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 1 # Load integer literal 1
+ lw t0, -16(fp) # Pop stack slot 4
+ add a0, t0, a0 # Operator +
+ lw a1, -12(fp) # Pop stack slot 3
+ bnez a1, label_40 # Ensure not None
+ j error.None # Go to error handler
+label_40: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_41 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_41: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: Vector.remove_at.self
+ bnez a0, label_42 # Ensure not None
+ j error.None # Go to error handler
+label_42: # Not None
+ lw a0, 12(a0) # Get attribute: Vector.items
+ sw a0, -16(fp) # Push on stack slot 4
+ lw a0, 0(fp) # Load var: Vector.remove_at.idx
+ lw t0, -16(fp) # Pop stack slot 4
+ lw t1, -12(fp) # Pop stack slot 3
+ bnez t0, label_43 # Ensure not None
+ j error.None # Go to error handler
+label_43: # Not None
+ lw t2, 12(t0) # Load attribute: __len__
+ bltu a0, t2, label_44 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_44: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul a0, a0, t2 # Compute list element offset in bytes
+ add a0, t0, a0 # Pointer to list element
+ sw t1, 0(a0) # Set list element
+ lw a0, 0(fp) # Load var: Vector.remove_at.idx
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, 0(fp) # Assign var: Vector.remove_at.idx
+label_38: # Test loop condition
+ lw a0, 0(fp) # Load var: Vector.remove_at.idx
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: Vector.remove_at.self
+ bnez a0, label_45 # Ensure not None
+ j error.None # Go to error handler
+label_45: # Not None
+ lw a0, 16(a0) # Get attribute: Vector.size
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 1 # Load integer literal 1
+ lw t0, -16(fp) # Pop stack slot 4
+ sub a0, t0, a0 # Operator -
+ lw t0, -12(fp) # Pop stack slot 3
+ blt t0, a0, label_37 # Branch on <
+ lw a0, 4(fp) # Load var: Vector.remove_at.self
+ bnez a0, label_46 # Ensure not None
+ j error.None # Go to error handler
+label_46: # Not None
+ lw a0, 16(a0) # Get attribute: Vector.size
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ sub a0, t0, a0 # Operator -
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: Vector.remove_at.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_47 # Ensure not None
+ j error.None # Go to error handler
+label_47: # Not None
+ sw a0, 16(a1) # Set attribute: Vector.size
+ mv a0, zero # Load None
+ j label_35 # Jump to function epilogue
+label_35: # Epilogue
+ .equiv @Vector.remove_at.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @Vector.remove_at.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $Vector.get
+$Vector.get:
+ addi sp, sp, -@Vector.get.size # Reserve space for stack frame.
+ sw ra, @Vector.get.size-4(sp) # return address
+ sw fp, @Vector.get.size-8(sp) # control link
+ addi fp, sp, @Vector.get.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: Vector.get.self
+ bnez a0, label_50 # Ensure not None
+ j error.None # Go to error handler
+label_50: # Not None
+ lw a0, 12(a0) # Get attribute: Vector.items
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: Vector.get.idx
+ lw a1, -12(fp) # Pop stack slot 3
+ bnez a1, label_51 # Ensure not None
+ j error.None # Go to error handler
+label_51: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_52 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_52: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ j label_49 # Go to return
+ mv a0, zero # Load None
+ j label_49 # Jump to function epilogue
+label_49: # Epilogue
+ .equiv @Vector.get.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @Vector.get.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $Vector.length
+$Vector.length:
+ addi sp, sp, -@Vector.length.size # Reserve space for stack frame.
+ sw ra, @Vector.length.size-4(sp) # return address
+ sw fp, @Vector.length.size-8(sp) # control link
+ addi fp, sp, @Vector.length.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: Vector.length.self
+ bnez a0, label_55 # Ensure not None
+ j error.None # Go to error handler
+label_55: # Not None
+ lw a0, 16(a0) # Get attribute: Vector.size
+ j label_54 # Go to return
+ mv a0, zero # Load None
+ j label_54 # Jump to function epilogue
+label_54: # Epilogue
+ .equiv @Vector.length.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @Vector.length.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $DoublingVector.increase_capacity
+$DoublingVector.increase_capacity:
+ addi sp, sp, -@DoublingVector.increase_capacity.size # Reserve space for stack frame.
+ sw ra, @DoublingVector.increase_capacity.size-4(sp) # return address
+ sw fp, @DoublingVector.increase_capacity.size-8(sp) # control link
+ addi fp, sp, @DoublingVector.increase_capacity.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self
+ bnez a0, label_60 # Ensure not None
+ j error.None # Go to error handler
+label_60: # Not None
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -16(fp) # Peek stack slot 3
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: DoublingVector.capacity
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: DoublingVector.capacity
+ addi sp, fp, -@DoublingVector.increase_capacity.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self
+ bnez a0, label_61 # Ensure not None
+ j error.None # Go to error handler
+label_61: # Not None
+ lw a0, 20(a0) # Get attribute: DoublingVector.doubling_limit
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 2 # Load integer literal 2
+ lw t0, -16(fp) # Pop stack slot 4
+ bnez a0, label_62 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_62: # Divisor is non-zero
+ xor t2, t0, a0 # Check for same sign
+ bltz t2, label_64 # If !=, need to adjust left operand
+ div a0, t0, a0 # Operator //
+ j label_63
+label_64: # Operands have differing signs
+ slt t2, zero, a0 # tmp = 1 if right > 0 else 0
+ add t2, t2, t2 # tmp *= 2
+ addi t2, t2, -1 # tmp = 1 if right>=0 else -1
+ add t2, t0, t2 # Adjust left operand
+ div t2, t2, a0 # Adjusted division, toward 0
+ addi a0, t2, -1 # Complete division when signs !=
+label_63: # End of //
+ lw t0, -12(fp) # Pop stack slot 3
+ blt a0, t0, label_59 # Branch on not <=
+ la t0, noconv # Identity conversion
+ sw t0, -20(fp) # Push argument 3 from last.
+ la t0, noconv # Identity conversion
+ sw t0, -24(fp) # Push argument 2 from last.
+ lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self
+ bnez a0, label_65 # Ensure not None
+ j error.None # Go to error handler
+label_65: # Not None
+ lw a0, 12(a0) # Get attribute: DoublingVector.items
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self
+ bnez a0, label_66 # Ensure not None
+ j error.None # Go to error handler
+label_66: # Not None
+ lw a0, 12(a0) # Get attribute: DoublingVector.items
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal concat # Call runtime concatenation routine.
+ addi sp, fp, -@DoublingVector.increase_capacity.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_67 # Ensure not None
+ j error.None # Go to error handler
+label_67: # Not None
+ sw a0, 12(a1) # Set attribute: DoublingVector.items
+ j label_58 # Then body complete; jump to end-if
+label_59: # Else body
+ la t0, noconv # Identity conversion
+ sw t0, -20(fp) # Push argument 3 from last.
+ la t0, noconv # Identity conversion
+ sw t0, -24(fp) # Push argument 2 from last.
+ lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self
+ bnez a0, label_68 # Ensure not None
+ j error.None # Go to error handler
+label_68: # Not None
+ lw a0, 12(a0) # Get attribute: DoublingVector.items
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 0 # Load integer literal 0
+ sw a0, -44(fp) # Push argument 1 from last.
+ li a0, 1 # Pass list length
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@DoublingVector.increase_capacity.size # Set SP to stack frame top.
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal concat # Call runtime concatenation routine.
+ addi sp, fp, -@DoublingVector.increase_capacity.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_69 # Ensure not None
+ j error.None # Go to error handler
+label_69: # Not None
+ sw a0, 12(a1) # Set attribute: DoublingVector.items
+label_58: # End of if-else statement
+ lw a0, 0(fp) # Load var: DoublingVector.increase_capacity.self
+ bnez a0, label_70 # Ensure not None
+ j error.None # Go to error handler
+label_70: # Not None
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -16(fp) # Peek stack slot 3
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: DoublingVector.capacity
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: DoublingVector.capacity
+ addi sp, fp, -@DoublingVector.increase_capacity.size # Set SP to stack frame top.
+ j label_57 # Go to return
+ mv a0, zero # Load None
+ j label_57 # Jump to function epilogue
+label_57: # Epilogue
+ .equiv @DoublingVector.increase_capacity.size, 48
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @DoublingVector.increase_capacity.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $vrange
+$vrange:
+ addi sp, sp, -@vrange.size # Reserve space for stack frame.
+ sw ra, @vrange.size-4(sp) # return address
+ sw fp, @vrange.size-8(sp) # control link
+ addi fp, sp, @vrange.size # New fp is at old SP.
+ mv a0, zero # Load None
+ sw a0, -12(fp) # local variable v
+ la a0, $DoublingVector$prototype # Load pointer to prototype of: DoublingVector
+ jal alloc # Allocate new object in A0
+ sw a0, -16(fp) # Push on stack slot 4
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: DoublingVector.__init__
+ jalr a1 # Invoke method: DoublingVector.__init__
+ addi sp, fp, -@vrange.size # Set SP to stack frame top.
+ lw a0, -16(fp) # Pop stack slot 4
+ sw a0, -12(fp) # Assign var: vrange.v
+ j label_74 # Jump to loop test
+label_73: # Top of while loop
+ lw a0, -12(fp) # Load var: vrange.v
+ bnez a0, label_75 # Ensure not None
+ j error.None # Go to error handler
+label_75: # Not None
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, 4(fp) # Load var: vrange.i
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -28(fp) # Peek stack slot 6
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 12(a1) # Load address of method: Vector.append
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.append
+ addi sp, fp, -@vrange.size # Set SP to stack frame top.
+ lw a0, 4(fp) # Load var: vrange.i
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 1 # Load integer literal 1
+ lw t0, -16(fp) # Pop stack slot 4
+ add a0, t0, a0 # Operator +
+ sw a0, 4(fp) # Assign var: vrange.i
+label_74: # Test loop condition
+ lw a0, 4(fp) # Load var: vrange.i
+ sw a0, -16(fp) # Push on stack slot 4
+ lw a0, 0(fp) # Load var: vrange.j
+ lw t0, -16(fp) # Pop stack slot 4
+ blt t0, a0, label_73 # Branch on <
+ lw a0, -12(fp) # Load var: vrange.v
+ j label_72 # Go to return
+ mv a0, zero # Load None
+ j label_72 # Jump to function epilogue
+label_72: # Epilogue
+ .equiv @vrange.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @vrange.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $sieve
+$sieve:
+ addi sp, sp, -@sieve.size # Reserve space for stack frame.
+ sw ra, @sieve.size-4(sp) # return address
+ sw fp, @sieve.size-8(sp) # control link
+ addi fp, sp, @sieve.size # New fp is at old SP.
+ li a0, 0 # Load integer literal 0
+ sw a0, -12(fp) # local variable i
+ li a0, 0 # Load integer literal 0
+ sw a0, -16(fp) # local variable j
+ li a0, 0 # Load integer literal 0
+ sw a0, -20(fp) # local variable k
+ j label_79 # Jump to loop test
+label_78: # Top of while loop
+ lw a0, 0(fp) # Load var: sieve.v
+ bnez a0, label_80 # Ensure not None
+ j error.None # Go to error handler
+label_80: # Not None
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, -12(fp) # Load var: sieve.i
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -28(fp) # Peek stack slot 6
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 24(a1) # Load address of method: Vector.get
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.get
+ addi sp, fp, -@sieve.size # Set SP to stack frame top.
+ sw a0, -20(fp) # Assign var: sieve.k
+ lw a0, -12(fp) # Load var: sieve.i
+ sw a0, -24(fp) # Push on stack slot 6
+ li a0, 1 # Load integer literal 1
+ lw t0, -24(fp) # Pop stack slot 6
+ add a0, t0, a0 # Operator +
+ sw a0, -16(fp) # Assign var: sieve.j
+ j label_82 # Jump to loop test
+label_81: # Top of while loop
+ lw a0, 0(fp) # Load var: sieve.v
+ bnez a0, label_85 # Ensure not None
+ j error.None # Go to error handler
+label_85: # Not None
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, -16(fp) # Load var: sieve.j
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -28(fp) # Peek stack slot 6
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 24(a1) # Load address of method: Vector.get
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.get
+ addi sp, fp, -@sieve.size # Set SP to stack frame top.
+ sw a0, -24(fp) # Push on stack slot 6
+ lw a0, -20(fp) # Load var: sieve.k
+ lw t0, -24(fp) # Pop stack slot 6
+ bnez a0, label_86 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_86: # Divisor is non-zero
+ rem t2, t0, a0 # Operator rem
+ beqz t2, label_87 # If no remainder, no adjustment
+ xor t3, t2, a0 # Check for differing signs.
+ bgez t3, label_87 # Don't adjust if signs equal.
+ add a0, t2, a0 # Adjust
+ j label_88
+label_87: # Store result
+ mv a0, t2
+label_88: # End of %
+ sw a0, -24(fp) # Push on stack slot 6
+ li a0, 0 # Load integer literal 0
+ lw t0, -24(fp) # Pop stack slot 6
+ bne t0, a0, label_84 # Branch on not ==
+ lw a0, 0(fp) # Load var: sieve.v
+ bnez a0, label_89 # Ensure not None
+ j error.None # Go to error handler
+label_89: # Not None
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, -16(fp) # Load var: sieve.j
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -28(fp) # Peek stack slot 6
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 20(a1) # Load address of method: Vector.remove_at
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.remove_at
+ addi sp, fp, -@sieve.size # Set SP to stack frame top.
+ j label_83 # Then body complete; jump to end-if
+label_84: # Else body
+ lw a0, -16(fp) # Load var: sieve.j
+ sw a0, -24(fp) # Push on stack slot 6
+ li a0, 1 # Load integer literal 1
+ lw t0, -24(fp) # Pop stack slot 6
+ add a0, t0, a0 # Operator +
+ sw a0, -16(fp) # Assign var: sieve.j
+label_83: # End of if-else statement
+label_82: # Test loop condition
+ lw a0, -16(fp) # Load var: sieve.j
+ sw a0, -24(fp) # Push on stack slot 6
+ lw a0, 0(fp) # Load var: sieve.v
+ bnez a0, label_90 # Ensure not None
+ j error.None # Go to error handler
+label_90: # Not None
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -32(fp) # Peek stack slot 7
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 28(a1) # Load address of method: Vector.length
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.length
+ addi sp, fp, -@sieve.size # Set SP to stack frame top.
+ lw t0, -24(fp) # Pop stack slot 6
+ blt t0, a0, label_81 # Branch on <
+ lw a0, -12(fp) # Load var: sieve.i
+ sw a0, -24(fp) # Push on stack slot 6
+ li a0, 1 # Load integer literal 1
+ lw t0, -24(fp) # Pop stack slot 6
+ add a0, t0, a0 # Operator +
+ sw a0, -12(fp) # Assign var: sieve.i
+label_79: # Test loop condition
+ lw a0, -12(fp) # Load var: sieve.i
+ sw a0, -24(fp) # Push on stack slot 6
+ lw a0, 0(fp) # Load var: sieve.v
+ bnez a0, label_91 # Ensure not None
+ j error.None # Go to error handler
+label_91: # Not None
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -32(fp) # Peek stack slot 7
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 28(a1) # Load address of method: Vector.length
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: Vector.length
+ addi sp, fp, -@sieve.size # Set SP to stack frame top.
+ lw t0, -24(fp) # Pop stack slot 6
+ blt t0, a0, label_78 # Branch on <
+ mv a0, zero # Load None
+ j label_77 # Jump to function epilogue
+label_77: # Epilogue
+ .equiv @sieve.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @sieve.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/benchmarks/stdlib.py.ast.typed.s b/src/test/data/pa3/benchmarks/stdlib.py.ast.typed.s
new file mode 100644
index 0000000..36ff54e
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/stdlib.py.ast.typed.s
@@ -0,0 +1,1198 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $c
+$c:
+ .word 42 # Initial value of global var: c
+
+.globl $n
+$n:
+ .word 10 # Initial value of global var: n
+
+.globl $s
+$s:
+ .word const_2 # Initial value of global var: s
+
+.globl $i
+$i:
+ .word 0 # Initial value of global var: i
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $n # Load global: n
+ sub a0, zero, a0 # Unary negation
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $c # Load global: c
+ lw t0, -12(fp) # Pop stack slot 3
+ mul a0, t0, a0 # Operator *
+ sw a0, $i, t0 # Assign global: i (using tmp register)
+ j label_2 # Jump to loop test
+label_1: # Top of while loop
+ lw a0, $i # Load global: i
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $int_to_str # Invoke function: int_to_str
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $s, t0 # Assign global: s (using tmp register)
+ lw a0, $s # Load global: s
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $s # Load global: s
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $str_to_int # Invoke function: str_to_int
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $c # Load global: c
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, $i, t0 # Assign global: i (using tmp register)
+label_2: # Test loop condition
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $n # Load global: n
+ sw a0, -16(fp) # Push on stack slot 4
+ lw a0, $c # Load global: c
+ lw t0, -16(fp) # Pop stack slot 4
+ mul a0, t0, a0 # Operator *
+ lw t0, -12(fp) # Pop stack slot 3
+ bge a0, t0, label_1 # Branch on <=
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_4 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_5 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $int_to_str
+$int_to_str:
+ addi sp, sp, -@int_to_str.size # Reserve space for stack frame.
+ sw ra, @int_to_str.size-4(sp) # return address
+ sw fp, @int_to_str.size-8(sp) # control link
+ addi fp, sp, @int_to_str.size # New fp is at old SP.
+ mv a0, zero # Load None
+ sw a0, -12(fp) # local variable digits
+ la a0, const_2 # Load string literal
+ sw a0, -16(fp) # local variable result
+ la a0, const_6 # Load string literal
+ sw a0, -24(fp) # Push argument 10 from last.
+ la a0, const_7 # Load string literal
+ sw a0, -28(fp) # Push argument 9 from last.
+ la a0, const_8 # Load string literal
+ sw a0, -32(fp) # Push argument 8 from last.
+ la a0, const_9 # Load string literal
+ sw a0, -36(fp) # Push argument 7 from last.
+ la a0, const_10 # Load string literal
+ sw a0, -40(fp) # Push argument 6 from last.
+ la a0, const_11 # Load string literal
+ sw a0, -44(fp) # Push argument 5 from last.
+ la a0, const_12 # Load string literal
+ sw a0, -48(fp) # Push argument 4 from last.
+ la a0, const_13 # Load string literal
+ sw a0, -52(fp) # Push argument 3 from last.
+ la a0, const_14 # Load string literal
+ sw a0, -56(fp) # Push argument 2 from last.
+ la a0, const_15 # Load string literal
+ sw a0, -60(fp) # Push argument 1 from last.
+ li a0, 10 # Pass list length
+ sw a0, -64(fp) # Push argument 0 from last.
+ addi sp, fp, -64 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@int_to_str.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Assign var: int_to_str.digits
+ lw a0, 0(fp) # Load var: int_to_str.x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load integer literal 0
+ lw t0, -20(fp) # Pop stack slot 5
+ bge t0, a0, label_5 # Branch on not <
+ la a0, const_16 # Load string literal
+ sw a0, -16(fp) # Assign var: int_to_str.result
+ lw a0, 0(fp) # Load var: int_to_str.x
+ sub a0, zero, a0 # Unary negation
+ sw a0, 0(fp) # Assign var: int_to_str.x
+label_5: # End of if-else statement
+ lw a0, 0(fp) # Load var: int_to_str.x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 10 # Load integer literal 10
+ lw t0, -20(fp) # Pop stack slot 5
+ blt t0, a0, label_6 # Branch on not >=
+ lw a0, -16(fp) # Load var: int_to_str.result
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: int_to_str.x
+ sw a0, -52(fp) # Push on stack slot 13
+ li a0, 10 # Load integer literal 10
+ lw t0, -52(fp) # Pop stack slot 13
+ bnez a0, label_7 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_7: # Divisor is non-zero
+ xor t2, t0, a0 # Check for same sign
+ bltz t2, label_9 # If !=, need to adjust left operand
+ div a0, t0, a0 # Operator //
+ j label_8
+label_9: # Operands have differing signs
+ slt t2, zero, a0 # tmp = 1 if right > 0 else 0
+ add t2, t2, t2 # tmp *= 2
+ addi t2, t2, -1 # tmp = 1 if right>=0 else -1
+ add t2, t0, t2 # Adjust left operand
+ div t2, t2, a0 # Adjusted division, toward 0
+ addi a0, t2, -1 # Complete division when signs !=
+label_8: # End of //
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal $int_to_str # Invoke function: int_to_str
+ addi sp, fp, -@int_to_str.size # Set SP to stack frame top.
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal strcat # Call string concatenation function
+ addi sp, fp, -@int_to_str.size # Set SP to stack frame top.
+ sw a0, -16(fp) # Assign var: int_to_str.result
+label_6: # End of if-else statement
+ lw a0, -16(fp) # Load var: int_to_str.result
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, -12(fp) # Load var: int_to_str.digits
+ sw a0, -36(fp) # Push on stack slot 9
+ lw a0, 0(fp) # Load var: int_to_str.x
+ sw a0, -40(fp) # Push on stack slot 10
+ li a0, 10 # Load integer literal 10
+ lw t0, -40(fp) # Pop stack slot 10
+ bnez a0, label_10 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_10: # Divisor is non-zero
+ rem t2, t0, a0 # Operator rem
+ beqz t2, label_11 # If no remainder, no adjustment
+ xor t3, t2, a0 # Check for differing signs.
+ bgez t3, label_11 # Don't adjust if signs equal.
+ add a0, t2, a0 # Adjust
+ j label_12
+label_11: # Store result
+ mv a0, t2
+label_12: # End of %
+ lw a1, -36(fp) # Pop stack slot 9
+ bnez a1, label_13 # Ensure not None
+ j error.None # Go to error handler
+label_13: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_14 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_14: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal strcat # Call string concatenation function
+ addi sp, fp, -@int_to_str.size # Set SP to stack frame top.
+ sw a0, -16(fp) # Assign var: int_to_str.result
+ lw a0, -16(fp) # Load var: int_to_str.result
+ j label_4 # Go to return
+ mv a0, zero # Load None
+ j label_4 # Jump to function epilogue
+label_4: # Epilogue
+ .equiv @int_to_str.size, 64
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @int_to_str.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $str_to_int
+$str_to_int:
+ addi sp, sp, -@str_to_int.size # Reserve space for stack frame.
+ sw ra, @str_to_int.size-4(sp) # return address
+ sw fp, @str_to_int.size-8(sp) # control link
+ addi fp, sp, @str_to_int.size # New fp is at old SP.
+ li a0, 0 # Load integer literal 0
+ sw a0, -12(fp) # local variable result
+ li a0, 0 # Load integer literal 0
+ sw a0, -16(fp) # local variable digit
+ la a0, const_2 # Load string literal
+ sw a0, -20(fp) # local variable char
+ li a0, 1 # Load integer literal 1
+ sw a0, -24(fp) # local variable sign
+ li a0, 1 # Load boolean literal: true
+ sw a0, -28(fp) # local variable first_char
+ lw a0, 0(fp) # Load var: str_to_int.x
+ sw a0, -32(fp) # Push on stack slot 8
+ mv t1, zero # Initialize for-loop index
+ sw t1, -36(fp) # Push on stack slot 9
+label_17: # for-loop header
+ lw t1, -36(fp) # Peek stack slot 8
+ lw t0, -32(fp) # Peek stack slot 7
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_18 # Exit loop if idx >= len(iter)
+ lw t0, -36(fp) # Pop stack slot 9
+ lw a1, -32(fp) # Peek stack slot 7
+ addi t1, t0, 1 # Increment index for next iteration
+ sw t1, -36(fp) # Push on stack slot 9
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ sw a0, -20(fp) # Assign var: str_to_int.char
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_16 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_20 # Branch on false.
+ lw a0, -28(fp) # Load var: str_to_int.first_char
+ bnez a0, label_21 # Branch on true.
+ li a0, 0 # Load integer literal 0
+ j label_16 # Go to return
+label_21: # End of if-else statement
+ li a0, 1 # Load integer literal 1
+ sub a0, zero, a0 # Unary negation
+ sw a0, -24(fp) # Assign var: str_to_int.sign
+ j label_19 # Then body complete; jump to end-if
+label_20: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_6 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_23 # Branch on false.
+ li a0, 0 # Load integer literal 0
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_22 # Then body complete; jump to end-if
+label_23: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_7 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_25 # Branch on false.
+ li a0, 1 # Load integer literal 1
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_24 # Then body complete; jump to end-if
+label_25: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_8 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_27 # Branch on false.
+ li a0, 2 # Load integer literal 2
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_26 # Then body complete; jump to end-if
+label_27: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_9 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_29 # Branch on false.
+ li a0, 3 # Load integer literal 3
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_28 # Then body complete; jump to end-if
+label_29: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_9 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_31 # Branch on false.
+ li a0, 3 # Load integer literal 3
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_30 # Then body complete; jump to end-if
+label_31: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_10 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_33 # Branch on false.
+ li a0, 4 # Load integer literal 4
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_32 # Then body complete; jump to end-if
+label_33: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_11 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_35 # Branch on false.
+ li a0, 5 # Load integer literal 5
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_34 # Then body complete; jump to end-if
+label_35: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_12 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_37 # Branch on false.
+ li a0, 6 # Load integer literal 6
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_36 # Then body complete; jump to end-if
+label_37: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_13 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_39 # Branch on false.
+ li a0, 7 # Load integer literal 7
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_38 # Then body complete; jump to end-if
+label_39: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_14 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_41 # Branch on false.
+ li a0, 8 # Load integer literal 8
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_40 # Then body complete; jump to end-if
+label_41: # Else body
+ lw a0, -20(fp) # Load var: str_to_int.char
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_15 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@str_to_int.size # Set SP to stack frame top.
+ beqz a0, label_43 # Branch on false.
+ li a0, 9 # Load integer literal 9
+ sw a0, -16(fp) # Assign var: str_to_int.digit
+ j label_42 # Then body complete; jump to end-if
+label_43: # Else body
+ li a0, 0 # Load integer literal 0
+ j label_16 # Go to return
+label_42: # End of if-else statement
+label_40: # End of if-else statement
+label_38: # End of if-else statement
+label_36: # End of if-else statement
+label_34: # End of if-else statement
+label_32: # End of if-else statement
+label_30: # End of if-else statement
+label_28: # End of if-else statement
+label_26: # End of if-else statement
+label_24: # End of if-else statement
+label_22: # End of if-else statement
+label_19: # End of if-else statement
+ li a0, 0 # Load boolean literal: false
+ sw a0, -28(fp) # Assign var: str_to_int.first_char
+ lw a0, -12(fp) # Load var: str_to_int.result
+ sw a0, -40(fp) # Push on stack slot 10
+ li a0, 10 # Load integer literal 10
+ lw t0, -40(fp) # Pop stack slot 10
+ mul a0, t0, a0 # Operator *
+ sw a0, -40(fp) # Push on stack slot 10
+ lw a0, -16(fp) # Load var: str_to_int.digit
+ lw t0, -40(fp) # Pop stack slot 10
+ add a0, t0, a0 # Operator +
+ sw a0, -12(fp) # Assign var: str_to_int.result
+ j label_17 # Loop back to header
+label_18: # for-loop footer
+ lw a0, -12(fp) # Load var: str_to_int.result
+ sw a0, -32(fp) # Push on stack slot 8
+ lw a0, -24(fp) # Load var: str_to_int.sign
+ lw t0, -32(fp) # Pop stack slot 8
+ mul a0, t0, a0 # Operator *
+ j label_16 # Go to return
+ mv a0, zero # Load None
+ j label_16 # Jump to function epilogue
+label_16: # Epilogue
+ .equiv @str_to_int.size, 48
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @str_to_int.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_17 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ la a0, $str$prototype
+ lw t0, 0(a0)
+ lw t1, 4(a0)
+ lw t2, 8(a0)
+ li t3, 1
+ la a0, allChars
+ li t4, 256
+ mv t5, zero
+initchars_1:
+ sw t0, 0(a0)
+ sw t1, 4(a0)
+ sw t2, 8(a0)
+ sw t3, 12(a0)
+ sw t5, 16(a0)
+ addi a0, a0, 20
+ addi t5, t5, 1
+ bne t4, t5, initchars_1
+ jr ra
+ .data
+ .align 2
+ .globl allChars
+allChars:
+ .space 5120
+ .text
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_18 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_19 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_20 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_17
+const_17:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_16
+const_16:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "-" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "0" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "1" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_19
+const_19:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "2" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "3" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "4" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "5" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_12
+const_12:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "6" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_20
+const_20:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_13
+const_13:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "7" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_14
+const_14:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "8" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_15
+const_15:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "9" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_18
+const_18:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/benchmarks/tree.py.ast.typed.s b/src/test/data/pa3/benchmarks/tree.py.ast.typed.s
new file mode 100644
index 0000000..c6feef8
--- /dev/null
+++ b/src/test/data/pa3/benchmarks/tree.py.ast.typed.s
@@ -0,0 +1,1267 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $TreeNode$prototype
+$TreeNode$prototype:
+ .word 4 # Type tag for class: TreeNode
+ .word 6 # Object size
+ .word $TreeNode$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: value
+ .word 0 # Initial value of attribute: left
+ .word 0 # Initial value of attribute: right
+ .align 2
+
+.globl $Tree$prototype
+$Tree$prototype:
+ .word 5 # Type tag for class: Tree
+ .word 5 # Object size
+ .word $Tree$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: root
+ .word 0 # Initial value of attribute: size
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $TreeNode$dispatchTable
+$TreeNode$dispatchTable:
+ .word $object.__init__ # Implementation for method: TreeNode.__init__
+ .word $TreeNode.insert # Implementation for method: TreeNode.insert
+ .word $TreeNode.contains # Implementation for method: TreeNode.contains
+
+.globl $Tree$dispatchTable
+$Tree$dispatchTable:
+ .word $object.__init__ # Implementation for method: Tree.__init__
+ .word $Tree.insert # Implementation for method: Tree.insert
+ .word $Tree.contains # Implementation for method: Tree.contains
+
+.globl $n
+$n:
+ .word 100 # Initial value of global var: n
+
+.globl $c
+$c:
+ .word 4 # Initial value of global var: c
+
+.globl $t
+$t:
+ .word 0 # Initial value of global var: t
+
+.globl $i
+$i:
+ .word 0 # Initial value of global var: i
+
+.globl $k
+$k:
+ .word 37813 # Initial value of global var: k
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $Tree$prototype # Load pointer to prototype of: Tree
+ jal alloc # Allocate new object in A0
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: Tree.__init__
+ jalr a1 # Invoke method: Tree.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, $t, t0 # Assign global: t (using tmp register)
+ j label_2 # Jump to loop test
+label_1: # Top of while loop
+ lw a0, $t # Load global: t
+ bnez a0, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, $k # Load global: k
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: Tree.insert
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: Tree.insert
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $k # Load global: k
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 37813 # Load integer literal 37813
+ lw t0, -12(fp) # Pop stack slot 3
+ mul a0, t0, a0 # Operator *
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 37831 # Load integer literal 37831
+ lw t0, -12(fp) # Pop stack slot 3
+ bnez a0, label_4 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_4: # Divisor is non-zero
+ rem t2, t0, a0 # Operator rem
+ beqz t2, label_5 # If no remainder, no adjustment
+ xor t3, t2, a0 # Check for differing signs.
+ bgez t3, label_5 # Don't adjust if signs equal.
+ add a0, t2, a0 # Adjust
+ j label_6
+label_5: # Store result
+ mv a0, t2
+label_6: # End of %
+ sw a0, $k, t0 # Assign global: k (using tmp register)
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $c # Load global: c
+ lw t0, -12(fp) # Pop stack slot 3
+ bnez a0, label_8 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_8: # Divisor is non-zero
+ rem t2, t0, a0 # Operator rem
+ beqz t2, label_9 # If no remainder, no adjustment
+ xor t3, t2, a0 # Check for differing signs.
+ bgez t3, label_9 # Don't adjust if signs equal.
+ add a0, t2, a0 # Adjust
+ j label_10
+label_9: # Store result
+ mv a0, t2
+label_10: # End of %
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 0 # Load integer literal 0
+ lw t0, -12(fp) # Pop stack slot 3
+ beq t0, a0, label_7 # Branch on not !=
+ lw a0, $t # Load global: t
+ bnez a0, label_11 # Ensure not None
+ j error.None # Go to error handler
+label_11: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, $i # Load global: i
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: Tree.insert
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: Tree.insert
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+label_7: # End of if-else statement
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, $i, t0 # Assign global: i (using tmp register)
+label_2: # Test loop condition
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $n # Load global: n
+ lw t0, -12(fp) # Pop stack slot 3
+ blt t0, a0, label_1 # Branch on <
+ lw a0, $t # Load global: t
+ bnez a0, label_12 # Ensure not None
+ j error.None # Go to error handler
+label_12: # Not None
+ lw a0, 16(a0) # Get attribute: Tree.size
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 4 # Load integer literal 4
+ sw a0, -24(fp) # Push argument 6 from last.
+ li a0, 8 # Load integer literal 8
+ sw a0, -28(fp) # Push argument 5 from last.
+ li a0, 15 # Load integer literal 15
+ sw a0, -32(fp) # Push argument 4 from last.
+ li a0, 16 # Load integer literal 16
+ sw a0, -36(fp) # Push argument 3 from last.
+ li a0, 23 # Load integer literal 23
+ sw a0, -40(fp) # Push argument 2 from last.
+ li a0, 42 # Load integer literal 42
+ sw a0, -44(fp) # Push argument 1 from last.
+ li a0, 6 # Pass list length
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ bnez a0, label_13 # Ensure not None
+ j error.None # Go to error handler
+label_13: # Not None
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_14: # for-loop header
+ lw t1, -16(fp) # Pop stack slot 4
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_15 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $i, t1 # Assign global: i (using tmp register)
+ lw a0, $t # Load global: t
+ bnez a0, label_17 # Ensure not None
+ j error.None # Go to error handler
+label_17: # Not None
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $i # Load global: i
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -28(fp) # Peek stack slot 6
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 8(a1) # Load address of method: Tree.contains
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: Tree.contains
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ beqz a0, label_16 # Branch on false.
+ lw a0, $i # Load global: i
+ jal makeint # Box integer
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+label_16: # End of if-else statement
+ j label_14 # Loop back to header
+label_15: # for-loop footer
+ .equiv @..main.size, 48
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $TreeNode.insert
+$TreeNode.insert:
+ addi sp, sp, -@TreeNode.insert.size # Reserve space for stack frame.
+ sw ra, @TreeNode.insert.size-4(sp) # return address
+ sw fp, @TreeNode.insert.size-8(sp) # control link
+ addi fp, sp, @TreeNode.insert.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: TreeNode.insert.x
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: TreeNode.insert.self
+ bnez a0, label_22 # Ensure not None
+ j error.None # Go to error handler
+label_22: # Not None
+ lw a0, 12(a0) # Get attribute: TreeNode.value
+ lw t0, -12(fp) # Pop stack slot 3
+ bge t0, a0, label_21 # Branch on not <
+ lw a0, 4(fp) # Load var: TreeNode.insert.self
+ bnez a0, label_25 # Ensure not None
+ j error.None # Go to error handler
+label_25: # Not None
+ lw a0, 16(a0) # Get attribute: TreeNode.left
+ sw a0, -12(fp) # Push on stack slot 3
+ mv a0, zero # Load None
+ lw t0, -12(fp) # Pop stack slot 3
+ bne t0, a0, label_24 # Branch if unequal pointers
+ lw a0, 0(fp) # Load var: TreeNode.insert.x
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $makeNode # Invoke function: makeNode
+ addi sp, fp, -@TreeNode.insert.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: TreeNode.insert.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_26 # Ensure not None
+ j error.None # Go to error handler
+label_26: # Not None
+ sw a0, 16(a1) # Set attribute: TreeNode.left
+ li a0, 1 # Load boolean literal: true
+ j label_19 # Go to return
+ j label_23 # Then body complete; jump to end-if
+label_24: # Else body
+ lw a0, 4(fp) # Load var: TreeNode.insert.self
+ bnez a0, label_27 # Ensure not None
+ j error.None # Go to error handler
+label_27: # Not None
+ lw a0, 16(a0) # Get attribute: TreeNode.left
+ bnez a0, label_28 # Ensure not None
+ j error.None # Go to error handler
+label_28: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: TreeNode.insert.x
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: TreeNode.insert
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: TreeNode.insert
+ addi sp, fp, -@TreeNode.insert.size # Set SP to stack frame top.
+ j label_19 # Go to return
+label_23: # End of if-else statement
+ j label_20 # Then body complete; jump to end-if
+label_21: # Else body
+ lw a0, 0(fp) # Load var: TreeNode.insert.x
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: TreeNode.insert.self
+ bnez a0, label_30 # Ensure not None
+ j error.None # Go to error handler
+label_30: # Not None
+ lw a0, 12(a0) # Get attribute: TreeNode.value
+ lw t0, -12(fp) # Pop stack slot 3
+ bge a0, t0, label_29 # Branch on not >
+ lw a0, 4(fp) # Load var: TreeNode.insert.self
+ bnez a0, label_33 # Ensure not None
+ j error.None # Go to error handler
+label_33: # Not None
+ lw a0, 20(a0) # Get attribute: TreeNode.right
+ sw a0, -12(fp) # Push on stack slot 3
+ mv a0, zero # Load None
+ lw t0, -12(fp) # Pop stack slot 3
+ bne t0, a0, label_32 # Branch if unequal pointers
+ lw a0, 0(fp) # Load var: TreeNode.insert.x
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $makeNode # Invoke function: makeNode
+ addi sp, fp, -@TreeNode.insert.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: TreeNode.insert.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_34 # Ensure not None
+ j error.None # Go to error handler
+label_34: # Not None
+ sw a0, 20(a1) # Set attribute: TreeNode.right
+ li a0, 1 # Load boolean literal: true
+ j label_19 # Go to return
+ j label_31 # Then body complete; jump to end-if
+label_32: # Else body
+ lw a0, 4(fp) # Load var: TreeNode.insert.self
+ bnez a0, label_35 # Ensure not None
+ j error.None # Go to error handler
+label_35: # Not None
+ lw a0, 20(a0) # Get attribute: TreeNode.right
+ bnez a0, label_36 # Ensure not None
+ j error.None # Go to error handler
+label_36: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: TreeNode.insert.x
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: TreeNode.insert
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: TreeNode.insert
+ addi sp, fp, -@TreeNode.insert.size # Set SP to stack frame top.
+ j label_19 # Go to return
+label_31: # End of if-else statement
+label_29: # End of if-else statement
+label_20: # End of if-else statement
+ li a0, 0 # Load boolean literal: false
+ j label_19 # Go to return
+ mv a0, zero # Load None
+ j label_19 # Jump to function epilogue
+label_19: # Epilogue
+ .equiv @TreeNode.insert.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @TreeNode.insert.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $TreeNode.contains
+$TreeNode.contains:
+ addi sp, sp, -@TreeNode.contains.size # Reserve space for stack frame.
+ sw ra, @TreeNode.contains.size-4(sp) # return address
+ sw fp, @TreeNode.contains.size-8(sp) # control link
+ addi fp, sp, @TreeNode.contains.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: TreeNode.contains.x
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: TreeNode.contains.self
+ bnez a0, label_41 # Ensure not None
+ j error.None # Go to error handler
+label_41: # Not None
+ lw a0, 12(a0) # Get attribute: TreeNode.value
+ lw t0, -12(fp) # Pop stack slot 3
+ bge t0, a0, label_40 # Branch on not <
+ lw a0, 4(fp) # Load var: TreeNode.contains.self
+ bnez a0, label_44 # Ensure not None
+ j error.None # Go to error handler
+label_44: # Not None
+ lw a0, 16(a0) # Get attribute: TreeNode.left
+ sw a0, -12(fp) # Push on stack slot 3
+ mv a0, zero # Load None
+ lw t0, -12(fp) # Pop stack slot 3
+ bne t0, a0, label_43 # Branch if unequal pointers
+ li a0, 0 # Load boolean literal: false
+ j label_38 # Go to return
+ j label_42 # Then body complete; jump to end-if
+label_43: # Else body
+ lw a0, 4(fp) # Load var: TreeNode.contains.self
+ bnez a0, label_45 # Ensure not None
+ j error.None # Go to error handler
+label_45: # Not None
+ lw a0, 16(a0) # Get attribute: TreeNode.left
+ bnez a0, label_46 # Ensure not None
+ j error.None # Go to error handler
+label_46: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: TreeNode.contains.x
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 8(a1) # Load address of method: TreeNode.contains
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: TreeNode.contains
+ addi sp, fp, -@TreeNode.contains.size # Set SP to stack frame top.
+ j label_38 # Go to return
+label_42: # End of if-else statement
+ j label_39 # Then body complete; jump to end-if
+label_40: # Else body
+ lw a0, 0(fp) # Load var: TreeNode.contains.x
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: TreeNode.contains.self
+ bnez a0, label_49 # Ensure not None
+ j error.None # Go to error handler
+label_49: # Not None
+ lw a0, 12(a0) # Get attribute: TreeNode.value
+ lw t0, -12(fp) # Pop stack slot 3
+ bge a0, t0, label_48 # Branch on not >
+ lw a0, 4(fp) # Load var: TreeNode.contains.self
+ bnez a0, label_52 # Ensure not None
+ j error.None # Go to error handler
+label_52: # Not None
+ lw a0, 20(a0) # Get attribute: TreeNode.right
+ sw a0, -12(fp) # Push on stack slot 3
+ mv a0, zero # Load None
+ lw t0, -12(fp) # Pop stack slot 3
+ bne t0, a0, label_51 # Branch if unequal pointers
+ li a0, 0 # Load boolean literal: false
+ j label_38 # Go to return
+ j label_50 # Then body complete; jump to end-if
+label_51: # Else body
+ lw a0, 4(fp) # Load var: TreeNode.contains.self
+ bnez a0, label_53 # Ensure not None
+ j error.None # Go to error handler
+label_53: # Not None
+ lw a0, 20(a0) # Get attribute: TreeNode.right
+ bnez a0, label_54 # Ensure not None
+ j error.None # Go to error handler
+label_54: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: TreeNode.contains.x
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 8(a1) # Load address of method: TreeNode.contains
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: TreeNode.contains
+ addi sp, fp, -@TreeNode.contains.size # Set SP to stack frame top.
+ j label_38 # Go to return
+label_50: # End of if-else statement
+ j label_47 # Then body complete; jump to end-if
+label_48: # Else body
+ li a0, 1 # Load boolean literal: true
+ j label_38 # Go to return
+label_47: # End of if-else statement
+label_39: # End of if-else statement
+ mv a0, zero # Load None
+ j label_38 # Jump to function epilogue
+label_38: # Epilogue
+ .equiv @TreeNode.contains.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @TreeNode.contains.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $Tree.insert
+$Tree.insert:
+ addi sp, sp, -@Tree.insert.size # Reserve space for stack frame.
+ sw ra, @Tree.insert.size-4(sp) # return address
+ sw fp, @Tree.insert.size-8(sp) # control link
+ addi fp, sp, @Tree.insert.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: Tree.insert.self
+ bnez a0, label_59 # Ensure not None
+ j error.None # Go to error handler
+label_59: # Not None
+ lw a0, 12(a0) # Get attribute: Tree.root
+ sw a0, -12(fp) # Push on stack slot 3
+ mv a0, zero # Load None
+ lw t0, -12(fp) # Pop stack slot 3
+ bne t0, a0, label_58 # Branch if unequal pointers
+ lw a0, 0(fp) # Load var: Tree.insert.x
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $makeNode # Invoke function: makeNode
+ addi sp, fp, -@Tree.insert.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: Tree.insert.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_60 # Ensure not None
+ j error.None # Go to error handler
+label_60: # Not None
+ sw a0, 12(a1) # Set attribute: Tree.root
+ li a0, 1 # Load integer literal 1
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: Tree.insert.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_61 # Ensure not None
+ j error.None # Go to error handler
+label_61: # Not None
+ sw a0, 16(a1) # Set attribute: Tree.size
+ j label_57 # Then body complete; jump to end-if
+label_58: # Else body
+ lw a0, 4(fp) # Load var: Tree.insert.self
+ bnez a0, label_63 # Ensure not None
+ j error.None # Go to error handler
+label_63: # Not None
+ lw a0, 12(a0) # Get attribute: Tree.root
+ bnez a0, label_64 # Ensure not None
+ j error.None # Go to error handler
+label_64: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: Tree.insert.x
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: TreeNode.insert
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: TreeNode.insert
+ addi sp, fp, -@Tree.insert.size # Set SP to stack frame top.
+ beqz a0, label_62 # Branch on false.
+ lw a0, 4(fp) # Load var: Tree.insert.self
+ bnez a0, label_65 # Ensure not None
+ j error.None # Go to error handler
+label_65: # Not None
+ lw a0, 16(a0) # Get attribute: Tree.size
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 4(fp) # Load var: Tree.insert.self
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_66 # Ensure not None
+ j error.None # Go to error handler
+label_66: # Not None
+ sw a0, 16(a1) # Set attribute: Tree.size
+label_62: # End of if-else statement
+label_57: # End of if-else statement
+ mv a0, zero # Load None
+ j label_56 # Jump to function epilogue
+label_56: # Epilogue
+ .equiv @Tree.insert.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @Tree.insert.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $Tree.contains
+$Tree.contains:
+ addi sp, sp, -@Tree.contains.size # Reserve space for stack frame.
+ sw ra, @Tree.contains.size-4(sp) # return address
+ sw fp, @Tree.contains.size-8(sp) # control link
+ addi fp, sp, @Tree.contains.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: Tree.contains.self
+ bnez a0, label_71 # Ensure not None
+ j error.None # Go to error handler
+label_71: # Not None
+ lw a0, 12(a0) # Get attribute: Tree.root
+ sw a0, -12(fp) # Push on stack slot 3
+ mv a0, zero # Load None
+ lw t0, -12(fp) # Pop stack slot 3
+ bne t0, a0, label_70 # Branch if unequal pointers
+ li a0, 0 # Load boolean literal: false
+ j label_68 # Go to return
+ j label_69 # Then body complete; jump to end-if
+label_70: # Else body
+ lw a0, 4(fp) # Load var: Tree.contains.self
+ bnez a0, label_72 # Ensure not None
+ j error.None # Go to error handler
+label_72: # Not None
+ lw a0, 12(a0) # Get attribute: Tree.root
+ bnez a0, label_73 # Ensure not None
+ j error.None # Go to error handler
+label_73: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: Tree.contains.x
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 8(a1) # Load address of method: TreeNode.contains
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: TreeNode.contains
+ addi sp, fp, -@Tree.contains.size # Set SP to stack frame top.
+ j label_68 # Go to return
+label_69: # End of if-else statement
+ mv a0, zero # Load None
+ j label_68 # Jump to function epilogue
+label_68: # Epilogue
+ .equiv @Tree.contains.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @Tree.contains.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $makeNode
+$makeNode:
+ addi sp, sp, -@makeNode.size # Reserve space for stack frame.
+ sw ra, @makeNode.size-4(sp) # return address
+ sw fp, @makeNode.size-8(sp) # control link
+ addi fp, sp, @makeNode.size # New fp is at old SP.
+ mv a0, zero # Load None
+ sw a0, -12(fp) # local variable b
+ la a0, $TreeNode$prototype # Load pointer to prototype of: TreeNode
+ jal alloc # Allocate new object in A0
+ sw a0, -16(fp) # Push on stack slot 4
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: TreeNode.__init__
+ jalr a1 # Invoke method: TreeNode.__init__
+ addi sp, fp, -@makeNode.size # Set SP to stack frame top.
+ lw a0, -16(fp) # Pop stack slot 4
+ sw a0, -12(fp) # Assign var: makeNode.b
+ lw a0, 0(fp) # Load var: makeNode.x
+ sw a0, -16(fp) # Push on stack slot 4
+ lw a0, -12(fp) # Load var: makeNode.b
+ mv a1, a0 # Move object
+ lw a0, -16(fp) # Pop stack slot 4
+ bnez a1, label_76 # Ensure not None
+ j error.None # Go to error handler
+label_76: # Not None
+ sw a0, 12(a1) # Set attribute: TreeNode.value
+ lw a0, -12(fp) # Load var: makeNode.b
+ j label_75 # Go to return
+ mv a0, zero # Load None
+ j label_75 # Jump to function epilogue
+label_75: # Epilogue
+ .equiv @makeNode.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @makeNode.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/call.py.ast.typed.s b/src/test/data/pa3/sample/call.py.ast.typed.s
new file mode 100644
index 0000000..bd6d256
--- /dev/null
+++ b/src/test/data/pa3/sample/call.py.ast.typed.s
@@ -0,0 +1,794 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $f # Invoke function: f
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $f
+$f:
+ addi sp, sp, -@f.size # Reserve space for stack frame.
+ sw ra, @f.size-4(sp) # return address
+ sw fp, @f.size-8(sp) # control link
+ addi fp, sp, @f.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@f.size # Set SP to stack frame top.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $g # Invoke function: g
+ addi sp, fp, -@f.size # Set SP to stack frame top.
+ la a0, const_6 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@f.size # Set SP to stack frame top.
+ li a0, 42 # Load integer literal 42
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @f.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @f.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $g
+$g:
+ addi sp, sp, -@g.size # Reserve space for stack frame.
+ sw ra, @g.size-4(sp) # return address
+ sw fp, @g.size-8(sp) # control link
+ addi fp, sp, @g.size # New fp is at old SP.
+ la a0, const_7 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@g.size # Set SP to stack frame top.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $h # Invoke function: h
+ addi sp, fp, -@g.size # Set SP to stack frame top.
+ la a0, const_8 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@g.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_4 # Jump to function epilogue
+label_4: # Epilogue
+ .equiv @g.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @g.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $h
+$h:
+ addi sp, sp, -@h.size # Reserve space for stack frame.
+ sw ra, @h.size-4(sp) # return address
+ sw fp, @h.size-8(sp) # control link
+ addi fp, sp, @h.size # New fp is at old SP.
+ la a0, const_9 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@h.size # Set SP to stack frame top.
+ la a0, const_10 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@h.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @h.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @h.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_11 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_12 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_13 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_14 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "end g" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 7 # Constant value of attribute: __len__
+ .string "start h" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "end h" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 7 # Constant value of attribute: __len__
+ .string "start g" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 7 # Constant value of attribute: __len__
+ .string "start f" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "end f" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_13
+const_13:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_14
+const_14:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_12
+const_12:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/call_with_args.py.ast.typed.s b/src/test/data/pa3/sample/call_with_args.py.ast.typed.s
new file mode 100644
index 0000000..fb7e78c
--- /dev/null
+++ b/src/test/data/pa3/sample/call_with_args.py.ast.typed.s
@@ -0,0 +1,806 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 4 # Load integer literal 4
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $f # Invoke function: f
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $f
+$f:
+ addi sp, sp, -@f.size # Reserve space for stack frame.
+ sw ra, @f.size-4(sp) # return address
+ sw fp, @f.size-8(sp) # control link
+ addi fp, sp, @f.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@f.size # Set SP to stack frame top.
+ lw a0, 0(fp) # Load var: f.x
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@f.size # Set SP to stack frame top.
+ li a0, 1 # Load integer literal 1
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: f.x
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $g # Invoke function: g
+ addi sp, fp, -@f.size # Set SP to stack frame top.
+ la a0, const_6 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@f.size # Set SP to stack frame top.
+ lw a0, 0(fp) # Load var: f.x
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @f.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @f.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $g
+$g:
+ addi sp, sp, -@g.size # Reserve space for stack frame.
+ sw ra, @g.size-4(sp) # return address
+ sw fp, @g.size-8(sp) # control link
+ addi fp, sp, @g.size # New fp is at old SP.
+ la a0, const_7 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@g.size # Set SP to stack frame top.
+ lw a0, 4(fp) # Load var: g.y
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@g.size # Set SP to stack frame top.
+ lw a0, 0(fp) # Load var: g.z
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@g.size # Set SP to stack frame top.
+ la a0, const_8 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $h # Invoke function: h
+ addi sp, fp, -@g.size # Set SP to stack frame top.
+ la a0, const_9 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@g.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_4 # Jump to function epilogue
+label_4: # Epilogue
+ .equiv @g.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @g.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $h
+$h:
+ addi sp, sp, -@h.size # Reserve space for stack frame.
+ sw ra, @h.size-4(sp) # return address
+ sw fp, @h.size-8(sp) # control link
+ addi fp, sp, @h.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: h.msg
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@h.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @h.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @h.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_10 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_11 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_12 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_13 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "end g" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_12
+const_12:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 7 # Constant value of attribute: __len__
+ .string "start g" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 7 # Constant value of attribute: __len__
+ .string "start f" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "end f" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_13
+const_13:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "h" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/error_div_zero.py.ast.typed.s b/src/test/data/pa3/sample/error_div_zero.py.ast.typed.s
new file mode 100644
index 0000000..d7648d5
--- /dev/null
+++ b/src/test/data/pa3/sample/error_div_zero.py.ast.typed.s
@@ -0,0 +1,673 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 42 # Load integer literal 42
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load integer literal 0
+ lw t0, -20(fp) # Pop stack slot 5
+ bnez a0, label_1 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_1: # Divisor is non-zero
+ xor t2, t0, a0 # Check for same sign
+ bltz t2, label_3 # If !=, need to adjust left operand
+ div a0, t0, a0 # Operator //
+ j label_2
+label_3: # Operands have differing signs
+ slt t2, zero, a0 # tmp = 1 if right > 0 else 0
+ add t2, t2, t2 # tmp *= 2
+ addi t2, t2, -1 # tmp = 1 if right>=0 else -1
+ add t2, t0, t2 # Adjust left operand
+ div t2, t2, a0 # Adjusted division, toward 0
+ addi a0, t2, -1 # Complete division when signs !=
+label_2: # End of //
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/error_invalid_print.py.ast.typed.s b/src/test/data/pa3/sample/error_invalid_print.py.ast.typed.s
new file mode 100644
index 0000000..8bdc6b2
--- /dev/null
+++ b/src/test/data/pa3/sample/error_invalid_print.py.ast.typed.s
@@ -0,0 +1,654 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ mv a0, zero # Load None
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/error_mod_zero.py.ast.typed.s b/src/test/data/pa3/sample/error_mod_zero.py.ast.typed.s
new file mode 100644
index 0000000..5d91f8e
--- /dev/null
+++ b/src/test/data/pa3/sample/error_mod_zero.py.ast.typed.s
@@ -0,0 +1,670 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 42 # Load integer literal 42
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load integer literal 0
+ lw t0, -20(fp) # Pop stack slot 5
+ bnez a0, label_1 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_1: # Divisor is non-zero
+ rem t2, t0, a0 # Operator rem
+ beqz t2, label_2 # If no remainder, no adjustment
+ xor t3, t2, a0 # Check for differing signs.
+ bgez t3, label_2 # Don't adjust if signs equal.
+ add a0, t2, a0 # Adjust
+ j label_3
+label_2: # Store result
+ mv a0, t2
+label_3: # End of %
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/expr_if.py.ast.typed.s b/src/test/data/pa3/sample/expr_if.py.ast.typed.s
new file mode 100644
index 0000000..52baf16
--- /dev/null
+++ b/src/test/data/pa3/sample/expr_if.py.ast.typed.s
@@ -0,0 +1,674 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 3 # Load integer literal 3
+ mv a0, a0 # Set result from 'then' expression
+ j label_2
+label_1: # Else part
+ li a0, 4 # Load integer literal 4
+ mv a0, a0 # Set result from 'else' expression
+label_2: # End of if-else expression
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_3 # Branch on false.
+ li a0, 3 # Load integer literal 3
+ mv a0, a0 # Set result from 'then' expression
+ j label_4
+label_3: # Else part
+ li a0, 4 # Load integer literal 4
+ mv a0, a0 # Set result from 'else' expression
+label_4: # End of if-else expression
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/id_global.py.ast.typed.s b/src/test/data/pa3/sample/id_global.py.ast.typed.s
new file mode 100644
index 0000000..ffc6393
--- /dev/null
+++ b/src/test/data/pa3/sample/id_global.py.ast.typed.s
@@ -0,0 +1,659 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 42 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/id_local.py.ast.typed.s b/src/test/data/pa3/sample/id_local.py.ast.typed.s
new file mode 100644
index 0000000..07fd798
--- /dev/null
+++ b/src/test/data/pa3/sample/id_local.py.ast.typed.s
@@ -0,0 +1,676 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $f # Invoke function: f
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $f
+$f:
+ addi sp, sp, -@f.size # Reserve space for stack frame.
+ sw ra, @f.size-4(sp) # return address
+ sw fp, @f.size-8(sp) # control link
+ addi fp, sp, @f.size # New fp is at old SP.
+ li a0, 1 # Load integer literal 1
+ sw a0, -12(fp) # local variable x
+ lw a0, -12(fp) # Load var: f.x
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @f.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @f.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/input.py.ast.typed.s b/src/test/data/pa3/sample/input.py.ast.typed.s
new file mode 100644
index 0000000..e2a03c0
--- /dev/null
+++ b/src/test/data/pa3/sample/input.py.ast.typed.s
@@ -0,0 +1,687 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $s
+$s:
+ .word const_2 # Initial value of global var: s
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $input # Invoke function: input
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $s, t0 # Assign global: s (using tmp register)
+ j label_2 # Jump to loop test
+label_1: # Top of while loop
+ lw a0, $s # Load global: s
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $input # Invoke function: input
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $s, t0 # Assign global: s (using tmp register)
+label_2: # Test loop condition
+ lw a0, $s # Load global: s
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 0 # Load integer literal 0
+ lw t0, -12(fp) # Pop stack slot 3
+ blt a0, t0, label_1 # Branch on >
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_4 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_5 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/len_invalid_1.py.ast.typed.s b/src/test/data/pa3/sample/len_invalid_1.py.ast.typed.s
new file mode 100644
index 0000000..70b7d40
--- /dev/null
+++ b/src/test/data/pa3/sample/len_invalid_1.py.ast.typed.s
@@ -0,0 +1,663 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/len_invalid_2.py.ast.typed.s b/src/test/data/pa3/sample/len_invalid_2.py.ast.typed.s
new file mode 100644
index 0000000..2e5e6a8
--- /dev/null
+++ b/src/test/data/pa3/sample/len_invalid_2.py.ast.typed.s
@@ -0,0 +1,664 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 1 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_concat.py.ast.typed.s b/src/test/data/pa3/sample/list_concat.py.ast.typed.s
new file mode 100644
index 0000000..63e6373
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat.py.ast.typed.s
@@ -0,0 +1,751 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $z
+$z:
+ .word 0 # Initial value of global var: z
+
+.globl $i
+$i:
+ .word 0 # Initial value of global var: i
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push argument 1 from last.
+ li a0, 4 # Load integer literal 4
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 5 # Load integer literal 5
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 6 # Load integer literal 6
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $concat # Invoke function: concat
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $z, t0 # Assign global: z (using tmp register)
+ j label_2 # Jump to loop test
+label_1: # Top of while loop
+ lw a0, $z # Load global: z
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $i # Load global: i
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_4 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_4: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, $i, t0 # Assign global: i (using tmp register)
+label_2: # Test loop condition
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $z # Load global: z
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw t0, -12(fp) # Pop stack slot 3
+ blt t0, a0, label_1 # Branch on <
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $concat
+$concat:
+ addi sp, sp, -@concat.size # Reserve space for stack frame.
+ sw ra, @concat.size-4(sp) # return address
+ sw fp, @concat.size-8(sp) # control link
+ addi fp, sp, @concat.size # New fp is at old SP.
+ la t0, noconv # Identity conversion
+ sw t0, -20(fp) # Push argument 3 from last.
+ la t0, noconv # Identity conversion
+ sw t0, -24(fp) # Push argument 2 from last.
+ lw a0, 4(fp) # Load var: concat.x
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: concat.y
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal concat # Call runtime concatenation routine.
+ addi sp, fp, -@concat.size # Set SP to stack frame top.
+ j label_6 # Go to return
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @concat.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @concat.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_concat_2.py.ast.typed.s b/src/test/data/pa3/sample/list_concat_2.py.ast.typed.s
new file mode 100644
index 0000000..b358cfe
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat_2.py.ast.typed.s
@@ -0,0 +1,748 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $z
+$z:
+ .word 0 # Initial value of global var: z
+
+.globl $i
+$i:
+ .word 0 # Initial value of global var: i
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la t0, noconv # Identity conversion
+ sw t0, -20(fp) # Push argument 3 from last.
+ la t0, noconv # Identity conversion
+ sw t0, -24(fp) # Push argument 2 from last.
+ la t0, noconv # Identity conversion
+ sw t0, -36(fp) # Push argument 3 from last.
+ la t0, noconv # Identity conversion
+ sw t0, -40(fp) # Push argument 2 from last.
+ li a0, 1 # Load integer literal 1
+ sw a0, -52(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -56(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -60(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -64(fp) # Push argument 0 from last.
+ addi sp, fp, -64 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -44(fp) # Push argument 1 from last.
+ li a0, 4 # Load integer literal 4
+ sw a0, -52(fp) # Push argument 3 from last.
+ li a0, 5 # Load integer literal 5
+ sw a0, -56(fp) # Push argument 2 from last.
+ li a0, 6 # Load integer literal 6
+ sw a0, -60(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -64(fp) # Push argument 0 from last.
+ addi sp, fp, -64 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal concat # Call runtime concatenation routine.
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 7 # Load integer literal 7
+ sw a0, -36(fp) # Push argument 3 from last.
+ li a0, 8 # Load integer literal 8
+ sw a0, -40(fp) # Push argument 2 from last.
+ li a0, 9 # Load integer literal 9
+ sw a0, -44(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal concat # Call runtime concatenation routine.
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $z, t0 # Assign global: z (using tmp register)
+ j label_2 # Jump to loop test
+label_1: # Top of while loop
+ lw a0, $z # Load global: z
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $i # Load global: i
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_4 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_4: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, $i, t0 # Assign global: i (using tmp register)
+label_2: # Test loop condition
+ lw a0, $i # Load global: i
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $z # Load global: z
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw t0, -12(fp) # Pop stack slot 3
+ blt t0, a0, label_1 # Branch on <
+ .equiv @..main.size, 64
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_concat_none.py.ast.typed.s b/src/test/data/pa3/sample/list_concat_none.py.ast.typed.s
new file mode 100644
index 0000000..42391db
--- /dev/null
+++ b/src/test/data/pa3/sample/list_concat_none.py.ast.typed.s
@@ -0,0 +1,677 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.globl $y
+$y:
+ .word 0 # Initial value of global var: y
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la t0, noconv # Identity conversion
+ sw t0, -36(fp) # Push argument 3 from last.
+ la t0, noconv # Identity conversion
+ sw t0, -40(fp) # Push argument 2 from last.
+ lw a0, $x # Load global: x
+ sw a0, -44(fp) # Push argument 1 from last.
+ lw a0, $y # Load global: y
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal concat # Call runtime concatenation routine.
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 48
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_get_element.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element.py.ast.typed.s
new file mode 100644
index 0000000..5e59a14
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element.py.ast.typed.s
@@ -0,0 +1,728 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load integer literal 0
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load integer literal 1
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_4 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_4: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 2 # Load integer literal 2
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_5 # Ensure not None
+ j error.None # Go to error handler
+label_5: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_6 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_6: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed.s
new file mode 100644
index 0000000..4b94b83
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_complex.py.ast.typed.s
@@ -0,0 +1,738 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $next
+$next:
+ .word 0 # Initial value of global var: next
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $make_list # Invoke function: make_list
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -20(fp) # Push on stack slot 5
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $next_int # Invoke function: next_int
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -24(fp) # Push on stack slot 6
+ li a0, 3 # Load integer literal 3
+ lw t0, -24(fp) # Pop stack slot 6
+ sub a0, t0, a0 # Operator -
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $next_int
+$next_int:
+ addi sp, sp, -@next_int.size # Reserve space for stack frame.
+ sw ra, @next_int.size-4(sp) # return address
+ sw fp, @next_int.size-8(sp) # control link
+ addi fp, sp, @next_int.size # New fp is at old SP.
+ lw a0, $next # Load global: next
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, $next, t0 # Assign global: next (using tmp register)
+ lw a0, $next # Load global: next
+ j label_4 # Go to return
+ mv a0, zero # Load None
+ j label_4 # Jump to function epilogue
+label_4: # Epilogue
+ .equiv @next_int.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @next_int.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $make_list
+$make_list:
+ addi sp, sp, -@make_list.size # Reserve space for stack frame.
+ sw ra, @make_list.size-4(sp) # return address
+ sw fp, @make_list.size-8(sp) # control link
+ addi fp, sp, @make_list.size # New fp is at old SP.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $next_int # Invoke function: next_int
+ addi sp, fp, -@make_list.size # Set SP to stack frame top.
+ sw a0, -20(fp) # Push argument 3 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $next_int # Invoke function: next_int
+ addi sp, fp, -@make_list.size # Set SP to stack frame top.
+ sw a0, -24(fp) # Push argument 2 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $next_int # Invoke function: next_int
+ addi sp, fp, -@make_list.size # Set SP to stack frame top.
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@make_list.size # Set SP to stack frame top.
+ j label_6 # Go to return
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @make_list.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @make_list.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_get_element_none.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element_none.py.ast.typed.s
new file mode 100644
index 0000000..9ae5241
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_none.py.ast.typed.s
@@ -0,0 +1,674 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load integer literal 0
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed.s
new file mode 100644
index 0000000..56fd249
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_1.py.ast.typed.s
@@ -0,0 +1,687 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load integer literal 1
+ sub a0, zero, a0 # Unary negation
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed.s
new file mode 100644
index 0000000..963102d
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_2.py.ast.typed.s
@@ -0,0 +1,686 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 3 # Load integer literal 3
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed.s b/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed.s
new file mode 100644
index 0000000..c22d09e
--- /dev/null
+++ b/src/test/data/pa3/sample/list_get_element_oob_3.py.ast.typed.s
@@ -0,0 +1,680 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 0 # Pass list length
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load integer literal 0
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_len.py.ast.typed.s b/src/test/data/pa3/sample/list_len.py.ast.typed.s
new file mode 100644
index 0000000..aa6145c
--- /dev/null
+++ b/src/test/data/pa3/sample/list_len.py.ast.typed.s
@@ -0,0 +1,675 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_len_empty.py.ast.typed.s b/src/test/data/pa3/sample/list_len_empty.py.ast.typed.s
new file mode 100644
index 0000000..4d693cf
--- /dev/null
+++ b/src/test/data/pa3/sample/list_len_empty.py.ast.typed.s
@@ -0,0 +1,669 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 0 # Pass list length
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_set_element.py.ast.typed.s b/src/test/data/pa3/sample/list_set_element.py.ast.typed.s
new file mode 100644
index 0000000..608c5d8
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element.py.ast.typed.s
@@ -0,0 +1,785 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ li a0, 4 # Load integer literal 4
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $x # Load global: x
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 0 # Load integer literal 0
+ lw t0, -16(fp) # Pop stack slot 4
+ lw t1, -12(fp) # Pop stack slot 3
+ bnez t0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t2, 12(t0) # Load attribute: __len__
+ bltu a0, t2, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul a0, a0, t2 # Compute list element offset in bytes
+ add a0, t0, a0 # Pointer to list element
+ sw t1, 0(a0) # Set list element
+ li a0, 5 # Load integer literal 5
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $x # Load global: x
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 1 # Load integer literal 1
+ lw t0, -16(fp) # Pop stack slot 4
+ lw t1, -12(fp) # Pop stack slot 3
+ bnez t0, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ lw t2, 12(t0) # Load attribute: __len__
+ bltu a0, t2, label_4 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_4: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul a0, a0, t2 # Compute list element offset in bytes
+ add a0, t0, a0 # Pointer to list element
+ sw t1, 0(a0) # Set list element
+ li a0, 6 # Load integer literal 6
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $x # Load global: x
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 2 # Load integer literal 2
+ lw t0, -16(fp) # Pop stack slot 4
+ lw t1, -12(fp) # Pop stack slot 3
+ bnez t0, label_5 # Ensure not None
+ j error.None # Go to error handler
+label_5: # Not None
+ lw t2, 12(t0) # Load attribute: __len__
+ bltu a0, t2, label_6 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_6: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul a0, a0, t2 # Compute list element offset in bytes
+ add a0, t0, a0 # Pointer to list element
+ sw t1, 0(a0) # Set list element
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load integer literal 0
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_7 # Ensure not None
+ j error.None # Go to error handler
+label_7: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_8 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_8: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load integer literal 1
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_9 # Ensure not None
+ j error.None # Go to error handler
+label_9: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_10 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_10: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 2 # Load integer literal 2
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_11 # Ensure not None
+ j error.None # Go to error handler
+label_11: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_12 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_12: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_set_element_none.py.ast.typed.s b/src/test/data/pa3/sample/list_set_element_none.py.ast.typed.s
new file mode 100644
index 0000000..dc925b0
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_none.py.ast.typed.s
@@ -0,0 +1,672 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $x # Load global: x
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 0 # Load integer literal 0
+ lw t0, -16(fp) # Pop stack slot 4
+ lw t1, -12(fp) # Pop stack slot 3
+ bnez t0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t2, 12(t0) # Load attribute: __len__
+ bltu a0, t2, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul a0, a0, t2 # Compute list element offset in bytes
+ add a0, t0, a0 # Pointer to list element
+ sw t1, 0(a0) # Set list element
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed.s b/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed.s
new file mode 100644
index 0000000..ae9e3af
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_1.py.ast.typed.s
@@ -0,0 +1,748 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ li a0, 4 # Load integer literal 4
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $x # Load global: x
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 1 # Load integer literal 1
+ sub a0, zero, a0 # Unary negation
+ lw t0, -16(fp) # Pop stack slot 4
+ lw t1, -12(fp) # Pop stack slot 3
+ bnez t0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t2, 12(t0) # Load attribute: __len__
+ bltu a0, t2, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul a0, a0, t2 # Compute list element offset in bytes
+ add a0, t0, a0 # Pointer to list element
+ sw t1, 0(a0) # Set list element
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load integer literal 0
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_4 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_4: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load integer literal 1
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_5 # Ensure not None
+ j error.None # Go to error handler
+label_5: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_6 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_6: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 2 # Load integer literal 2
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_7 # Ensure not None
+ j error.None # Go to error handler
+label_7: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_8 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_8: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed.s b/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed.s
new file mode 100644
index 0000000..6745567
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_2.py.ast.typed.s
@@ -0,0 +1,747 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ li a0, 4 # Load integer literal 4
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $x # Load global: x
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 4 # Load integer literal 4
+ lw t0, -16(fp) # Pop stack slot 4
+ lw t1, -12(fp) # Pop stack slot 3
+ bnez t0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t2, 12(t0) # Load attribute: __len__
+ bltu a0, t2, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul a0, a0, t2 # Compute list element offset in bytes
+ add a0, t0, a0 # Pointer to list element
+ sw t1, 0(a0) # Set list element
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load integer literal 0
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_4 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_4: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load integer literal 1
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_5 # Ensure not None
+ j error.None # Go to error handler
+label_5: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_6 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_6: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 2 # Load integer literal 2
+ lw a1, -20(fp) # Pop stack slot 5
+ bnez a1, label_7 # Ensure not None
+ j error.None # Go to error handler
+label_7: # Not None
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_8 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_8: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t0, 4 # Word size in bytes
+ mul a0, a0, t0 # Compute list element offset in bytes
+ add a0, a1, a0 # Pointer to list element
+ lw a0, 0(a0) # Get list element
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed.s b/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed.s
new file mode 100644
index 0000000..b72f4ec
--- /dev/null
+++ b/src/test/data/pa3/sample/list_set_element_oob_3.py.ast.typed.s
@@ -0,0 +1,678 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 0 # Pass list length
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ li a0, 4 # Load integer literal 4
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $x # Load global: x
+ sw a0, -16(fp) # Push on stack slot 4
+ li a0, 0 # Load integer literal 0
+ lw t0, -16(fp) # Pop stack slot 4
+ lw t1, -12(fp) # Pop stack slot 3
+ bnez t0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw t2, 12(t0) # Load attribute: __len__
+ bltu a0, t2, label_2 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_2: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul a0, a0, t2 # Compute list element offset in bytes
+ add a0, t0, a0 # Pointer to list element
+ sw t1, 0(a0) # Set list element
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/literal_bool.py.ast.typed.s b/src/test/data/pa3/sample/literal_bool.py.ast.typed.s
new file mode 100644
index 0000000..4fe0129
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_bool.py.ast.typed.s
@@ -0,0 +1,661 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load boolean literal: true
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 0 # Load boolean literal: false
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/literal_int.py.ast.typed.s b/src/test/data/pa3/sample/literal_int.py.ast.typed.s
new file mode 100644
index 0000000..1d9ab5b
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_int.py.ast.typed.s
@@ -0,0 +1,661 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 42 # Load integer literal 42
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 65999 # Load integer literal 65999
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/literal_str.py.ast.typed.s b/src/test/data/pa3/sample/literal_str.py.ast.typed.s
new file mode 100644
index 0000000..c47f99c
--- /dev/null
+++ b/src/test/data/pa3/sample/literal_str.py.ast.typed.s
@@ -0,0 +1,663 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, const_2 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_4 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_5 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 7 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 11 # Constant value of attribute: __len__
+ .string "Hello World" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/nested.py.ast.typed.s b/src/test/data/pa3/sample/nested.py.ast.typed.s
new file mode 100644
index 0000000..a21c539
--- /dev/null
+++ b/src/test/data/pa3/sample/nested.py.ast.typed.s
@@ -0,0 +1,728 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $g
+$g:
+ .word 1 # Initial value of global var: g
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $g # Load global: g
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $foo # Invoke function: foo
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $foo.bar.baz
+$foo.bar.baz:
+ addi sp, sp, -@foo.bar.baz.size # Reserve space for stack frame.
+ sw ra, @foo.bar.baz.size-4(sp) # return address
+ sw fp, @foo.bar.baz.size-8(sp) # control link
+ addi fp, sp, @foo.bar.baz.size # New fp is at old SP.
+ lw t0, 0(fp) # Load static link from foo.bar.baz to foo.bar
+ lw t0, 0(t0) # Load static link from foo.bar to foo
+ lw a0, -12(t0) # Load var: foo.y
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @foo.bar.baz.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @foo.bar.baz.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $foo.bar
+$foo.bar:
+ addi sp, sp, -@foo.bar.size # Reserve space for stack frame.
+ sw ra, @foo.bar.size-4(sp) # return address
+ sw fp, @foo.bar.size-8(sp) # control link
+ addi fp, sp, @foo.bar.size # New fp is at old SP.
+ li a0, 3 # Load integer literal 3
+ sw a0, -12(fp) # local variable z
+ mv t0, fp # Get static link to foo.bar
+ sw t0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $foo.bar.baz # Invoke function: foo.bar.baz
+ addi sp, fp, -@foo.bar.size # Set SP to stack frame top.
+ j label_4 # Go to return
+ mv a0, zero # Load None
+ j label_4 # Jump to function epilogue
+label_4: # Epilogue
+ .equiv @foo.bar.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @foo.bar.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $foo
+$foo:
+ addi sp, sp, -@foo.size # Reserve space for stack frame.
+ sw ra, @foo.size-4(sp) # return address
+ sw fp, @foo.size-8(sp) # control link
+ addi fp, sp, @foo.size # New fp is at old SP.
+ li a0, 2 # Load integer literal 2
+ sw a0, -12(fp) # local variable y
+ mv t0, fp # Get static link to foo
+ sw t0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $foo.bar # Invoke function: foo.bar
+ addi sp, fp, -@foo.size # Set SP to stack frame top.
+ j label_6 # Go to return
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @foo.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @foo.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/nested2.py.ast.typed.s b/src/test/data/pa3/sample/nested2.py.ast.typed.s
new file mode 100644
index 0000000..ba0c2a0
--- /dev/null
+++ b/src/test/data/pa3/sample/nested2.py.ast.typed.s
@@ -0,0 +1,753 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $g
+$g:
+ .word 1 # Initial value of global var: g
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $g # Load global: g
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $foo # Invoke function: foo
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $foo.bar.baz
+$foo.bar.baz:
+ addi sp, sp, -@foo.bar.baz.size # Reserve space for stack frame.
+ sw ra, @foo.bar.baz.size-4(sp) # return address
+ sw fp, @foo.bar.baz.size-8(sp) # control link
+ addi fp, sp, @foo.bar.baz.size # New fp is at old SP.
+ mv t0, fp # Get static link to foo.bar.baz
+ lw t0, 0(t0) # Get static link to foo.bar
+ lw t0, 0(t0) # Get static link to foo
+ sw t0, -12(fp) # Push argument 1 from last.
+ lw t0, 0(fp) # Load static link from foo.bar.baz to foo.bar
+ lw t0, 0(t0) # Load static link from foo.bar to foo
+ lw a0, -12(t0) # Load var: foo.y
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $foo.qux # Invoke function: foo.qux
+ addi sp, fp, -@foo.bar.baz.size # Set SP to stack frame top.
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @foo.bar.baz.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @foo.bar.baz.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $foo.bar
+$foo.bar:
+ addi sp, sp, -@foo.bar.size # Reserve space for stack frame.
+ sw ra, @foo.bar.size-4(sp) # return address
+ sw fp, @foo.bar.size-8(sp) # control link
+ addi fp, sp, @foo.bar.size # New fp is at old SP.
+ li a0, 3 # Load integer literal 3
+ sw a0, -12(fp) # local variable z
+ mv t0, fp # Get static link to foo.bar
+ sw t0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $foo.bar.baz # Invoke function: foo.bar.baz
+ addi sp, fp, -@foo.bar.size # Set SP to stack frame top.
+ j label_4 # Go to return
+ mv a0, zero # Load None
+ j label_4 # Jump to function epilogue
+label_4: # Epilogue
+ .equiv @foo.bar.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @foo.bar.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $foo.qux
+$foo.qux:
+ addi sp, sp, -@foo.qux.size # Reserve space for stack frame.
+ sw ra, @foo.qux.size-4(sp) # return address
+ sw fp, @foo.qux.size-8(sp) # control link
+ addi fp, sp, @foo.qux.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: foo.qux.p
+ j label_6 # Go to return
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @foo.qux.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @foo.qux.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $foo
+$foo:
+ addi sp, sp, -@foo.size # Reserve space for stack frame.
+ sw ra, @foo.size-4(sp) # return address
+ sw fp, @foo.size-8(sp) # control link
+ addi fp, sp, @foo.size # New fp is at old SP.
+ li a0, 2 # Load integer literal 2
+ sw a0, -12(fp) # local variable y
+ mv t0, fp # Get static link to foo
+ sw t0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $foo.bar # Invoke function: foo.bar
+ addi sp, fp, -@foo.size # Set SP to stack frame top.
+ j label_8 # Go to return
+ mv a0, zero # Load None
+ j label_8 # Jump to function epilogue
+label_8: # Epilogue
+ .equiv @foo.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @foo.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_attr_get.py.ast.typed.s b/src/test/data/pa3/sample/object_attr_get.py.ast.typed.s
new file mode 100644
index 0000000..1b1201a
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_get.py.ast.typed.s
@@ -0,0 +1,755 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+
+.globl $a
+$a:
+ .word 0 # Initial value of global var: a
+
+.globl $b
+$b:
+ .word 0 # Initial value of global var: b
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, $a, t0 # Assign global: a (using tmp register)
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, $b, t0 # Assign global: b (using tmp register)
+ lw a0, $a # Load global: a
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw a0, 12(a0) # Get attribute: A.a
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ bnez a0, label_2 # Ensure not None
+ j error.None # Go to error handler
+label_2: # Not None
+ lw a0, 12(a0) # Get attribute: B.a
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ bnez a0, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ lw a0, 16(a0) # Get attribute: B.b
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_5 # Jump to function epilogue
+label_5: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed.s b/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed.s
new file mode 100644
index 0000000..6936a0b
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_get_none.py.ast.typed.s
@@ -0,0 +1,752 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+
+.globl $a
+$a:
+ .word 0 # Initial value of global var: a
+
+.globl $b
+$b:
+ .word 0 # Initial value of global var: b
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, $a, t0 # Assign global: a (using tmp register)
+ lw a0, $a # Load global: a
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw a0, 12(a0) # Get attribute: A.a
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ bnez a0, label_2 # Ensure not None
+ j error.None # Go to error handler
+label_2: # Not None
+ lw a0, 12(a0) # Get attribute: B.a
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ bnez a0, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ lw a0, 16(a0) # Get attribute: B.b
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_5 # Jump to function epilogue
+label_5: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_attr_set.py.ast.typed.s b/src/test/data/pa3/sample/object_attr_set.py.ast.typed.s
new file mode 100644
index 0000000..124fc5c
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set.py.ast.typed.s
@@ -0,0 +1,773 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+
+.globl $a
+$a:
+ .word 0 # Initial value of global var: a
+
+.globl $b
+$b:
+ .word 0 # Initial value of global var: b
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, $a, t0 # Assign global: a (using tmp register)
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, $b, t0 # Assign global: b (using tmp register)
+ li a0, 1 # Load integer literal 1
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $b # Load global: b
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, 12(a1) # Set attribute: B.a
+ li a0, 0 # Load boolean literal: false
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $b # Load global: b
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_2 # Ensure not None
+ j error.None # Go to error handler
+label_2: # Not None
+ sw a0, 16(a1) # Set attribute: B.b
+ lw a0, $a # Load global: a
+ bnez a0, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ lw a0, 12(a0) # Get attribute: A.a
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ lw a0, 12(a0) # Get attribute: B.a
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ bnez a0, label_5 # Ensure not None
+ j error.None # Go to error handler
+label_5: # Not None
+ lw a0, 16(a0) # Get attribute: B.b
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_7 # Jump to function epilogue
+label_7: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed.s b/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed.s
new file mode 100644
index 0000000..4cf3855
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set_eval_order.py.ast.typed.s
@@ -0,0 +1,902 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+
+.globl $a
+$a:
+ .word 0 # Initial value of global var: a
+
+.globl $b
+$b:
+ .word 0 # Initial value of global var: b
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, $a, t0 # Assign global: a (using tmp register)
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, $b, t0 # Assign global: b (using tmp register)
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $get_one # Invoke function: get_one
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $get_b # Invoke function: get_b
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, 12(a1) # Set attribute: B.a
+ la a0, const_2 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $get_false # Invoke function: get_false
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push on stack slot 3
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $get_b # Invoke function: get_b
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_2 # Ensure not None
+ j error.None # Go to error handler
+label_2: # Not None
+ sw a0, 16(a1) # Set attribute: B.b
+ la a0, const_3 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a # Load global: a
+ bnez a0, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ lw a0, 12(a0) # Get attribute: A.a
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ lw a0, 12(a0) # Get attribute: B.a
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ bnez a0, label_5 # Ensure not None
+ j error.None # Go to error handler
+label_5: # Not None
+ lw a0, 16(a0) # Get attribute: B.b
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_5 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_6 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_7 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_7 # Jump to function epilogue
+label_7: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $get_b
+$get_b:
+ addi sp, sp, -@get_b.size # Reserve space for stack frame.
+ sw ra, @get_b.size-4(sp) # return address
+ sw fp, @get_b.size-8(sp) # control link
+ addi fp, sp, @get_b.size # New fp is at old SP.
+ la a0, const_8 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@get_b.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ j label_9 # Go to return
+ mv a0, zero # Load None
+ j label_9 # Jump to function epilogue
+label_9: # Epilogue
+ .equiv @get_b.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @get_b.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $get_one
+$get_one:
+ addi sp, sp, -@get_one.size # Reserve space for stack frame.
+ sw ra, @get_one.size-4(sp) # return address
+ sw fp, @get_one.size-8(sp) # control link
+ addi fp, sp, @get_one.size # New fp is at old SP.
+ la a0, const_9 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@get_one.size # Set SP to stack frame top.
+ li a0, 1 # Load integer literal 1
+ j label_11 # Go to return
+ mv a0, zero # Load None
+ j label_11 # Jump to function epilogue
+label_11: # Epilogue
+ .equiv @get_one.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @get_one.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $get_false
+$get_false:
+ addi sp, sp, -@get_false.size # Reserve space for stack frame.
+ sw ra, @get_false.size-4(sp) # return address
+ sw fp, @get_false.size-8(sp) # control link
+ addi fp, sp, @get_false.size # New fp is at old SP.
+ la a0, const_10 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@get_false.size # Set SP to stack frame top.
+ li a0, 0 # Load boolean literal: false
+ j label_13 # Go to return
+ mv a0, zero # Load None
+ j label_13 # Jump to function epilogue
+label_13: # Epilogue
+ .equiv @get_false.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @get_false.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_11 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_12 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_13 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_14 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 7 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 9 # Constant value of attribute: __len__
+ .string "Getting 1" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Getting False" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_13
+const_13:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 12 # Constant value of attribute: __len__
+ .string "Assigned B.b" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 12 # Constant value of attribute: __len__
+ .string "Assigned B.a" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_14
+const_14:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 7 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 9 # Constant value of attribute: __len__
+ .string "Getting B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_12
+const_12:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed.s b/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed.s
new file mode 100644
index 0000000..5b17825
--- /dev/null
+++ b/src/test/data/pa3/sample/object_attr_set_none.py.ast.typed.s
@@ -0,0 +1,770 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+
+.globl $a
+$a:
+ .word 0 # Initial value of global var: a
+
+.globl $b
+$b:
+ .word 0 # Initial value of global var: b
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, $a, t0 # Assign global: a (using tmp register)
+ lw a0, $a # Load global: a
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ lw a0, 12(a0) # Get attribute: A.a
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 1 # Load integer literal 1
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $b # Load global: b
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_2 # Ensure not None
+ j error.None # Go to error handler
+label_2: # Not None
+ sw a0, 12(a1) # Set attribute: B.a
+ li a0, 0 # Load boolean literal: false
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, $b # Load global: b
+ mv a1, a0 # Move object
+ lw a0, -12(fp) # Pop stack slot 3
+ bnez a1, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ sw a0, 16(a1) # Set attribute: B.b
+ lw a0, $b # Load global: b
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ lw a0, 12(a0) # Get attribute: B.a
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ bnez a0, label_5 # Ensure not None
+ j error.None # Go to error handler
+label_5: # Not None
+ lw a0, 16(a0) # Get attribute: B.b
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_7 # Jump to function epilogue
+label_7: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_init.py.ast.typed.s b/src/test/data/pa3/sample/object_init.py.ast.typed.s
new file mode 100644
index 0000000..0d286c8
--- /dev/null
+++ b/src/test/data/pa3/sample/object_init.py.ast.typed.s
@@ -0,0 +1,713 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Pop stack slot 3
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_method.py.ast.typed.s b/src/test/data/pa3/sample/object_method.py.ast.typed.s
new file mode 100644
index 0000000..a06aa6b
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method.py.ast.typed.s
@@ -0,0 +1,786 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+ .word $A.foo # Implementation for method: A.foo
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+ .word $A.foo # Implementation for method: B.foo
+ .word $B.bar # Implementation for method: B.bar
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -20(fp) # Push on stack slot 5
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -20(fp) # Pop stack slot 5
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -32(fp) # Peek stack slot 7
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 8(a1) # Load address of method: B.bar
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: B.bar
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $A.foo
+$A.foo:
+ addi sp, sp, -@A.foo.size # Reserve space for stack frame.
+ sw ra, @A.foo.size-4(sp) # return address
+ sw fp, @A.foo.size-8(sp) # control link
+ addi fp, sp, @A.foo.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: A.foo.self
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ lw a0, 12(a0) # Get attribute: A.a
+ j label_3 # Go to return
+ mv a0, zero # Load None
+ j label_3 # Jump to function epilogue
+label_3: # Epilogue
+ .equiv @A.foo.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @A.foo.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.bar
+$B.bar:
+ addi sp, sp, -@B.bar.size # Reserve space for stack frame.
+ sw ra, @B.bar.size-4(sp) # return address
+ sw fp, @B.bar.size-8(sp) # control link
+ addi fp, sp, @B.bar.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: B.bar.self
+ bnez a0, label_9 # Ensure not None
+ j error.None # Go to error handler
+label_9: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: B.bar.self
+ bnez a0, label_10 # Ensure not None
+ j error.None # Go to error handler
+label_10: # Not None
+ lw a0, 16(a0) # Get attribute: B.b
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: B.foo
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: B.foo
+ addi sp, fp, -@B.bar.size # Set SP to stack frame top.
+ j label_8 # Go to return
+ mv a0, zero # Load None
+ j label_8 # Jump to function epilogue
+label_8: # Epilogue
+ .equiv @B.bar.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.bar.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed.s b/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed.s
new file mode 100644
index 0000000..da46cdc
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_complex_call.py.ast.typed.s
@@ -0,0 +1,824 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+ .word $A.foo # Implementation for method: A.foo
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+ .word $B.foo # Implementation for method: B.foo
+ .word $B.bar # Implementation for method: B.bar
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -20(fp) # Push on stack slot 5
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -20(fp) # Pop stack slot 5
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -32(fp) # Peek stack slot 7
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 8(a1) # Load address of method: B.bar
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: B.bar
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $A.foo
+$A.foo:
+ addi sp, sp, -@A.foo.size # Reserve space for stack frame.
+ sw ra, @A.foo.size-4(sp) # return address
+ sw fp, @A.foo.size-8(sp) # control link
+ addi fp, sp, @A.foo.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: A.foo.self
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ lw a0, 12(a0) # Get attribute: A.a
+ j label_3 # Go to return
+ mv a0, zero # Load None
+ j label_3 # Jump to function epilogue
+label_3: # Epilogue
+ .equiv @A.foo.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @A.foo.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.bar
+$B.bar:
+ addi sp, sp, -@B.bar.size # Reserve space for stack frame.
+ sw ra, @B.bar.size-4(sp) # return address
+ sw fp, @B.bar.size-8(sp) # control link
+ addi fp, sp, @B.bar.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: B.bar.self
+ bnez a0, label_9 # Ensure not None
+ j error.None # Go to error handler
+label_9: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: B.bar.self
+ bnez a0, label_10 # Ensure not None
+ j error.None # Go to error handler
+label_10: # Not None
+ sw a0, -28(fp) # Push argument 1 from last.
+ la a0, const_6 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.bar.size # Set SP to stack frame top.
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -28(fp) # Peek stack slot 6
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: B.foo
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: B.foo
+ addi sp, fp, -@B.bar.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: B.foo
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: B.foo
+ addi sp, fp, -@B.bar.size # Set SP to stack frame top.
+ j label_8 # Go to return
+ mv a0, zero # Load None
+ j label_8 # Jump to function epilogue
+label_8: # Epilogue
+ .equiv @B.bar.size, 48
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.bar.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.foo
+$B.foo:
+ addi sp, sp, -@B.foo.size # Reserve space for stack frame.
+ sw ra, @B.foo.size-4(sp) # return address
+ sw fp, @B.foo.size-8(sp) # control link
+ addi fp, sp, @B.foo.size # New fp is at old SP.
+ li a0, 1 # Load integer literal 1
+ j label_12 # Go to return
+ mv a0, zero # Load None
+ j label_12 # Jump to function epilogue
+label_12: # Epilogue
+ .equiv @B.foo.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.foo.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_7 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "..." # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_method_nested.py.ast.typed.s b/src/test/data/pa3/sample/object_method_nested.py.ast.typed.s
new file mode 100644
index 0000000..9cdc60a
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_nested.py.ast.typed.s
@@ -0,0 +1,806 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+ .word $A.foo # Implementation for method: A.foo
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+ .word $A.foo # Implementation for method: B.foo
+ .word $B.bar # Implementation for method: B.bar
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -20(fp) # Push on stack slot 5
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -20(fp) # Pop stack slot 5
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -32(fp) # Peek stack slot 7
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 8(a1) # Load address of method: B.bar
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: B.bar
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $A.foo
+$A.foo:
+ addi sp, sp, -@A.foo.size # Reserve space for stack frame.
+ sw ra, @A.foo.size-4(sp) # return address
+ sw fp, @A.foo.size-8(sp) # control link
+ addi fp, sp, @A.foo.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: A.foo.self
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ lw a0, 12(a0) # Get attribute: A.a
+ j label_3 # Go to return
+ mv a0, zero # Load None
+ j label_3 # Jump to function epilogue
+label_3: # Epilogue
+ .equiv @A.foo.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @A.foo.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.bar.qux
+$B.bar.qux:
+ addi sp, sp, -@B.bar.qux.size # Reserve space for stack frame.
+ sw ra, @B.bar.qux.size-4(sp) # return address
+ sw fp, @B.bar.qux.size-8(sp) # control link
+ addi fp, sp, @B.bar.qux.size # New fp is at old SP.
+ lw t0, 4(fp) # Load static link from B.bar.qux to B.bar
+ lw a0, 0(t0) # Load var: B.bar.self
+ bnez a0, label_9 # Ensure not None
+ j error.None # Go to error handler
+label_9: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: B.bar.qux.p
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: B.foo
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: B.foo
+ addi sp, fp, -@B.bar.qux.size # Set SP to stack frame top.
+ j label_8 # Go to return
+ mv a0, zero # Load None
+ j label_8 # Jump to function epilogue
+label_8: # Epilogue
+ .equiv @B.bar.qux.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.bar.qux.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.bar
+$B.bar:
+ addi sp, sp, -@B.bar.size # Reserve space for stack frame.
+ sw ra, @B.bar.size-4(sp) # return address
+ sw fp, @B.bar.size-8(sp) # control link
+ addi fp, sp, @B.bar.size # New fp is at old SP.
+ mv t0, fp # Get static link to B.bar
+ sw t0, -12(fp) # Push argument 1 from last.
+ li a0, 1 # Load boolean literal: true
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $B.bar.qux # Invoke function: B.bar.qux
+ addi sp, fp, -@B.bar.size # Set SP to stack frame top.
+ j label_11 # Go to return
+ mv a0, zero # Load None
+ j label_11 # Jump to function epilogue
+label_11: # Epilogue
+ .equiv @B.bar.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.bar.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_method_none.py.ast.typed.s b/src/test/data/pa3/sample/object_method_none.py.ast.typed.s
new file mode 100644
index 0000000..c171c09
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_none.py.ast.typed.s
@@ -0,0 +1,788 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+ .word $A.foo # Implementation for method: A.foo
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+ .word $A.foo # Implementation for method: B.foo
+ .word $B.bar # Implementation for method: B.bar
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -20(fp) # Push on stack slot 5
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -20(fp) # Pop stack slot 5
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -32(fp) # Peek stack slot 7
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 8(a1) # Load address of method: B.bar
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: B.bar
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $A.foo
+$A.foo:
+ addi sp, sp, -@A.foo.size # Reserve space for stack frame.
+ sw ra, @A.foo.size-4(sp) # return address
+ sw fp, @A.foo.size-8(sp) # control link
+ addi fp, sp, @A.foo.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: A.foo.self
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ lw a0, 12(a0) # Get attribute: A.a
+ j label_3 # Go to return
+ mv a0, zero # Load None
+ j label_3 # Jump to function epilogue
+label_3: # Epilogue
+ .equiv @A.foo.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @A.foo.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.bar
+$B.bar:
+ addi sp, sp, -@B.bar.size # Reserve space for stack frame.
+ sw ra, @B.bar.size-4(sp) # return address
+ sw fp, @B.bar.size-8(sp) # control link
+ addi fp, sp, @B.bar.size # New fp is at old SP.
+ mv a0, zero # Load None
+ sw a0, -12(fp) # local variable a
+ lw a0, -12(fp) # Load var: B.bar.a
+ bnez a0, label_9 # Ensure not None
+ j error.None # Go to error handler
+label_9: # Not None
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: B.bar.self
+ bnez a0, label_10 # Ensure not None
+ j error.None # Go to error handler
+label_10: # Not None
+ lw a0, 16(a0) # Get attribute: B.b
+ jal makebool # Box boolean
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -28(fp) # Peek stack slot 6
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: A.foo
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: A.foo
+ addi sp, fp, -@B.bar.size # Set SP to stack frame top.
+ j label_8 # Go to return
+ mv a0, zero # Load None
+ j label_8 # Jump to function epilogue
+label_8: # Epilogue
+ .equiv @B.bar.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.bar.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/object_method_override.py.ast.typed.s b/src/test/data/pa3/sample/object_method_override.py.ast.typed.s
new file mode 100644
index 0000000..2de48d1
--- /dev/null
+++ b/src/test/data/pa3/sample/object_method_override.py.ast.typed.s
@@ -0,0 +1,803 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $B$prototype
+$B$prototype:
+ .word 5 # Type tag for class: B
+ .word 5 # Object size
+ .word $B$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .word 1 # Initial value of attribute: b
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+ .word $A.foo # Implementation for method: A.foo
+
+.globl $B$dispatchTable
+$B$dispatchTable:
+ .word $B.__init__ # Implementation for method: B.__init__
+ .word $B.foo # Implementation for method: B.foo
+ .word $B.bar # Implementation for method: B.bar
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $B$prototype # Load pointer to prototype of: B
+ jal alloc # Allocate new object in A0
+ sw a0, -20(fp) # Push on stack slot 5
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: B.__init__
+ jalr a1 # Invoke method: B.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -20(fp) # Pop stack slot 5
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -32(fp) # Push argument 0 from last.
+ lw a0, -32(fp) # Peek stack slot 7
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 8(a1) # Load address of method: B.bar
+ addi sp, fp, -32 # Set SP to last argument.
+ jalr a1 # Invoke method: B.bar
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $A.foo
+$A.foo:
+ addi sp, sp, -@A.foo.size # Reserve space for stack frame.
+ sw ra, @A.foo.size-4(sp) # return address
+ sw fp, @A.foo.size-8(sp) # control link
+ addi fp, sp, @A.foo.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: A.foo.self
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ lw a0, 12(a0) # Get attribute: A.a
+ j label_3 # Go to return
+ mv a0, zero # Load None
+ j label_3 # Jump to function epilogue
+label_3: # Epilogue
+ .equiv @A.foo.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @A.foo.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.__init__
+$B.__init__:
+ addi sp, sp, -@B.__init__.size # Reserve space for stack frame.
+ sw ra, @B.__init__.size-4(sp) # return address
+ sw fp, @B.__init__.size-8(sp) # control link
+ addi fp, sp, @B.__init__.size # New fp is at old SP.
+ la a0, const_5 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@B.__init__.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ j label_6 # Jump to function epilogue
+label_6: # Epilogue
+ .equiv @B.__init__.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.__init__.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.bar
+$B.bar:
+ addi sp, sp, -@B.bar.size # Reserve space for stack frame.
+ sw ra, @B.bar.size-4(sp) # return address
+ sw fp, @B.bar.size-8(sp) # control link
+ addi fp, sp, @B.bar.size # New fp is at old SP.
+ lw a0, 0(fp) # Load var: B.bar.self
+ bnez a0, label_9 # Ensure not None
+ j error.None # Go to error handler
+label_9: # Not None
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: B.bar.self
+ bnez a0, label_10 # Ensure not None
+ j error.None # Go to error handler
+label_10: # Not None
+ lw a0, 16(a0) # Get attribute: B.b
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ lw a0, -12(fp) # Peek stack slot 2
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 4(a1) # Load address of method: B.foo
+ addi sp, fp, -16 # Set SP to last argument.
+ jalr a1 # Invoke method: B.foo
+ addi sp, fp, -@B.bar.size # Set SP to stack frame top.
+ j label_8 # Go to return
+ mv a0, zero # Load None
+ j label_8 # Jump to function epilogue
+label_8: # Epilogue
+ .equiv @B.bar.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.bar.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $B.foo
+$B.foo:
+ addi sp, sp, -@B.foo.size # Reserve space for stack frame.
+ sw ra, @B.foo.size-4(sp) # return address
+ sw fp, @B.foo.size-8(sp) # control link
+ addi fp, sp, @B.foo.size # New fp is at old SP.
+ li a0, 1 # Load integer literal 1
+ j label_12 # Go to return
+ mv a0, zero # Load None
+ j label_12 # Jump to function epilogue
+label_12: # Epilogue
+ .equiv @B.foo.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @B.foo.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "B" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/op_add.py.ast.typed.s b/src/test/data/pa3/sample/op_add.py.ast.typed.s
new file mode 100644
index 0000000..8a5e0da
--- /dev/null
+++ b/src/test/data/pa3/sample/op_add.py.ast.typed.s
@@ -0,0 +1,659 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 100 # Load integer literal 100
+ lw t0, -20(fp) # Pop stack slot 5
+ add a0, t0, a0 # Operator +
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed.s b/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed.s
new file mode 100644
index 0000000..39ed0f2
--- /dev/null
+++ b/src/test/data/pa3/sample/op_cmp_bool.py.ast.typed.s
@@ -0,0 +1,745 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load boolean literal: true
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load boolean literal: true
+ lw t0, -20(fp) # Pop stack slot 5
+ snez t0, t0 # Ensure that operand for == is 1 or 0
+ seqz a0, a0 # Ensure that operand for == is 0 or 1 (flipped)
+ xor a0, t0, a0 # Operator ==
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 1 # Load boolean literal: true
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load boolean literal: false
+ lw t0, -20(fp) # Pop stack slot 5
+ snez t0, t0 # Ensure that operand for == is 1 or 0
+ seqz a0, a0 # Ensure that operand for == is 0 or 1 (flipped)
+ xor a0, t0, a0 # Operator ==
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 0 # Load boolean literal: false
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load boolean literal: true
+ lw t0, -20(fp) # Pop stack slot 5
+ snez t0, t0 # Ensure that operand for == is 1 or 0
+ seqz a0, a0 # Ensure that operand for == is 0 or 1 (flipped)
+ xor a0, t0, a0 # Operator ==
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 0 # Load boolean literal: false
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load boolean literal: false
+ lw t0, -20(fp) # Pop stack slot 5
+ snez t0, t0 # Ensure that operand for == is 1 or 0
+ seqz a0, a0 # Ensure that operand for == is 0 or 1 (flipped)
+ xor a0, t0, a0 # Operator ==
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 1 # Load boolean literal: true
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load boolean literal: true
+ lw t0, -20(fp) # Pop stack slot 5
+ snez t0, t0 # Ensure that operand for != is 1 or 0
+ snez a0, a0 # Ensure that operand for != is 1 or 0
+ xor a0, t0, a0 # Operator !=
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 1 # Load boolean literal: true
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load boolean literal: false
+ lw t0, -20(fp) # Pop stack slot 5
+ snez t0, t0 # Ensure that operand for != is 1 or 0
+ snez a0, a0 # Ensure that operand for != is 1 or 0
+ xor a0, t0, a0 # Operator !=
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 0 # Load boolean literal: false
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 1 # Load boolean literal: true
+ lw t0, -20(fp) # Pop stack slot 5
+ snez t0, t0 # Ensure that operand for != is 1 or 0
+ snez a0, a0 # Ensure that operand for != is 1 or 0
+ xor a0, t0, a0 # Operator !=
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ li a0, 0 # Load boolean literal: false
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 0 # Load boolean literal: false
+ lw t0, -20(fp) # Pop stack slot 5
+ snez t0, t0 # Ensure that operand for != is 1 or 0
+ snez a0, a0 # Ensure that operand for != is 1 or 0
+ xor a0, t0, a0 # Operator !=
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/op_cmp_int.py.ast.typed.s b/src/test/data/pa3/sample/op_cmp_int.py.ast.typed.s
new file mode 100644
index 0000000..432f5dd
--- /dev/null
+++ b/src/test/data/pa3/sample/op_cmp_int.py.ast.typed.s
@@ -0,0 +1,785 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 42 # Initial value of global var: x
+
+.globl $y
+$y:
+ .word 7 # Initial value of global var: y
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $y # Load global: y
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Operator ==
+ seqz a0, a0 # Operator == (..contd)
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $y # Load global: y
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Operator !=
+ snez a0, a0 # Operator != (..contd)
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $y # Load global: y
+ lw t0, -20(fp) # Pop stack slot 5
+ slt a0, t0, a0 # Operator <
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $y # Load global: y
+ lw t0, -20(fp) # Pop stack slot 5
+ slt a0, a0, t0 # Operator <=
+ seqz a0, a0 # Operator <= (..contd)
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $y # Load global: y
+ lw t0, -20(fp) # Pop stack slot 5
+ slt a0, a0, t0 # Operator >
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $y # Load global: y
+ lw t0, -20(fp) # Pop stack slot 5
+ slt a0, t0, a0 # Operator >=
+ seqz a0, a0 # Operator >= (..contd)
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $x # Load global: x
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Operator ==
+ seqz a0, a0 # Operator == (..contd)
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $x # Load global: x
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Operator !=
+ snez a0, a0 # Operator != (..contd)
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $x # Load global: x
+ lw t0, -20(fp) # Pop stack slot 5
+ slt a0, t0, a0 # Operator <
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $x # Load global: x
+ lw t0, -20(fp) # Pop stack slot 5
+ slt a0, a0, t0 # Operator <=
+ seqz a0, a0 # Operator <= (..contd)
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $x # Load global: x
+ lw t0, -20(fp) # Pop stack slot 5
+ slt a0, a0, t0 # Operator >
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $x # Load global: x
+ lw t0, -20(fp) # Pop stack slot 5
+ slt a0, t0, a0 # Operator >=
+ seqz a0, a0 # Operator >= (..contd)
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/op_div_mod.py.ast.typed.s b/src/test/data/pa3/sample/op_div_mod.py.ast.typed.s
new file mode 100644
index 0000000..4769581
--- /dev/null
+++ b/src/test/data/pa3/sample/op_div_mod.py.ast.typed.s
@@ -0,0 +1,702 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 42 # Initial value of global var: x
+
+.globl $y
+$y:
+ .word 9 # Initial value of global var: y
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $y # Load global: y
+ lw t0, -20(fp) # Pop stack slot 5
+ bnez a0, label_1 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_1: # Divisor is non-zero
+ xor t2, t0, a0 # Check for same sign
+ bltz t2, label_3 # If !=, need to adjust left operand
+ div a0, t0, a0 # Operator //
+ j label_2
+label_3: # Operands have differing signs
+ slt t2, zero, a0 # tmp = 1 if right > 0 else 0
+ add t2, t2, t2 # tmp *= 2
+ addi t2, t2, -1 # tmp = 1 if right>=0 else -1
+ add t2, t0, t2 # Adjust left operand
+ div t2, t2, a0 # Adjusted division, toward 0
+ addi a0, t2, -1 # Complete division when signs !=
+label_2: # End of //
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $y # Load global: y
+ lw t0, -20(fp) # Pop stack slot 5
+ bnez a0, label_4 # Ensure non-zero divisor
+ j error.Div # Go to error handler
+label_4: # Divisor is non-zero
+ rem t2, t0, a0 # Operator rem
+ beqz t2, label_5 # If no remainder, no adjustment
+ xor t3, t2, a0 # Check for differing signs.
+ bgez t3, label_5 # Don't adjust if signs equal.
+ add a0, t2, a0 # Adjust
+ j label_6
+label_5: # Store result
+ mv a0, t2
+label_6: # End of %
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/op_is.py.ast.typed.s b/src/test/data/pa3/sample/op_is.py.ast.typed.s
new file mode 100644
index 0000000..e2e8d2e
--- /dev/null
+++ b/src/test/data/pa3/sample/op_is.py.ast.typed.s
@@ -0,0 +1,778 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $A$prototype
+$A$prototype:
+ .word 4 # Type tag for class: A
+ .word 4 # Object size
+ .word $A$dispatchTable # Pointer to dispatch table
+ .word 42 # Initial value of attribute: a
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $A$dispatchTable
+$A$dispatchTable:
+ .word $object.__init__ # Implementation for method: A.__init__
+
+.globl $a1
+$a1:
+ .word 0 # Initial value of global var: a1
+
+.globl $a2
+$a2:
+ .word 0 # Initial value of global var: a2
+
+.globl $a3
+$a3:
+ .word 0 # Initial value of global var: a3
+
+.globl $a4
+$a4:
+ .word 0 # Initial value of global var: a4
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $A$prototype # Load pointer to prototype of: A
+ jal alloc # Allocate new object in A0
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: A.__init__
+ jalr a1 # Invoke method: A.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, $a1, t0 # Assign global: a1 (using tmp register)
+ lw a0, $a1 # Load global: a1
+ sw a0, $a2, t0 # Assign global: a2 (using tmp register)
+ la a0, $A$prototype # Load pointer to prototype of: A
+ jal alloc # Allocate new object in A0
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: A.__init__
+ jalr a1 # Invoke method: A.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Pop stack slot 3
+ sw a0, $a3, t0 # Assign global: a3 (using tmp register)
+ lw a0, $a1 # Load global: a1
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $a1 # Load global: a1
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Compare references
+ seqz a0, a0 # Operator is
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a1 # Load global: a1
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $a2 # Load global: a2
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Compare references
+ seqz a0, a0 # Operator is
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a1 # Load global: a1
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $a3 # Load global: a3
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Compare references
+ seqz a0, a0 # Operator is
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a1 # Load global: a1
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $a4 # Load global: a4
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Compare references
+ seqz a0, a0 # Operator is
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a1 # Load global: a1
+ sw a0, -20(fp) # Push on stack slot 5
+ mv a0, zero # Load None
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Compare references
+ seqz a0, a0 # Operator is
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a4 # Load global: a4
+ sw a0, -20(fp) # Push on stack slot 5
+ mv a0, zero # Load None
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Compare references
+ seqz a0, a0 # Operator is
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ mv a0, zero # Load None
+ sw a0, -20(fp) # Push on stack slot 5
+ mv a0, zero # Load None
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Compare references
+ seqz a0, a0 # Operator is
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/op_logical.py.ast.typed.s b/src/test/data/pa3/sample/op_logical.py.ast.typed.s
new file mode 100644
index 0000000..d25a10d
--- /dev/null
+++ b/src/test/data/pa3/sample/op_logical.py.ast.typed.s
@@ -0,0 +1,765 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $f # Invoke function: f
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ bnez a0, label_2 # Branch on true.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $g # Invoke function: g
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ beqz a0, label_1 # Branch on false.
+label_2::
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $g # Invoke function: g
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ beqz a0, label_4 # Branch on false.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $f # Invoke function: f
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ beqz a0, label_4 # Branch on false.
+ la a0, const_2 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_3 # Then body complete; jump to end-if
+label_4: # Else body
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $f # Invoke function: f
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ beqz a0, label_5 # Operator and: short-circuit left operand
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $g # Invoke function: g
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ bnez a0, label_6 # Operator or: short-circuit left operand
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $f # Invoke function: f
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+label_6: # Done evaluating operator: or
+label_5: # Done evaluating operator: and
+ seqz a0, a0 # Logical not
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+label_3: # End of if-else statement
+label_1: # End of if-else statement
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_4 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_5 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $f
+$f:
+ addi sp, sp, -@f.size # Reserve space for stack frame.
+ sw ra, @f.size-4(sp) # return address
+ sw fp, @f.size-8(sp) # control link
+ addi fp, sp, @f.size # New fp is at old SP.
+ la a0, const_6 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@f.size # Set SP to stack frame top.
+ li a0, 1 # Load boolean literal: true
+ j label_8 # Go to return
+ mv a0, zero # Load None
+ j label_8 # Jump to function epilogue
+label_8: # Epilogue
+ .equiv @f.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @f.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $g
+$g:
+ addi sp, sp, -@g.size # Reserve space for stack frame.
+ sw ra, @g.size-4(sp) # return address
+ sw fp, @g.size-8(sp) # control link
+ addi fp, sp, @g.size # New fp is at old SP.
+ la a0, const_7 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@g.size # Set SP to stack frame top.
+ li a0, 0 # Load boolean literal: false
+ j label_10 # Go to return
+ mv a0, zero # Load None
+ j label_10 # Jump to function epilogue
+label_10: # Epilogue
+ .equiv @g.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @g.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_8 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_11 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "Never" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 7 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 8 # Constant value of attribute: __len__
+ .string "f called" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 7 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 8 # Constant value of attribute: __len__
+ .string "g called" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/op_mul.py.ast.typed.s b/src/test/data/pa3/sample/op_mul.py.ast.typed.s
new file mode 100644
index 0000000..cbd8e4c
--- /dev/null
+++ b/src/test/data/pa3/sample/op_mul.py.ast.typed.s
@@ -0,0 +1,663 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 6 # Load integer literal 6
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 9 # Load integer literal 9
+ lw t0, -20(fp) # Pop stack slot 5
+ mul a0, t0, a0 # Operator *
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 2 # Load integer literal 2
+ lw t0, -20(fp) # Pop stack slot 5
+ mul a0, t0, a0 # Operator *
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/op_negate.py.ast.typed.s b/src/test/data/pa3/sample/op_negate.py.ast.typed.s
new file mode 100644
index 0000000..43422bf
--- /dev/null
+++ b/src/test/data/pa3/sample/op_negate.py.ast.typed.s
@@ -0,0 +1,660 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 42 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ sub a0, zero, a0 # Unary negation
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/op_sub.py.ast.typed.s b/src/test/data/pa3/sample/op_sub.py.ast.typed.s
new file mode 100644
index 0000000..a445117
--- /dev/null
+++ b/src/test/data/pa3/sample/op_sub.py.ast.typed.s
@@ -0,0 +1,659 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push on stack slot 5
+ li a0, 100 # Load integer literal 100
+ lw t0, -20(fp) # Pop stack slot 5
+ sub a0, t0, a0 # Operator -
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/pass.py.ast.typed.s b/src/test/data/pa3/sample/pass.py.ast.typed.s
new file mode 100644
index 0000000..e16f865
--- /dev/null
+++ b/src/test/data/pa3/sample/pass.py.ast.typed.s
@@ -0,0 +1,649 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/predef_constructors.py.ast.typed.s b/src/test/data/pa3/sample/predef_constructors.py.ast.typed.s
new file mode 100644
index 0000000..a592c9f
--- /dev/null
+++ b/src/test/data/pa3/sample/predef_constructors.py.ast.typed.s
@@ -0,0 +1,695 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, $object$prototype # Load pointer to prototype of: object
+ jal alloc # Allocate new object in A0
+ sw a0, -20(fp) # Push on stack slot 5
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: object.__init__
+ jalr a1 # Invoke method: object.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -20(fp) # Pop stack slot 5
+ sw a0, -20(fp) # Push on stack slot 5
+ mv a0, zero # Load None
+ lw t0, -20(fp) # Pop stack slot 5
+ xor a0, t0, a0 # Compare references
+ seqz a0, a0 # Operator is
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ mv a0, zero # Special cases: int and bool unboxed.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ la a0, $str$prototype # Load pointer to prototype of: str
+ jal alloc # Allocate new object in A0
+ sw a0, -20(fp) # Push on stack slot 5
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ lw a1, 8(a0) # Load address of object's dispatch table
+ lw a1, 0(a1) # Load address of method: str.__init__
+ jalr a1 # Invoke method: str.__init__
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, -20(fp) # Pop stack slot 5
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ mv a0, zero # Special cases: int and bool unboxed.
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_list.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list.py.ast.typed.s
new file mode 100644
index 0000000..876f5bf
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list.py.ast.typed.s
@@ -0,0 +1,697 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.globl $z
+$z:
+ .word 0 # Initial value of global var: z
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $z, t0 # Assign global: z (using tmp register)
+ lw a0, $z # Load global: z
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_2: # for-loop header
+ lw t1, -16(fp) # Pop stack slot 4
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_3 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $x, t1 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_2 # Loop back to header
+label_3: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed.s
new file mode 100644
index 0000000..2b2a470
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_empty.py.ast.typed.s
@@ -0,0 +1,747 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.globl $y
+$y:
+ .word 0 # Initial value of global var: y
+
+.globl $z
+$z:
+ .word 0 # Initial value of global var: z
+
+.globl $e
+$e:
+ .word 0 # Initial value of global var: e
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $z, t0 # Assign global: z (using tmp register)
+ li a0, 0 # Pass list length
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $e, t0 # Assign global: e (using tmp register)
+ lw a0, $z # Load global: z
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_2: # for-loop header
+ lw t1, -16(fp) # Pop stack slot 4
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_3 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $x, t1 # Assign global: x (using tmp register)
+ lw a0, $e # Load global: e
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ sw a0, -20(fp) # Push on stack slot 5
+ mv t1, zero # Initialize for-loop index
+ sw t1, -24(fp) # Push on stack slot 6
+label_5: # for-loop header
+ lw t1, -24(fp) # Pop stack slot 6
+ lw t0, -20(fp) # Peek stack slot 4
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_6 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -24(fp) # Push on stack slot 6
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $y, t1 # Assign global: y (using tmp register)
+ la a0, const_2 # Load string literal
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_5 # Loop back to header
+label_6: # for-loop footer
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_2 # Loop back to header
+label_3: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_4 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_5 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "Never" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed.s
new file mode 100644
index 0000000..fd3e718
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_eval.py.ast.typed.s
@@ -0,0 +1,703 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.globl $z
+$z:
+ .word 0 # Initial value of global var: z
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $z, t0 # Assign global: z (using tmp register)
+ lw a0, $z # Load global: z
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_2: # for-loop header
+ lw t1, -16(fp) # Pop stack slot 4
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_3 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $x, t1 # Assign global: x (using tmp register)
+ li a0, 0 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $z, t0 # Assign global: z (using tmp register)
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_2 # Loop back to header
+label_3: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed.s
new file mode 100644
index 0000000..d5a78a7
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_modify.py.ast.typed.s
@@ -0,0 +1,716 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.globl $z
+$z:
+ .word 0 # Initial value of global var: z
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 1 # Load integer literal 1
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $z, t0 # Assign global: z (using tmp register)
+ lw a0, $z # Load global: z
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_2: # for-loop header
+ lw t1, -16(fp) # Pop stack slot 4
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_3 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $x, t1 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -20(fp) # Push on stack slot 5
+ lw a0, $z # Load global: z
+ sw a0, -24(fp) # Push on stack slot 6
+ lw a0, $x # Load global: x
+ lw t0, -24(fp) # Pop stack slot 6
+ lw t1, -20(fp) # Pop stack slot 5
+ bnez t0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ lw t2, 12(t0) # Load attribute: __len__
+ bltu a0, t2, label_5 # Ensure 0 <= index < len
+ j error.OOB # Go to error handler
+label_5: # Index within bounds
+ addi a0, a0, 4 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul a0, a0, t2 # Compute list element offset in bytes
+ add a0, t0, a0 # Pointer to list element
+ sw t1, 0(a0) # Set list element
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_2 # Loop back to header
+label_3: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed.s
new file mode 100644
index 0000000..8408245
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nested.py.ast.typed.s
@@ -0,0 +1,727 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.globl $y
+$y:
+ .word 0 # Initial value of global var: y
+
+.globl $z
+$z:
+ .word 0 # Initial value of global var: z
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $z, t0 # Assign global: z (using tmp register)
+ lw a0, $z # Load global: z
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_2: # for-loop header
+ lw t1, -16(fp) # Pop stack slot 4
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_3 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $x, t1 # Assign global: x (using tmp register)
+ lw a0, $z # Load global: z
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ sw a0, -20(fp) # Push on stack slot 5
+ mv t1, zero # Initialize for-loop index
+ sw t1, -24(fp) # Push on stack slot 6
+label_5: # for-loop header
+ lw t1, -24(fp) # Pop stack slot 6
+ lw t0, -20(fp) # Peek stack slot 4
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_6 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -24(fp) # Push on stack slot 6
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $y, t1 # Assign global: y (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -36(fp) # Push on stack slot 9
+ lw a0, $y # Load global: y
+ lw t0, -36(fp) # Pop stack slot 9
+ mul a0, t0, a0 # Operator *
+ jal makeint # Box integer
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_5 # Loop back to header
+label_6: # for-loop footer
+ j label_2 # Loop back to header
+label_3: # for-loop footer
+ .equiv @..main.size, 48
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed.s
new file mode 100644
index 0000000..76aae48
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nested_same_var.py.ast.typed.s
@@ -0,0 +1,723 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.globl $y
+$y:
+ .word 0 # Initial value of global var: y
+
+.globl $z
+$z:
+ .word 0 # Initial value of global var: z
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -20(fp) # Push argument 3 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -24(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -28(fp) # Push argument 1 from last.
+ li a0, 3 # Pass list length
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $z, t0 # Assign global: z (using tmp register)
+ lw a0, $z # Load global: z
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_2: # for-loop header
+ lw t1, -16(fp) # Pop stack slot 4
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_3 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $x, t1 # Assign global: x (using tmp register)
+ lw a0, $z # Load global: z
+ bnez a0, label_4 # Ensure not None
+ j error.None # Go to error handler
+label_4: # Not None
+ sw a0, -20(fp) # Push on stack slot 5
+ mv t1, zero # Initialize for-loop index
+ sw t1, -24(fp) # Push on stack slot 6
+label_5: # for-loop header
+ lw t1, -24(fp) # Pop stack slot 6
+ lw t0, -20(fp) # Peek stack slot 4
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_6 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -24(fp) # Push on stack slot 6
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $x, t1 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_5 # Loop back to header
+label_6: # for-loop footer
+ j label_2 # Loop back to header
+label_3: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed.s
new file mode 100644
index 0000000..bedf91d
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_none.py.ast.typed.s
@@ -0,0 +1,685 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.globl $z
+$z:
+ .word 0 # Initial value of global var: z
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $z # Load global: z
+ bnez a0, label_1 # Ensure not None
+ j error.None # Go to error handler
+label_1: # Not None
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_2: # for-loop header
+ lw t1, -16(fp) # Pop stack slot 4
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_3 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $x, t1 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_2 # Loop back to header
+label_3: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed.s
new file mode 100644
index 0000000..8c5e299
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_nonlocal.py.ast.typed.s
@@ -0,0 +1,791 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 1 # Load integer literal 1
+ sw a0, -56(fp) # Push argument 2 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -60(fp) # Push argument 1 from last.
+ li a0, 2 # Pass list length
+ sw a0, -64(fp) # Push argument 0 from last.
+ addi sp, fp, -64 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -32(fp) # Push argument 4 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -56(fp) # Push argument 2 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -60(fp) # Push argument 1 from last.
+ li a0, 2 # Pass list length
+ sw a0, -64(fp) # Push argument 0 from last.
+ addi sp, fp, -64 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -36(fp) # Push argument 3 from last.
+ li a0, 4 # Load integer literal 4
+ sw a0, -56(fp) # Push argument 2 from last.
+ li a0, 5 # Load integer literal 5
+ sw a0, -60(fp) # Push argument 1 from last.
+ li a0, 2 # Pass list length
+ sw a0, -64(fp) # Push argument 0 from last.
+ addi sp, fp, -64 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -40(fp) # Push argument 2 from last.
+ li a0, 6 # Load integer literal 6
+ sw a0, -56(fp) # Push argument 2 from last.
+ li a0, 7 # Load integer literal 7
+ sw a0, -60(fp) # Push argument 1 from last.
+ li a0, 2 # Pass list length
+ sw a0, -64(fp) # Push argument 0 from last.
+ addi sp, fp, -64 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -44(fp) # Push argument 1 from last.
+ li a0, 4 # Pass list length
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $crunch # Invoke function: crunch
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 64
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $crunch.make_z
+$crunch.make_z:
+ addi sp, sp, -@crunch.make_z.size # Reserve space for stack frame.
+ sw ra, @crunch.make_z.size-4(sp) # return address
+ sw fp, @crunch.make_z.size-8(sp) # control link
+ addi fp, sp, @crunch.make_z.size # New fp is at old SP.
+ lw t0, 0(fp) # Load static link from crunch.make_z to crunch
+ lw a0, 0(t0) # Load var: crunch.zz
+ bnez a0, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_4: # for-loop header
+ lw t1, -16(fp) # Pop stack slot 4
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_5 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ lw t1, 0(fp) # Load static link from crunch.make_z to crunch
+ sw t0, -12(t1) # Assign var: crunch.z
+ j label_4 # Loop back to header
+label_5: # for-loop footer
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @crunch.make_z.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @crunch.make_z.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $crunch
+$crunch:
+ addi sp, sp, -@crunch.size # Reserve space for stack frame.
+ sw ra, @crunch.size-4(sp) # return address
+ sw fp, @crunch.size-8(sp) # control link
+ addi fp, sp, @crunch.size # New fp is at old SP.
+ mv a0, zero # Load None
+ sw a0, -12(fp) # local variable z
+ mv t0, fp # Get static link to crunch
+ sw t0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $crunch.make_z # Invoke function: crunch.make_z
+ addi sp, fp, -@crunch.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Load var: crunch.z
+ bnez a0, label_8 # Ensure not None
+ j error.None # Go to error handler
+label_8: # Not None
+ sw a0, -16(fp) # Push on stack slot 4
+ mv t1, zero # Initialize for-loop index
+ sw t1, -20(fp) # Push on stack slot 5
+label_9: # for-loop header
+ lw t1, -20(fp) # Pop stack slot 5
+ lw t0, -16(fp) # Peek stack slot 3
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_10 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -20(fp) # Push on stack slot 5
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, $x, t1 # Assign global: x (using tmp register)
+ j label_9 # Loop back to header
+label_10: # for-loop footer
+ mv a0, zero # Load None
+ j label_7 # Jump to function epilogue
+label_7: # Epilogue
+ .equiv @crunch.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @crunch.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed.s
new file mode 100644
index 0000000..825a597
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_list_return.py.ast.typed.s
@@ -0,0 +1,719 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 10 # Load integer literal 10
+ sw a0, -32(fp) # Push argument 4 from last.
+ li a0, 20 # Load integer literal 20
+ sw a0, -36(fp) # Push argument 3 from last.
+ li a0, 30 # Load integer literal 30
+ sw a0, -40(fp) # Push argument 2 from last.
+ li a0, 40 # Load integer literal 40
+ sw a0, -44(fp) # Push argument 1 from last.
+ li a0, 4 # Pass list length
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal conslist # Move values to new list object
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print_list # Invoke function: print_list
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 48
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $print_list
+$print_list:
+ addi sp, sp, -@print_list.size # Reserve space for stack frame.
+ sw ra, @print_list.size-4(sp) # return address
+ sw fp, @print_list.size-8(sp) # control link
+ addi fp, sp, @print_list.size # New fp is at old SP.
+ li a0, 0 # Load integer literal 0
+ sw a0, -12(fp) # local variable x
+ lw a0, 0(fp) # Load var: print_list.z
+ bnez a0, label_3 # Ensure not None
+ j error.None # Go to error handler
+label_3: # Not None
+ sw a0, -16(fp) # Push on stack slot 4
+ mv t1, zero # Initialize for-loop index
+ sw t1, -20(fp) # Push on stack slot 5
+label_4: # for-loop header
+ lw t1, -20(fp) # Pop stack slot 5
+ lw t0, -16(fp) # Peek stack slot 3
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_5 # Exit loop if idx >= len(iter)
+ addi t1, t1, 1 # Increment idx
+ sw t1, -20(fp) # Push on stack slot 5
+ addi t1, t1, 3 # Compute list element offset in words
+ li t2, 4 # Word size in bytes
+ mul t1, t1, t2 # Compute list element offset in bytes
+ add t1, t0, t1 # Pointer to list element
+ lw t0, 0(t1) # Get list element
+ sw t0, -12(fp) # Assign var: print_list.x
+ lw a0, -12(fp) # Load var: print_list.x
+ jal makeint # Box integer
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@print_list.size # Set SP to stack frame top.
+ lw a0, -12(fp) # Load var: print_list.x
+ sw a0, -24(fp) # Push on stack slot 6
+ li a0, 30 # Load integer literal 30
+ lw t0, -24(fp) # Pop stack slot 6
+ blt t0, a0, label_6 # Branch on not >=
+ mv a0, zero # Returning None implicitly
+ j label_2 # Go to return
+label_6: # End of if-else statement
+ j label_4 # Loop back to header
+label_5: # for-loop footer
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @print_list.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @print_list.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_str.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_str.py.ast.typed.s
new file mode 100644
index 0000000..bd0f21d
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str.py.ast.typed.s
@@ -0,0 +1,726 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word const_2 # Initial value of global var: x
+
+.globl $z
+$z:
+ .word const_3 # Initial value of global var: z
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $z # Load global: z
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_1: # for-loop header
+ lw t1, -16(fp) # Peek stack slot 3
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_2 # Exit loop if idx >= len(iter)
+ lw t0, -16(fp) # Pop stack slot 4
+ lw a1, -12(fp) # Peek stack slot 2
+ addi t1, t0, 1 # Increment index for next iteration
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_1 # Loop back to header
+label_2: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_5 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_6 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_7 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ la a0, $str$prototype
+ lw t0, 0(a0)
+ lw t1, 4(a0)
+ lw t2, 8(a0)
+ li t3, 1
+ la a0, allChars
+ li t4, 256
+ mv t5, zero
+initchars_1:
+ sw t0, 0(a0)
+ sw t1, 4(a0)
+ sw t2, 8(a0)
+ sw t3, 12(a0)
+ sw t5, 16(a0)
+ addi a0, a0, 20
+ addi t5, t5, 1
+ bne t4, t5, initchars_1
+ jr ra
+ .data
+ .align 2
+ .globl allChars
+allChars:
+ .space 5120
+ .text
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "abc" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed.s
new file mode 100644
index 0000000..1518234
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_empty.py.ast.typed.s
@@ -0,0 +1,767 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word const_2 # Initial value of global var: x
+
+.globl $y
+$y:
+ .word const_3 # Initial value of global var: y
+
+.globl $z
+$z:
+ .word const_4 # Initial value of global var: z
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $z # Load global: z
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_1: # for-loop header
+ lw t1, -16(fp) # Peek stack slot 3
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_2 # Exit loop if idx >= len(iter)
+ lw t0, -16(fp) # Pop stack slot 4
+ lw a1, -12(fp) # Peek stack slot 2
+ addi t1, t0, 1 # Increment index for next iteration
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ la a0, const_2 # Load string literal
+ sw a0, -20(fp) # Push on stack slot 5
+ mv t1, zero # Initialize for-loop index
+ sw t1, -24(fp) # Push on stack slot 6
+label_3: # for-loop header
+ lw t1, -24(fp) # Peek stack slot 5
+ lw t0, -20(fp) # Peek stack slot 4
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_4 # Exit loop if idx >= len(iter)
+ lw t0, -24(fp) # Pop stack slot 6
+ lw a1, -20(fp) # Peek stack slot 4
+ addi t1, t0, 1 # Increment index for next iteration
+ sw t1, -24(fp) # Push on stack slot 6
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_3 # Loop back to header
+label_4: # for-loop footer
+ j label_1 # Loop back to header
+label_2: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_6 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_7 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_8 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ la a0, $str$prototype
+ lw t0, 0(a0)
+ lw t1, 4(a0)
+ lw t2, 8(a0)
+ li t3, 1
+ la a0, allChars
+ li t4, 256
+ mv t5, zero
+initchars_1:
+ sw t0, 0(a0)
+ sw t1, 4(a0)
+ sw t2, 8(a0)
+ sw t3, 12(a0)
+ sw t5, 16(a0)
+ addi a0, a0, 20
+ addi t5, t5, 1
+ bne t4, t5, initchars_1
+ jr ra
+ .data
+ .align 2
+ .globl allChars
+allChars:
+ .space 5120
+ .text
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_11 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "123" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "abc" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed.s
new file mode 100644
index 0000000..c240950
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_eval.py.ast.typed.s
@@ -0,0 +1,737 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word const_2 # Initial value of global var: x
+
+.globl $z
+$z:
+ .word const_3 # Initial value of global var: z
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $z # Load global: z
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_1: # for-loop header
+ lw t1, -16(fp) # Peek stack slot 3
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_2 # Exit loop if idx >= len(iter)
+ lw t0, -16(fp) # Pop stack slot 4
+ lw a1, -12(fp) # Peek stack slot 2
+ addi t1, t0, 1 # Increment index for next iteration
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ la a0, const_4 # Load string literal
+ sw a0, $z, t0 # Assign global: z (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_1 # Loop back to header
+label_2: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_6 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_7 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_8 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ la a0, $str$prototype
+ lw t0, 0(a0)
+ lw t1, 4(a0)
+ lw t2, 8(a0)
+ li t3, 1
+ la a0, allChars
+ li t4, 256
+ mv t5, zero
+initchars_1:
+ sw t0, 0(a0)
+ sw t1, 4(a0)
+ sw t2, 8(a0)
+ sw t3, 12(a0)
+ sw t5, 16(a0)
+ addi a0, a0, 20
+ addi t5, t5, 1
+ bne t4, t5, initchars_1
+ jr ra
+ .data
+ .align 2
+ .globl allChars
+allChars:
+ .space 5120
+ .text
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_11 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 14 # Constant value of attribute: __len__
+ .string "doesn't matter" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "abc" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed.s
new file mode 100644
index 0000000..8f53930
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_nested.py.ast.typed.s
@@ -0,0 +1,767 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word const_2 # Initial value of global var: x
+
+.globl $y
+$y:
+ .word const_3 # Initial value of global var: y
+
+.globl $z
+$z:
+ .word const_4 # Initial value of global var: z
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $z # Load global: z
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_1: # for-loop header
+ lw t1, -16(fp) # Peek stack slot 3
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_2 # Exit loop if idx >= len(iter)
+ lw t0, -16(fp) # Pop stack slot 4
+ lw a1, -12(fp) # Peek stack slot 2
+ addi t1, t0, 1 # Increment index for next iteration
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $y # Load global: y
+ sw a0, -20(fp) # Push on stack slot 5
+ mv t1, zero # Initialize for-loop index
+ sw t1, -24(fp) # Push on stack slot 6
+label_3: # for-loop header
+ lw t1, -24(fp) # Peek stack slot 5
+ lw t0, -20(fp) # Peek stack slot 4
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_4 # Exit loop if idx >= len(iter)
+ lw t0, -24(fp) # Pop stack slot 6
+ lw a1, -20(fp) # Peek stack slot 4
+ addi t1, t0, 1 # Increment index for next iteration
+ sw t1, -24(fp) # Push on stack slot 6
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_3 # Loop back to header
+label_4: # for-loop footer
+ j label_1 # Loop back to header
+label_2: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_6 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_7 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_8 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ la a0, $str$prototype
+ lw t0, 0(a0)
+ lw t1, 4(a0)
+ lw t2, 8(a0)
+ li t3, 1
+ la a0, allChars
+ li t4, 256
+ mv t5, zero
+initchars_1:
+ sw t0, 0(a0)
+ sw t1, 4(a0)
+ sw t2, 8(a0)
+ sw t3, 12(a0)
+ sw t5, 16(a0)
+ addi a0, a0, 20
+ addi t5, t5, 1
+ bne t4, t5, initchars_1
+ jr ra
+ .data
+ .align 2
+ .globl allChars
+allChars:
+ .space 5120
+ .text
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_11 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "123" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "abc" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed.s b/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed.s
new file mode 100644
index 0000000..d5e1171
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_for_str_same_var.py.ast.typed.s
@@ -0,0 +1,713 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word const_2 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ sw a0, -12(fp) # Push on stack slot 3
+ mv t1, zero # Initialize for-loop index
+ sw t1, -16(fp) # Push on stack slot 4
+label_1: # for-loop header
+ lw t1, -16(fp) # Peek stack slot 3
+ lw t0, -12(fp) # Peek stack slot 2
+ lw t2, 12(t0) # Get attribute __len__
+ bgeu t1, t2, label_2 # Exit loop if idx >= len(iter)
+ lw t0, -16(fp) # Pop stack slot 4
+ lw a1, -12(fp) # Peek stack slot 2
+ addi t1, t0, 1 # Increment index for next iteration
+ sw t1, -16(fp) # Push on stack slot 4
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_1 # Loop back to header
+label_2: # for-loop footer
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_4 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_5 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ la a0, $str$prototype
+ lw t0, 0(a0)
+ lw t1, 4(a0)
+ lw t2, 8(a0)
+ li t3, 1
+ la a0, allChars
+ li t4, 256
+ mv t5, zero
+initchars_1:
+ sw t0, 0(a0)
+ sw t1, 4(a0)
+ sw t2, 8(a0)
+ sw t3, 12(a0)
+ sw t5, 16(a0)
+ addi a0, a0, 20
+ addi t5, t5, 1
+ bne t4, t5, initchars_1
+ jr ra
+ .data
+ .align 2
+ .globl allChars
+allChars:
+ .space 5120
+ .text
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "xXx" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_if.py.ast.typed.s b/src/test/data/pa3/sample/stmt_if.py.ast.typed.s
new file mode 100644
index 0000000..e287a90
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_if.py.ast.typed.s
@@ -0,0 +1,683 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ j label_2 # Branch on false.
+ la a0, const_2 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ j label_1 # Then body complete; jump to end-if
+label_2: # Else body
+ la a0, const_3 # Load string literal
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+label_4: # End of if-else statement
+label_3: # End of if-else statement
+label_1: # End of if-else statement
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_5 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_6 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_7 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 2 # Constant value of attribute: __len__
+ .string "No" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "Yes" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_return_early.py.ast.typed.s b/src/test/data/pa3/sample/stmt_return_early.py.ast.typed.s
new file mode 100644
index 0000000..97d0dbc
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_return_early.py.ast.typed.s
@@ -0,0 +1,680 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $f # Invoke function: f
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $f
+$f:
+ addi sp, sp, -@f.size # Reserve space for stack frame.
+ sw ra, @f.size-4(sp) # return address
+ sw fp, @f.size-8(sp) # control link
+ addi fp, sp, @f.size # New fp is at old SP.
+ j label_4 # Jump to loop test
+label_3: # Top of while loop
+ li a0, 1 # Load integer literal 1
+ j label_2 # Go to return
+label_4: # Test loop condition
+ j label_3 # Branch on true.
+ li a0, 0 # Load integer literal 0
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @f.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @f.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/stmt_while.py.ast.typed.s b/src/test/data/pa3/sample/stmt_while.py.ast.typed.s
new file mode 100644
index 0000000..3efd2e2
--- /dev/null
+++ b/src/test/data/pa3/sample/stmt_while.py.ast.typed.s
@@ -0,0 +1,673 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 1 # Initial value of global var: x
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ j label_2 # Jump to loop test
+label_1: # Top of while loop
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $x # Load global: x
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 1 # Load integer literal 1
+ lw t0, -12(fp) # Pop stack slot 3
+ add a0, t0, a0 # Operator +
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+label_2: # Test loop condition
+ lw a0, $x # Load global: x
+ sw a0, -12(fp) # Push on stack slot 3
+ li a0, 10 # Load integer literal 10
+ lw t0, -12(fp) # Pop stack slot 3
+ blt t0, a0, label_1 # Branch on <
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_3 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_4 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_2 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_6 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/str_cat.py.ast.typed.s b/src/test/data/pa3/sample/str_cat.py.ast.typed.s
new file mode 100644
index 0000000..91620c9
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cat.py.ast.typed.s
@@ -0,0 +1,835 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $a
+$a:
+ .word const_2 # Initial value of global var: a
+
+.globl $b
+$b:
+ .word const_3 # Initial value of global var: b
+
+.globl $c
+$c:
+ .word const_4 # Initial value of global var: c
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $a # Load global: a
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $b # Load global: b
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $cat2 # Invoke function: cat2
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ la a0, const_5 # Load string literal
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $c # Load global: c
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $cat2 # Invoke function: cat2
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a # Load global: a
+ sw a0, -24(fp) # Push argument 2 from last.
+ la a0, const_6 # Load string literal
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $c # Load global: c
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $cat3 # Invoke function: cat3
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a # Load global: a
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a # Load global: a
+ sw a0, -44(fp) # Push argument 1 from last.
+ lw a0, $a # Load global: a
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal $cat2 # Invoke function: cat2
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ la a0, const_5 # Load string literal
+ sw a0, -44(fp) # Push argument 1 from last.
+ la a0, const_5 # Load string literal
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal $cat2 # Invoke function: cat2
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 48
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_7 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_8 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_9 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_7 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $cat2
+$cat2:
+ addi sp, sp, -@cat2.size # Reserve space for stack frame.
+ sw ra, @cat2.size-4(sp) # return address
+ sw fp, @cat2.size-8(sp) # control link
+ addi fp, sp, @cat2.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: cat2.a
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: cat2.b
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal strcat # Call string concatenation function
+ addi sp, fp, -@cat2.size # Set SP to stack frame top.
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @cat2.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @cat2.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $cat3
+$cat3:
+ addi sp, sp, -@cat3.size # Reserve space for stack frame.
+ sw ra, @cat3.size-4(sp) # return address
+ sw fp, @cat3.size-8(sp) # control link
+ addi fp, sp, @cat3.size # New fp is at old SP.
+ lw a0, 8(fp) # Load var: cat3.a
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, 4(fp) # Load var: cat3.b
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal strcat # Call string concatenation function
+ addi sp, fp, -@cat3.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: cat3.c
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal strcat # Call string concatenation function
+ addi sp, fp, -@cat3.size # Set SP to stack frame top.
+ j label_4 # Go to return
+ mv a0, zero # Load None
+ j label_4 # Jump to function epilogue
+label_4: # Epilogue
+ .equiv @cat3.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @cat3.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_10 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_11 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_12 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_13 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string " " # Constant value of attribute: __str__
+ .align 2
+
+.globl const_12
+const_12:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "Hello" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_13
+const_13:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 7 # Constant value of attribute: __len__
+ .string "ChocoPy" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "World" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/str_cat_2.py.ast.typed.s b/src/test/data/pa3/sample/str_cat_2.py.ast.typed.s
new file mode 100644
index 0000000..cb90a71
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cat_2.py.ast.typed.s
@@ -0,0 +1,795 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $a
+$a:
+ .word const_2 # Initial value of global var: a
+
+.globl $b
+$b:
+ .word const_3 # Initial value of global var: b
+
+.globl $c
+$c:
+ .word const_4 # Initial value of global var: c
+
+.globl $d
+$d:
+ .word const_4 # Initial value of global var: d
+
+.globl $e
+$e:
+ .word const_4 # Initial value of global var: e
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $b # Load global: b
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, $a # Load global: a
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $cat2 # Invoke function: cat2
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $c, t0 # Assign global: c (using tmp register)
+ lw a0, $a # Load global: a
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, $a # Load global: a
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $cat2 # Invoke function: cat2
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $d, t0 # Assign global: d (using tmp register)
+ lw a0, $a # Load global: a
+ sw a0, -24(fp) # Push argument 2 from last.
+ lw a0, $b # Load global: b
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $b # Load global: b
+ sw a0, -44(fp) # Push argument 1 from last.
+ lw a0, $b # Load global: b
+ sw a0, -48(fp) # Push argument 0 from last.
+ addi sp, fp, -48 # Set SP to last argument.
+ jal $cat2 # Invoke function: cat2
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $cat3 # Invoke function: cat3
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $e, t0 # Assign global: e (using tmp register)
+ lw a0, $c # Load global: c
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $d # Load global: d
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $e # Load global: e
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 48
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_6 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_7 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $cat2
+$cat2:
+ addi sp, sp, -@cat2.size # Reserve space for stack frame.
+ sw ra, @cat2.size-4(sp) # return address
+ sw fp, @cat2.size-8(sp) # control link
+ addi fp, sp, @cat2.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: cat2.a
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: cat2.b
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal strcat # Call string concatenation function
+ addi sp, fp, -@cat2.size # Set SP to stack frame top.
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @cat2.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @cat2.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $cat3
+$cat3:
+ addi sp, sp, -@cat3.size # Reserve space for stack frame.
+ sw ra, @cat3.size-4(sp) # return address
+ sw fp, @cat3.size-8(sp) # control link
+ addi fp, sp, @cat3.size # New fp is at old SP.
+ lw a0, 8(fp) # Load var: cat3.a
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, 4(fp) # Load var: cat3.b
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal strcat # Call string concatenation function
+ addi sp, fp, -@cat3.size # Set SP to stack frame top.
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: cat3.c
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal strcat # Call string concatenation function
+ addi sp, fp, -@cat3.size # Set SP to stack frame top.
+ j label_4 # Go to return
+ mv a0, zero # Load None
+ j label_4 # Jump to function epilogue
+label_4: # Epilogue
+ .equiv @cat3.size, 32
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @cat3.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_8 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_11 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 2 # Constant value of attribute: __len__
+ .string "no" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __len__
+ .string "o" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/str_cmp.py.ast.typed.s b/src/test/data/pa3/sample/str_cmp.py.ast.typed.s
new file mode 100644
index 0000000..c06cce6
--- /dev/null
+++ b/src/test/data/pa3/sample/str_cmp.py.ast.typed.s
@@ -0,0 +1,806 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $a
+$a:
+ .word const_2 # Initial value of global var: a
+
+.globl $b
+$b:
+ .word const_3 # Initial value of global var: b
+
+.globl $c
+$c:
+ .word const_4 # Initial value of global var: c
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $a # Load global: a
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $a # Load global: a
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $eq # Invoke function: eq
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a # Load global: a
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $b # Load global: b
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $eq # Invoke function: eq
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $a # Load global: a
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $b # Load global: b
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $neq # Invoke function: neq
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $b # Load global: b
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $neq # Invoke function: neq
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $c # Load global: c
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $a # Load global: a
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $eq # Invoke function: eq
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $c # Load global: c
+ sw a0, -28(fp) # Push argument 1 from last.
+ lw a0, $b # Load global: b
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $neq # Invoke function: neq
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makebool # Box boolean
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_6 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_7 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_5 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $eq
+$eq:
+ addi sp, sp, -@eq.size # Reserve space for stack frame.
+ sw ra, @eq.size-4(sp) # return address
+ sw fp, @eq.size-8(sp) # control link
+ addi fp, sp, @eq.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: eq.a
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: eq.b
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal streql # Call string == function
+ addi sp, fp, -@eq.size # Set SP to stack frame top.
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @eq.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @eq.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl $neq
+$neq:
+ addi sp, sp, -@neq.size # Reserve space for stack frame.
+ sw ra, @neq.size-4(sp) # return address
+ sw fp, @neq.size-8(sp) # control link
+ addi fp, sp, @neq.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: neq.a
+ sw a0, -12(fp) # Push argument 1 from last.
+ lw a0, 0(fp) # Load var: neq.b
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal strneql # Call string == function
+ addi sp, fp, -@neq.size # Set SP to stack frame top.
+ j label_4 # Go to return
+ mv a0, zero # Load None
+ j label_4 # Jump to function epilogue
+label_4: # Epilogue
+ .equiv @neq.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @neq.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_8 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_11 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "Hello" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_11
+const_11:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 7 # Constant value of attribute: __len__
+ .string "ChocoPy" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "World" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/str_get_element.py.ast.typed.s b/src/test/data/pa3/sample/str_get_element.py.ast.typed.s
new file mode 100644
index 0000000..11529aa
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element.py.ast.typed.s
@@ -0,0 +1,779 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word const_2 # Initial value of global var: x
+
+.globl $a
+$a:
+ .word const_3 # Initial value of global var: a
+
+.globl $b
+$b:
+ .word const_3 # Initial value of global var: b
+
+.globl $c
+$c:
+ .word const_3 # Initial value of global var: c
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ sw a0, -12(fp) # Push argument 1 from last.
+ li a0, 0 # Load integer literal 0
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $str_get # Invoke function: str_get
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $a, t0 # Assign global: a (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -12(fp) # Push argument 1 from last.
+ li a0, 1 # Load integer literal 1
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $str_get # Invoke function: str_get
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $b, t0 # Assign global: b (using tmp register)
+ lw a0, $x # Load global: x
+ sw a0, -12(fp) # Push argument 1 from last.
+ li a0, 2 # Load integer literal 2
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $str_get # Invoke function: str_get
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $c, t0 # Assign global: c (using tmp register)
+ lw a0, $a # Load global: a
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $b # Load global: b
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ lw a0, $c # Load global: c
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_5 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_6 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $str_get
+$str_get:
+ addi sp, sp, -@str_get.size # Reserve space for stack frame.
+ sw ra, @str_get.size-4(sp) # return address
+ sw fp, @str_get.size-8(sp) # control link
+ addi fp, sp, @str_get.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: str_get.s
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: str_get.i
+ lw a1, -12(fp) # Peek stack slot 2
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_3 # Ensure 0 <= idx < len
+ j error.OOB # Go to error handler
+label_3: # Index within bounds
+ sw a0, -16(fp) # Push on stack slot 4
+ lw t0, -16(fp) # Pop stack slot 4
+ lw a1, -12(fp) # Peek stack slot 2
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @str_get.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @str_get.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_7 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ la a0, $str$prototype
+ lw t0, 0(a0)
+ lw t1, 4(a0)
+ lw t2, 8(a0)
+ li t3, 1
+ la a0, allChars
+ li t4, 256
+ mv t5, zero
+initchars_1:
+ sw t0, 0(a0)
+ sw t1, 4(a0)
+ sw t2, 8(a0)
+ sw t3, 12(a0)
+ sw t5, 16(a0)
+ addi a0, a0, 20
+ addi t5, t5, 1
+ bne t4, t5, initchars_1
+ jr ra
+ .data
+ .align 2
+ .globl allChars
+allChars:
+ .space 5120
+ .text
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "abc" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed.s b/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed.s
new file mode 100644
index 0000000..1390d56
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_1.py.ast.typed.s
@@ -0,0 +1,746 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word const_2 # Initial value of global var: x
+
+.globl $a
+$a:
+ .word const_3 # Initial value of global var: a
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ sw a0, -12(fp) # Push argument 1 from last.
+ li a0, 1 # Load integer literal 1
+ sub a0, zero, a0 # Unary negation
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $str_get # Invoke function: str_get
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $a, t0 # Assign global: a (using tmp register)
+ lw a0, $a # Load global: a
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_5 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_6 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $str_get
+$str_get:
+ addi sp, sp, -@str_get.size # Reserve space for stack frame.
+ sw ra, @str_get.size-4(sp) # return address
+ sw fp, @str_get.size-8(sp) # control link
+ addi fp, sp, @str_get.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: str_get.s
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: str_get.i
+ lw a1, -12(fp) # Peek stack slot 2
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_3 # Ensure 0 <= idx < len
+ j error.OOB # Go to error handler
+label_3: # Index within bounds
+ sw a0, -16(fp) # Push on stack slot 4
+ lw t0, -16(fp) # Pop stack slot 4
+ lw a1, -12(fp) # Peek stack slot 2
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @str_get.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @str_get.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_7 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ la a0, $str$prototype
+ lw t0, 0(a0)
+ lw t1, 4(a0)
+ lw t2, 8(a0)
+ li t3, 1
+ la a0, allChars
+ li t4, 256
+ mv t5, zero
+initchars_1:
+ sw t0, 0(a0)
+ sw t1, 4(a0)
+ sw t2, 8(a0)
+ sw t3, 12(a0)
+ sw t5, 16(a0)
+ addi a0, a0, 20
+ addi t5, t5, 1
+ bne t4, t5, initchars_1
+ jr ra
+ .data
+ .align 2
+ .globl allChars
+allChars:
+ .space 5120
+ .text
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "abc" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed.s b/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed.s
new file mode 100644
index 0000000..5f681e7
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_2.py.ast.typed.s
@@ -0,0 +1,745 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word const_2 # Initial value of global var: x
+
+.globl $a
+$a:
+ .word const_3 # Initial value of global var: a
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ sw a0, -12(fp) # Push argument 1 from last.
+ li a0, 3 # Load integer literal 3
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $str_get # Invoke function: str_get
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $a, t0 # Assign global: a (using tmp register)
+ lw a0, $a # Load global: a
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_5 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_6 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_4 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $str_get
+$str_get:
+ addi sp, sp, -@str_get.size # Reserve space for stack frame.
+ sw ra, @str_get.size-4(sp) # return address
+ sw fp, @str_get.size-8(sp) # control link
+ addi fp, sp, @str_get.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: str_get.s
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: str_get.i
+ lw a1, -12(fp) # Peek stack slot 2
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_3 # Ensure 0 <= idx < len
+ j error.OOB # Go to error handler
+label_3: # Index within bounds
+ sw a0, -16(fp) # Push on stack slot 4
+ lw t0, -16(fp) # Pop stack slot 4
+ lw a1, -12(fp) # Peek stack slot 2
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @str_get.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @str_get.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_7 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ la a0, $str$prototype
+ lw t0, 0(a0)
+ lw t1, 4(a0)
+ lw t2, 8(a0)
+ li t3, 1
+ la a0, allChars
+ li t4, 256
+ mv t5, zero
+initchars_1:
+ sw t0, 0(a0)
+ sw t1, 4(a0)
+ sw t2, 8(a0)
+ sw t3, 12(a0)
+ sw t5, 16(a0)
+ addi a0, a0, 20
+ addi t5, t5, 1
+ bne t4, t5, initchars_1
+ jr ra
+ .data
+ .align 2
+ .globl allChars
+allChars:
+ .space 5120
+ .text
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_10 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 3 # Constant value of attribute: __len__
+ .string "abc" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_10
+const_10:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed.s b/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed.s
new file mode 100644
index 0000000..05d59e9
--- /dev/null
+++ b/src/test/data/pa3/sample/str_get_element_oob_3.py.ast.typed.s
@@ -0,0 +1,736 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word const_2 # Initial value of global var: x
+
+.globl $a
+$a:
+ .word const_2 # Initial value of global var: a
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ lw a0, $x # Load global: x
+ sw a0, -12(fp) # Push argument 1 from last.
+ li a0, 0 # Load integer literal 0
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $str_get # Invoke function: str_get
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ sw a0, $a, t0 # Assign global: a (using tmp register)
+ lw a0, $a # Load global: a
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_4 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_5 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl $str_get
+$str_get:
+ addi sp, sp, -@str_get.size # Reserve space for stack frame.
+ sw ra, @str_get.size-4(sp) # return address
+ sw fp, @str_get.size-8(sp) # control link
+ addi fp, sp, @str_get.size # New fp is at old SP.
+ lw a0, 4(fp) # Load var: str_get.s
+ sw a0, -12(fp) # Push on stack slot 3
+ lw a0, 0(fp) # Load var: str_get.i
+ lw a1, -12(fp) # Peek stack slot 2
+ lw t0, 12(a1) # Load attribute: __len__
+ bltu a0, t0, label_3 # Ensure 0 <= idx < len
+ j error.OOB # Go to error handler
+label_3: # Index within bounds
+ sw a0, -16(fp) # Push on stack slot 4
+ lw t0, -16(fp) # Pop stack slot 4
+ lw a1, -12(fp) # Peek stack slot 2
+ addi t0, t0, 16 # Convert index to offset to char in bytes
+ add t0, a1, t0 # Get pointer to char
+ lbu t0, 0(t0) # Load character
+ li t1, 20
+ mul t0, t0, t1 # Multiply by size of string object
+ la a0, allChars # Index into single-char table
+ add a0, a0, t0
+ j label_2 # Go to return
+ mv a0, zero # Load None
+ j label_2 # Jump to function epilogue
+label_2: # Epilogue
+ .equiv @str_get.size, 16
+ lw ra, -4(fp) # Get return address
+ lw fp, -8(fp) # Use control link to restore caller's fp
+ addi sp, sp, @str_get.size # Restore stack pointer
+ jr ra # Return to caller
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ la a0, $str$prototype
+ lw t0, 0(a0)
+ lw t1, 4(a0)
+ lw t2, 8(a0)
+ li t3, 1
+ la a0, allChars
+ li t4, 256
+ mv t5, zero
+initchars_1:
+ sw t0, 0(a0)
+ sw t1, 4(a0)
+ sw t2, 8(a0)
+ sw t3, 12(a0)
+ sw t5, 16(a0)
+ addi a0, a0, 20
+ addi t5, t5, 1
+ bne t4, t5, initchars_1
+ jr ra
+ .data
+ .align 2
+ .globl allChars
+allChars:
+ .space 5120
+ .text
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __len__
+ .string "" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/str_len.py.ast.typed.s b/src/test/data/pa3/sample/str_len.py.ast.typed.s
new file mode 100644
index 0000000..fc08fea
--- /dev/null
+++ b/src/test/data/pa3/sample/str_len.py.ast.typed.s
@@ -0,0 +1,668 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ la a0, const_2 # Load string literal
+ sw a0, -32(fp) # Push argument 0 from last.
+ addi sp, fp, -32 # Set SP to last argument.
+ jal $len # Invoke function: len
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 32
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_4 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_5 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 7 # Constant value of attribute: __len__
+ .string "ChocoPy" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
diff --git a/src/test/data/pa3/sample/var_assign.py.ast.typed.s b/src/test/data/pa3/sample/var_assign.py.ast.typed.s
new file mode 100644
index 0000000..79635df
--- /dev/null
+++ b/src/test/data/pa3/sample/var_assign.py.ast.typed.s
@@ -0,0 +1,677 @@
+ .equiv @sbrk, 9
+ .equiv @print_string, 4
+ .equiv @print_char, 11
+ .equiv @print_int, 1
+ .equiv @exit2, 17
+ .equiv @read_string, 8
+ .equiv @fill_line_buffer, 18
+ .equiv @.__obj_size__, 4
+ .equiv @.__len__, 12
+ .equiv @.__int__, 12
+ .equiv @.__bool__, 12
+ .equiv @.__str__, 16
+ .equiv @.__elts__, 16
+ .equiv @error_div_zero, 2
+ .equiv @error_arg, 1
+ .equiv @error_oob, 3
+ .equiv @error_none, 4
+ .equiv @error_oom, 5
+ .equiv @error_nyi, 6
+ .equiv @listHeaderWords, 4
+ .equiv @strHeaderWords, 4
+ .equiv @bool.True, const_1
+ .equiv @bool.False, const_0
+
+.data
+
+.globl $object$prototype
+$object$prototype:
+ .word 0 # Type tag for class: object
+ .word 3 # Object size
+ .word $object$dispatchTable # Pointer to dispatch table
+ .align 2
+
+.globl $int$prototype
+$int$prototype:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __int__
+ .align 2
+
+.globl $bool$prototype
+$bool$prototype:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __bool__
+ .align 2
+
+.globl $str$prototype
+$str$prototype:
+ .word 3 # Type tag for class: str
+ .word 5 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .word 0 # Initial value of attribute: __str__
+ .align 2
+
+.globl $.list$prototype
+$.list$prototype:
+ .word -1 # Type tag for class: .list
+ .word 4 # Object size
+ .word 0 # Pointer to dispatch table
+ .word 0 # Initial value of attribute: __len__
+ .align 2
+
+.globl $object$dispatchTable
+$object$dispatchTable:
+ .word $object.__init__ # Implementation for method: object.__init__
+
+.globl $int$dispatchTable
+$int$dispatchTable:
+ .word $object.__init__ # Implementation for method: int.__init__
+
+.globl $bool$dispatchTable
+$bool$dispatchTable:
+ .word $object.__init__ # Implementation for method: bool.__init__
+
+.globl $str$dispatchTable
+$str$dispatchTable:
+ .word $object.__init__ # Implementation for method: str.__init__
+
+.globl $x
+$x:
+ .word 0 # Initial value of global var: x
+
+.globl $y
+$y:
+ .word const_2 # Initial value of global var: y
+
+.text
+
+.globl main
+main:
+ lui a0, 8192 # Initialize heap size (in multiples of 4KB)
+ add s11, s11, a0 # Save heap size
+ jal heap.init # Call heap.init routine
+ mv gp, a0 # Initialize heap pointer
+ mv s10, gp # Set beginning of heap
+ add s11, s10, s11 # Set end of heap (= start of heap + heap size)
+ mv ra, zero # No normal return from main program.
+ mv fp, zero # No preceding frame.
+ addi sp, sp, -@..main.size # Reserve space for stack frame.
+ sw ra, @..main.size-4(sp) # return address
+ sw fp, @..main.size-8(sp) # control link
+ addi fp, sp, @..main.size # New fp is at old SP.
+ jal initchars # Initialize one-character strings.
+ li a0, 42 # Load integer literal 42
+ sw a0, -12(fp) # Push on stack slot 3
+ sw a0, $x, t0 # Assign global: x (using tmp register)
+ lw a0, -12(fp) # Pop stack slot 3
+ jal makeint # Box integer
+ sw a0, $y, t0 # Assign global: y (using tmp register)
+ lw a0, $x # Load global: x
+ jal makeint # Box integer
+ sw a0, -16(fp) # Push argument 0 from last.
+ addi sp, fp, -16 # Set SP to last argument.
+ jal $print # Invoke function: print
+ addi sp, fp, -@..main.size # Set SP to stack frame top.
+ .equiv @..main.size, 16
+label_0: # End of program
+ li a0, 10 # Code for ecall: exit
+ ecall
+
+.globl $object.__init__
+$object.__init__:
+# Init method for type object.
+ mv a0, zero # `None` constant
+ jr ra # Return
+
+.globl $print
+$print:
+# Function print
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, print_6 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 1 # Load type tag of `int`
+ beq t0, t1, print_7 # Go to print(int)
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, print_8 # Go to print(str)
+ li t1, 2 # Load type tag of `bool`
+ beq t0, t1, print_9 # Go to print(bool)
+print_6: # Invalid argument
+ li a0, 1 # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+# Printing bools
+print_9: # Print bool object in A0
+ lw a0, @.__bool__(a0) # Load attribute __bool__
+ beq a0, zero, print_10 # Go to: print(False)
+ la a0, const_4 # String representation: True
+ j print_8 # Go to: print(str)
+print_10: # Print False object in A0
+ la a0, const_5 # String representation: False
+ j print_8 # Go to: print(str)
+
+# Printing strs.
+print_8: # Print str object in A0
+ addi a1, a0, @.__str__ # Load address of attribute __str__
+ j print_11 # Print the null-terminated string is now in A1
+ mv a0, zero # Load None
+ j print_5 # Go to return
+print_11: # Print null-terminated string in A1
+ li a0, @print_string # Code for ecall: print_string
+ ecall # Print string
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for ecall: print_char
+ ecall # Print character
+ j print_5 # Go to return
+
+# Printing ints.
+print_7: # Print int object in A0
+ lw a1, @.__int__(a0) # Load attribute __int__
+ li a0, @print_int # Code for ecall: print_int
+ ecall # Print integer
+ li a1, 10 # Load newline character
+ li a0, 11 # Code for ecall: print_char
+ ecall # Print character
+
+print_5: # End of function
+ mv a0, zero # Load None
+ jr ra # Return to caller
+
+.globl $len
+$len:
+# Function len
+ # We do not save/restore fp/ra for this function
+ # because we know that it does not use the stack or does not
+ # call other functions.
+
+ lw a0, 0(sp) # Load arg
+ beq a0, zero, len_12 # None is an illegal argument
+ lw t0, 0(a0) # Get type tag of arg
+ li t1, 3 # Load type tag of `str`
+ beq t0, t1, len_13 # Go to len(str)
+ li t1, -1 # Load type tag for list objects
+ beq t0, t1, len_13 # Go to len(list)
+len_12: # Invalid argument
+ li a0, @error_arg # Exit code for: Invalid argument
+ la a1, const_3 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+len_13: # Get length of string
+ lw a0, @.__len__(a0) # Load attribute: __len__
+ jr ra # Return to caller
+
+.globl $input
+$input:
+# Function input
+ addi sp, sp, -16 # Reserve stack
+ sw ra, 12(sp) # Save registers
+ sw fp, 8(sp)
+ sw s1, 4(sp)
+ addi fp, sp, 16 # Set fp
+
+ li a0, @fill_line_buffer # Fill the internal line buffer.
+ ecall
+ bgez a0, input_nonempty # More input found
+ la a0, $str$prototype # EOF: Return empty string.
+ j input_done
+
+input_nonempty:
+ mv s1, a0
+ addi t0, s1, 5 # Compute bytes for string (+NL+NUL),
+ addi t0, t0, @.__str__ # Including header.
+ srli a1, t0, 2 # Convert to words.
+ la a0, $str$prototype # Load address of string prototype.
+ jal ra, alloc2 # Allocate string.
+ sw s1, @.__len__(a0) # Store string length.
+ mv a2, s1 # Pass length.
+ mv s1, a0 # Save string object address.
+ addi a1, a0, @.__str__ # Pass address of string data.
+ li a0, @read_string # ecall to read from internal buffer.
+ ecall
+ addi a0, a0, 1 # Actual length (including NL).
+ sw a0, @.__len__(s1) # Store actual length.
+ add t0, a0, s1
+ li t1, 10 # Store newline and null byte
+ sb t1, @.__str__-1(t0)
+ sb zero, @.__str__(t0) # Store null byte at end.
+ mv a0, s1 # Return string object.
+
+input_done:
+ lw s1, -12(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 16
+ jr ra
+
+.globl alloc
+alloc:
+# Runtime support function alloc.
+ # Prototype address is in a0.
+ lw a1, 4(a0) # Get size of object in words
+ j alloc2 # Allocate object with exact size
+
+.globl alloc2
+alloc2:
+# Runtime support function alloc2 (realloc).
+ # Prototype address is in a0.
+ # Number of words to allocate is in a1.
+ li a2, 4 # Word size in bytes
+ mul a2, a1, a2 # Calculate number of bytes to allocate
+ add a2, gp, a2 # Estimate where GP will move
+ bgeu a2, s11, alloc2_15 # Go to OOM handler if too large
+ lw t0, @.__obj_size__(a0) # Get size of object in words
+ mv t2, a0 # Initialize src ptr
+ mv t3, gp # Initialize dest ptr
+alloc2_16: # Copy-loop header
+ lw t1, 0(t2) # Load next word from src
+ sw t1, 0(t3) # Store next word to dest
+ addi t2, t2, 4 # Increment src
+ addi t3, t3, 4 # Increment dest
+ addi t0, t0, -1 # Decrement counter
+ bne t0, zero, alloc2_16 # Loop if more words left to copy
+ mv a0, gp # Save new object's address to return
+ sw a1, @.__obj_size__(a0) # Set size of new object in words
+ # (same as requested size)
+ mv gp, a2 # Set next free slot in the heap
+ jr ra # Return to caller
+alloc2_15: # OOM handler
+ li a0, @error_oom # Exit code for: Out of memory
+ la a1, const_6 # Load error message as str
+ addi a1, a1, @.__str__ # Load address of attribute __str__
+ j abort # Abort
+
+.globl abort
+abort:
+# Runtime support function abort (does not return).
+ mv t0, a0 # Save exit code in temp
+ li a0, @print_string # Code for print_string ecall
+ ecall # Print error message in a1
+ li a1, 10 # Load newline character
+ li a0, @print_char # Code for print_char ecall
+ ecall # Print newline
+ mv a1, t0 # Move exit code to a1
+ li a0, @exit2 # Code for exit2 ecall
+ ecall # Exit with code
+abort_17: # Infinite loop
+ j abort_17 # Prevent fallthrough
+
+.globl heap.init
+heap.init:
+# Runtime support function heap.init.
+ mv a1, a0 # Move requested size to A1
+ li a0, @sbrk # Code for ecall: sbrk
+ ecall # Request A1 bytes
+ jr ra # Return to caller
+
+.globl concat
+concat:
+
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw fp, 24(sp)
+ addi fp, sp, 32
+ sw s1, -12(fp)
+ sw s2, -16(fp)
+ sw s3, -20(fp)
+ sw s4, -24(fp)
+ sw s5, -28(fp)
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ beqz t0, concat_none
+ beqz t1, concat_none
+ lw t0, @.__len__(t0)
+ lw t1, @.__len__(t1)
+ add s5, t0, t1
+ addi a1, s5, @listHeaderWords
+ la a0, $.list$prototype
+ jal alloc2
+ sw s5, @.__len__(a0)
+ mv s5, a0
+ addi s3, s5, @.__elts__
+ lw s1, 4(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 12(fp)
+concat_1:
+ beqz s2, concat_2
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_1
+concat_2:
+ lw s1, 0(fp)
+ lw s2, @.__len__(s1)
+ addi s1, s1, @.__elts__
+ lw s4, 8(fp)
+concat_3:
+ beqz s2, concat_4
+ lw a0, 0(s1)
+ jalr ra, s4, 0
+ sw a0, 0(s3)
+ addi s2, s2, -1
+ addi s1, s1, 4
+ addi s3, s3, 4
+ j concat_3
+concat_4:
+ mv a0, s5
+ lw s1, -12(fp)
+ lw s2, -16(fp)
+ lw s3, -20(fp)
+ lw s4, -24(fp)
+ lw s5, -28(fp)
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 32
+ jr ra
+concat_none:
+ j error.None
+
+
+.globl conslist
+conslist:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 0(fp)
+ la a0, $.list$prototype
+ beqz a1, conslist_done
+ addi a1, a1, @listHeaderWords
+ jal alloc2
+ lw t0, 0(fp)
+ sw t0, @.__len__(a0)
+ slli t1, t0, 2
+ add t1, t1, fp
+ addi t2, a0, @.__elts__
+conslist_1:
+ lw t3, 0(t1)
+ sw t3, 0(t2)
+ addi t1, t1, -4
+ addi t2, t2, 4
+ addi t0, t0, -1
+ bnez t0, conslist_1
+conslist_done:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strcat
+strcat:
+
+ addi sp, sp, -12
+ sw ra, 8(sp)
+ sw fp, 4(sp)
+ addi fp, sp, 12
+ lw t0, 4(fp)
+ lw t1, 0(fp)
+ lw t0, @.__len__(t0)
+ beqz t0, strcat_4
+ lw t1, @.__len__(t1)
+ beqz t1, strcat_5
+ add t1, t0, t1
+ sw t1, -12(fp)
+ addi t1, t1, 4
+ srli t1, t1, 2
+ addi a1, t1, @listHeaderWords
+ la a0, $str$prototype
+ jal alloc2
+ lw t0, -12(fp)
+ sw t0, @.__len__(a0)
+ addi t2, a0, 16
+ lw t0, 4(fp)
+ lw t1, @.__len__(t0)
+ addi t0, t0, @.__str__
+strcat_1:
+ beqz t1, strcat_2
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_1
+strcat_2:
+ lw t0, 0(fp)
+ lw t1, 12(t0)
+ addi t0, t0, 16
+strcat_3:
+ beqz t1, strcat_6
+ lbu t3, 0(t0)
+ sb t3, 0(t2)
+ addi t1, t1, -1
+ addi t0, t0, 1
+ addi t2, t2, 1
+ j strcat_3
+strcat_4:
+ lw a0, 0(fp)
+ j strcat_7
+strcat_5:
+ lw a0, 4(fp)
+ j strcat_7
+strcat_6:
+ sb zero, 0(t2)
+strcat_7:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 12
+ jr ra
+
+
+.globl streql
+streql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, streql_no
+streql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, streql_no
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, streql_1
+ li a0, 1
+ j streql_end
+streql_no:
+ xor a0, a0, a0
+streql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl strneql
+strneql:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw fp, 0(sp)
+ addi fp, sp, 8
+ lw a1, 4(fp)
+ lw a2, 0(fp)
+ lw t0, @.__len__(a1)
+ lw t1, @.__len__(a2)
+ bne t0, t1, strneql_yes
+strneql_1:
+ lbu t2, @.__str__(a1)
+ lbu t3, @.__str__(a2)
+ bne t2, t3, strneql_yes
+ addi a1, a1, 1
+ addi a2, a2, 1
+ addi t0, t0, -1
+ bgtz t0, strneql_1
+ xor a0, a0, a0
+ j strneql_end
+strneql_yes:
+ li a0, 1
+strneql_end:
+ lw ra, -4(fp)
+ lw fp, -8(fp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makeint
+makeint:
+
+ addi sp, sp, -8
+ sw ra, 4(sp)
+ sw a0, 0(sp)
+ la a0, $int$prototype
+ jal ra, alloc
+ lw t0, 0(sp)
+ sw t0, @.__int__(a0)
+ lw ra, 4(sp)
+ addi sp, sp, 8
+ jr ra
+
+
+.globl makebool
+makebool:
+
+ slli a0, a0, 4
+ la t0, @bool.False
+ add a0, a0, t0
+ jr ra
+
+
+.globl noconv
+noconv:
+
+ jr ra
+
+
+.globl initchars
+initchars:
+
+ jr ra
+
+
+.globl error.None
+error.None:
+ li a0, 4 # Exit code for: Operation on None
+ la a1, const_7 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.Div
+error.Div:
+ li a0, 2 # Exit code for: Division by zero
+ la a1, const_8 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.globl error.OOB
+error.OOB:
+ li a0, 3 # Exit code for: Index out of bounds
+ la a1, const_9 # Load error message as str
+ addi a1, a1, 16 # Load address of attribute __str__
+ j abort # Abort
+
+.data
+
+.globl const_0
+const_0:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 0 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_1
+const_1:
+ .word 2 # Type tag for class: bool
+ .word 4 # Object size
+ .word $bool$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __bool__
+ .align 2
+
+.globl const_8
+const_8:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Division by zero" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_6
+const_6:
+ .word 3 # Type tag for class: str
+ .word 8 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 13 # Constant value of attribute: __len__
+ .string "Out of memory" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_9
+const_9:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 19 # Constant value of attribute: __len__
+ .string "Index out of bounds" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_4
+const_4:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 4 # Constant value of attribute: __len__
+ .string "True" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_7
+const_7:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 17 # Constant value of attribute: __len__
+ .string "Operation on None" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_3
+const_3:
+ .word 3 # Type tag for class: str
+ .word 9 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 16 # Constant value of attribute: __len__
+ .string "Invalid argument" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_5
+const_5:
+ .word 3 # Type tag for class: str
+ .word 6 # Object size
+ .word $str$dispatchTable # Pointer to dispatch table
+ .word 5 # Constant value of attribute: __len__
+ .string "False" # Constant value of attribute: __str__
+ .align 2
+
+.globl const_2
+const_2:
+ .word 1 # Type tag for class: int
+ .word 4 # Object size
+ .word $int$dispatchTable # Pointer to dispatch table
+ .word 1 # Constant value of attribute: __int__
+ .align 2
diff --git a/web/WebCompiler.py.ast b/web/WebCompiler.py.ast
new file mode 100644
index 0000000..e69de29