def visit(self, node: COOL_AST.LetNode, scope): let_scope = scope.create_child() for var_name, var_type, var_expr in node.var_list: if var_expr is not None: var_expr_value = self.visit(var_expr, let_scope) else: instance = None if var_type in ['Int', 'Bool']: instance = self.define_internal_local(scope=let_scope, name="instance") self.register_instruction( CIL_AST.Allocate(var_type, self.context.get_type(var_type).tag, instance)) value = self.define_internal_local(scope=let_scope, name="value") self.register_instruction(CIL_AST.LoadInt(0, value)) result_init = self.define_internal_local(scope=let_scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, f'{var_type}_init', [CIL_AST.Arg(value), CIL_AST.Arg(instance)], var_type)) elif var_type == 'String': instance = self.define_internal_local(scope=let_scope, name="instance") self.register_instruction( CIL_AST.Allocate(var_type, self.context.get_type(var_type).tag, instance)) value = self.define_internal_local(scope=let_scope, name="value") self.register_instruction(CIL_AST.LoadStr('empty_str', value)) result_init = self.define_internal_local(scope=let_scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, f'{var_type}_init', [CIL_AST.Arg(value), CIL_AST.Arg(instance)], var_type)) var_expr_value = instance let_var = self.define_internal_local(scope=let_scope, name=var_name, cool_var_name=var_name) self.register_instruction(CIL_AST.Assign(let_var, var_expr_value)) body_value = self.visit(node.body, let_scope) result_local = self.define_internal_local(scope=scope, name="let_result") self.register_instruction(CIL_AST.Assign(result_local, body_value)) return result_local
def visit(self, node, scope): instance = None if node.type in ['Int', 'Bool']: instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate(node.type, self.context.get_type(node.type).tag, instance)) value = self.define_internal_local(scope=scope, name="value") self.register_instruction(CIL_AST.LoadInt(0, value)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, f'{node.type}_init', [CIL_AST.Arg(value), CIL_AST.Arg(instance)], node.type)) elif node.type == 'String': instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate(node.type, self.context.get_type(node.type).tag, instance)) value = self.define_internal_local(scope=scope, name="value") self.register_instruction(CIL_AST.LoadStr('empty_str', value)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, f'{node.type}_init', [CIL_AST.Arg(value), CIL_AST.Arg(instance)], node.type)) if node.val is None: self.register_instruction(CIL_AST.SetAttr('self', node.id, instance, self.current_type.name)) else: expr = self.visit(node.val, scope) self.register_instruction(CIL_AST.SetAttr('self', node.id, expr, self.current_type.name))
def visit(self, node, scope=None): scope = Scope() self.current_function = self.register_function('main') instance = self.define_internal_local(scope=scope, name="instance") result = self.define_internal_local(scope=scope, name="result") self.register_instruction(CIL_AST.Allocate('Main', self.context.get_type('Main').tag, instance)) self.register_instruction(CIL_AST.Call(result, 'Main_init', [CIL_AST.Arg(instance)], "Main")) self.register_instruction( CIL_AST.Call(result, self.to_function_name('main', 'Main'), [CIL_AST.Arg(instance)], "Main")) self.register_instruction(CIL_AST.Return(None)) self.current_function = None self.register_data('Abort called from class ') self.register_data('\n') self.dotdata['empty_str'] = '' # Add built-in types in .TYPES section self.register_builtin_types(scope) # Add string equals function self.build_string_equals_function(scope) for klass in node.declarations: self.visit(klass, scope.create_child()) return CIL_AST.Program(self.dottypes, self.dotdata, self.dotcode)
def visit(self, node: COOL_AST.InstantiateNode, scope): result_local = self.define_internal_local(scope=scope, name="result") result_init = self.define_internal_local(scope=scope, name="init") if node.lex == "SELF_TYPE": self.register_instruction(CIL_AST.Allocate(self.current_type.name, self.current_type.tag, result_local)) self.register_instruction( CIL_AST.Call(result_init, f'{self.current_type.name}_init', [result_local], self.current_type.name)) else: self.register_instruction(CIL_AST.Allocate(node.lex, self.context.get_type(node.lex).tag, result_local)) self.register_instruction( CIL_AST.Call(result_init, f'{node.lex}_init', [CIL_AST.Arg(result_local)], self.current_type.name)) return result_local
def visit(self, node: COOL_AST.ArithBinaryNode, scope): result_local = self.define_internal_local(scope=scope, name="result") op_local = self.define_internal_local(scope=scope, name="op") left_local = self.define_internal_local(scope=scope, name="left") right_local = self.define_internal_local(scope=scope, name="right") left_value = self.visit(node.left, scope) right_value = self.visit(node.right, scope) self.register_instruction(CIL_AST.GetAttr(left_local, left_value, "value", node.left.computed_type.name)) self.register_instruction(CIL_AST.GetAttr(right_local, right_value, "value", node.right.computed_type.name)) if isinstance(node, COOL_AST.PlusNode): self.register_instruction(CIL_AST.BinaryOperator(op_local, left_local, right_local, "+")) elif isinstance(node, COOL_AST.MinusNode): self.register_instruction(CIL_AST.BinaryOperator(op_local, left_local, right_local, "-")) elif isinstance(node, COOL_AST.StarNode): self.register_instruction(CIL_AST.BinaryOperator(op_local, left_local, right_local, "*")) elif isinstance(node, COOL_AST.DivNode): self.register_instruction(CIL_AST.BinaryOperator(op_local, left_local, right_local, "/")) # Allocate Int result self.register_instruction(CIL_AST.Allocate('Int', self.context.get_type('Int').tag, result_local)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'Int_init', [CIL_AST.Arg(op_local), CIL_AST.Arg(result_local)], "Int")) return result_local
def visit(self, node, scope): self.current_type = self.context.get_type(node.id) # Handle all the .TYPE section cil_type = self.register_type(self.current_type.name) cil_type.attributes = [f'{attr.name}' for c, attr in self.current_type.get_all_attributes()] cil_type.methods = {f'{m}': f'{c}.{m}' for c, m in self.current_type.get_all_methods()} scope.define_cil_local("self", self.current_type.name, self.current_type) func_declarations = [f for f in node.features if isinstance(f, COOL_AST.ClassDeclarationNode)] attr_declarations = [a for a in node.features if isinstance(a, COOL_AST.AttrDeclarationNode)] for attr in attr_declarations: scope.define_cil_local(attr.id, attr.id, node.id) # -------------------------Init--------------------------------- self.current_function = self.register_function(f'{node.id}_init') self.register_param(VariableInfo('self', None)) # Init parents recursively result = self.define_internal_local(scope=scope, name="result") self.register_instruction(CIL_AST.Call(result, f'{node.parent}_init', [CIL_AST.Arg('self')], node.parent)) self.register_instruction(CIL_AST.Return(None)) for attr in attr_declarations: self.visit(attr, scope) # --------------------------------------------------------------- self.current_function = None for feature in func_declarations: self.visit(feature, scope.create_child()) self.current_type = None
def visit(self, node: COOL_AST.ConstantNumNode, scope): instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate('Int', self.context.get_type('Int').tag, instance)) value = self.define_internal_local(scope=scope, name="value") self.register_instruction(CIL_AST.LoadInt(node.lex, value)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'Int_init', [CIL_AST.Arg(value), CIL_AST.Arg(instance)], "Int")) return instance
def visit(self, node: COOL_AST.IsVoidNode, scope): expre_value = self.visit(node.expr, scope) result_local = self.define_internal_local(scope=scope, name="isvoid_result") self.register_instruction(CIL_AST.IsVoid(result_local, expre_value)) instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate('Bool', self.context.get_type('Bool').tag, instance)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'Bool_init', [CIL_AST.Arg(result_local), CIL_AST.Arg(instance)], "Bool")) return instance
def visit(self, node: COOL_AST.BoolNode, scope): boolean = 0 if str(node.lex) == "True": boolean = 1 instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate('Bool', self.context.get_type('Bool').tag, instance)) value = self.define_internal_local(scope=scope, name="value") self.register_instruction(CIL_AST.LoadInt(boolean, value)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'Bool_init', [CIL_AST.Arg(value), CIL_AST.Arg(instance)], "Bool")) return instance
def visit(self, node: COOL_AST.BooleanBinaryNode, scope): result_local = self.define_internal_local(scope=scope, name="result") op_local = self.define_internal_local(scope=scope, name="op") left_local = self.define_internal_local(scope=scope, name="left") right_local = self.define_internal_local(scope=scope, name="right") left_value = self.visit(node.left, scope) right_value = self.visit(node.right, scope) self.register_instruction(CIL_AST.GetAttr(left_local, left_value, "value", node.left.computed_type.name)) self.register_instruction(CIL_AST.GetAttr(right_local, right_value, "value", node.right.computed_type.name)) if isinstance(node, COOL_AST.LessNode): self.register_instruction(CIL_AST.BinaryOperator(op_local, left_local, right_local, "<")) elif isinstance(node, COOL_AST.LessNode): self.register_instruction(CIL_AST.BinaryOperator(op_local, left_local, right_local, "<=")) elif isinstance(node, COOL_AST.EqualNode): if node.left.computed_type.name == 'String': self.register_instruction( CIL_AST.Call(op_local, 'String_equals', [CIL_AST.Arg(right_value), CIL_AST.Arg(left_value)], 'String')) elif node.left.computed_type.name in ['Int', 'Bool']: self.register_instruction( CIL_AST.GetAttr(left_local, left_value, "value", node.left.computed_type.name)) self.register_instruction( CIL_AST.GetAttr(right_local, right_value, "value", node.right.computed_type.name)) else: self.register_instruction(CIL_AST.Assign(left_local, left_value)) self.register_instruction(CIL_AST.Assign(right_local, right_value)) self.register_instruction(CIL_AST.BinaryOperator(op_local, left_local, right_local, "=")) # Allocate Bool result self.register_instruction(CIL_AST.Allocate('Bool', self.context.get_type('Bool').tag, result_local)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'Bool_init', [CIL_AST.Arg(op_local), CIL_AST.Arg(result_local)], "Bool")) return result_local
def visit(self, node: COOL_AST.StringNode, scope): str_name = "" for s in self.dotdata.keys(): if self.dotdata[s] == node.lex: str_name = s break if str_name == "": str_name = self.register_data(node.lex) result_local = self.define_internal_local(scope=scope) self.register_instruction(CIL_AST.LoadStr(str_name, result_local)) instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate('String', self.context.get_type('String').tag, instance)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'String_init', [CIL_AST.Arg(result_local), CIL_AST.Arg(instance)], "String")) return instance
def visit(self, node: COOL_AST.NotNode, scope): result_local = self.define_internal_local(scope=scope, name="result") op_local = self.define_internal_local(scope=scope, name="op") expr_local = self.define_internal_local(scope=scope) expr_value = self.visit(node.expr, scope) self.register_instruction(CIL_AST.GetAttr(expr_local, expr_value, "value", node.expr.computed_type.name)) self.register_instruction(CIL_AST.UnaryOperator(op_local, expr_local, "not")) # Allocate Bool result self.register_instruction(CIL_AST.Allocate('Bool', self.context.get_type('Bool').tag, result_local)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'Bool_init', [CIL_AST.Arg(op_local), CIL_AST.Arg(result_local)], "Bool")) return result_local
def register_builtin_types(self, scope): for t in ['Object', 'Int', 'String', 'Bool', 'IO']: builtin_type = self.context.get_type(t) cil_type = self.register_type(t) cil_type.attributes = [f'{attr.name}' for attr in builtin_type.attributes] cil_type.methods = {f'{m}': f'{c}.{m}' for c, m in builtin_type.get_all_methods()} if t in ['Int', 'String', 'Bool']: cil_type.attributes.append('value') # ----------------Object--------------------- # init self.current_function = self.register_function('Object_init') self.register_param(VariableInfo('self', None)) self.register_instruction(CIL_AST.Return(None)) # abort self.current_function = self.register_function(self.to_function_name('abort', 'Object')) self.register_param(VariableInfo('self', None)) msg = self.define_internal_local(scope=scope, name="msg") key_msg = '' for s in self.dotdata.keys(): if self.dotdata[s] == 'Abort called from class ': key_msg = s self.register_instruction(CIL_AST.LoadStr(key_msg, msg)) self.register_instruction(CIL_AST.PrintString(msg)) type_name = self.define_internal_local(scope=scope, name="type_name") self.register_instruction(CIL_AST.TypeOf('self', type_name)) self.register_instruction(CIL_AST.PrintString(type_name)) eol_local = self.define_internal_local(scope=scope, name="eol") for s in self.dotdata.keys(): if self.dotdata[s] == '\n': eol = s self.register_instruction(CIL_AST.LoadStr(eol, eol_local)) self.register_instruction(CIL_AST.PrintString(eol_local)) self.register_instruction(CIL_AST.Halt()) # type_name self.current_function = self.register_function(self.to_function_name('type_name', 'Object')) self.register_param(VariableInfo('self', None)) type_name = self.define_internal_local(scope=scope, name="type_name") self.register_instruction(CIL_AST.TypeOf('self', type_name)) instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate('String', self.context.get_type('String').tag, instance)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'String_init', [CIL_AST.Arg(type_name), CIL_AST.Arg(instance)], "String")) self.register_instruction(CIL_AST.Return(instance)) # copy self.current_function = self.register_function(self.to_function_name('copy', 'Object')) self.register_param(VariableInfo('self', None)) copy = self.define_internal_local(scope=scope, name="copy") self.register_instruction(CIL_AST.Copy('self', copy)) self.register_instruction(CIL_AST.Return(copy)) # ----------------IO--------------------- # init self.current_function = self.register_function('IO_init') self.register_param(VariableInfo('self', None)) self.register_instruction(CIL_AST.Return(None)) # out_string self.current_function = self.register_function(self.to_function_name('out_string', 'IO')) self.register_param(VariableInfo('self', None)) self.register_param(VariableInfo('x', None)) v = self.define_internal_local(scope=scope, name="v") self.register_instruction(CIL_AST.GetAttr(v, 'x', 'value', 'String')) self.register_instruction(CIL_AST.PrintString(v)) self.register_instruction(CIL_AST.Return('self')) # out_int self.current_function = self.register_function(self.to_function_name('out_int', 'IO')) self.register_param(VariableInfo('self', None)) self.register_param(VariableInfo('x', None)) v = self.define_internal_local(scope=scope, name="v") self.register_instruction(CIL_AST.GetAttr(v, 'x', 'value', 'Int')) self.register_instruction(CIL_AST.PrintInteger(v)) self.register_instruction(CIL_AST.Return('self')) # in_string self.current_function = self.register_function(self.to_function_name('in_string', 'IO')) self.register_param(VariableInfo('self', None)) msg = self.define_internal_local(scope=scope, name="read_str") self.register_instruction(CIL_AST.ReadString(msg)) instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate('String', self.context.get_type('String').tag, instance)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'String_init', [CIL_AST.Arg(msg), CIL_AST.Arg(instance)], "String")) self.register_instruction(CIL_AST.Return(instance)) # in_int self.current_function = self.register_function(self.to_function_name('in_int', 'IO')) self.register_param(VariableInfo('self', None)) number = self.define_internal_local(scope=scope, name="read_int") self.register_instruction(CIL_AST.ReadInteger(number)) instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate('Int', self.context.get_type('Int').tag, instance)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'Int_init', [CIL_AST.Arg(number), CIL_AST.Arg(instance)], "Int")) self.register_instruction(CIL_AST.Return(instance)) # ----------------String--------------------- # init self.current_function = self.register_function('String_init') self.register_param(VariableInfo('self', None)) self.register_param(VariableInfo('v', None)) self.register_instruction(CIL_AST.SetAttr('self', 'value', 'v', 'String')) self.register_instruction(CIL_AST.Return(None)) # length self.current_function = self.register_function(self.to_function_name('length', 'String')) self.register_param(VariableInfo('self', None)) length_result = self.define_internal_local(scope=scope, name="length") self.register_instruction(CIL_AST.Length('self', length_result)) instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate('Int', self.context.get_type('Int').tag, instance)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'Int_init', [CIL_AST.Arg(length_result), CIL_AST.Arg(instance)], "Int")) self.register_instruction(CIL_AST.Return(instance)) # concat self.current_function = self.register_function(self.to_function_name('concat', 'String')) self.register_param(VariableInfo('self', None)) self.register_param(VariableInfo('s', None)) str1 = self.define_internal_local(scope=scope, name="str1") self.register_instruction(CIL_AST.GetAttr(str1, 'self', 'value', 'String')) len1 = self.define_internal_local(scope=scope, name="len1") self.register_instruction(CIL_AST.Call(len1, 'String.length', [CIL_AST.Arg('self')], 'String')) str2 = self.define_internal_local(scope=scope, name="str2") self.register_instruction(CIL_AST.GetAttr(str2, 's', 'value', 'String')) len2 = self.define_internal_local(scope=scope, name="len2") self.register_instruction(CIL_AST.Call(len2, 'String.length', [CIL_AST.Arg('s')], 'String')) local_len1 = self.define_internal_local(scope=scope, name="local_len1") self.register_instruction(CIL_AST.GetAttr(local_len1, len1, 'value', 'Int')) local_len2 = self.define_internal_local(scope=scope, name="local_len2") self.register_instruction(CIL_AST.GetAttr(local_len2, len2, 'value', 'Int')) concat_result = self.define_internal_local(scope=scope, name="concat") self.register_instruction(CIL_AST.Concat(str1, local_len1, str2, local_len2, concat_result)) instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate('String', self.context.get_type('String').tag, instance)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'String_init', [CIL_AST.Arg(concat_result), CIL_AST.Arg(instance)], "String")) self.register_instruction(CIL_AST.Return(instance)) # substr self.current_function = self.register_function(self.to_function_name('substr', 'String')) self.register_param(VariableInfo('self', None)) self.register_param(VariableInfo('i', None)) self.register_param(VariableInfo('l', None)) i_value = self.define_internal_local(scope=scope, name="i_value") self.register_instruction(CIL_AST.GetAttr(i_value, 'i', 'value', 'Int')) l_value = self.define_internal_local(scope=scope, name="l_value") self.register_instruction(CIL_AST.GetAttr(l_value, 'l', 'value', 'Int')) subs_result = self.define_internal_local(scope=scope, name="subs_result") self.register_instruction(CIL_AST.SubStr(i_value, l_value, 'self', subs_result)) instance = self.define_internal_local(scope=scope, name="instance") self.register_instruction(CIL_AST.Allocate('String', self.context.get_type('String').tag, instance)) result_init = self.define_internal_local(scope=scope, name="result_init") self.register_instruction( CIL_AST.Call(result_init, 'String_init', [CIL_AST.Arg(subs_result), CIL_AST.Arg(instance)], "String")) self.register_instruction(CIL_AST.Return(instance)) # ----------------Bool--------------------- # init self.current_function = self.register_function('Bool_init') self.register_param(VariableInfo('self', None)) self.register_param(VariableInfo('v', None)) self.register_instruction(CIL_AST.SetAttr('self', 'value', 'v', 'Bool')) self.register_instruction(CIL_AST.Return(None)) # ----------------Int--------------------- # init self.current_function = self.register_function('Int_init') self.register_param(VariableInfo('self', None)) self.register_param(VariableInfo('v', None)) self.register_instruction(CIL_AST.SetAttr('self', 'value', 'v', 'Int')) self.register_instruction(CIL_AST.Return(None))