def generate_code(self, code_builder: OpCodeBuilder): self.expr.generate_code(code_builder) code = { UnaryOpType.Min: codes.Neg(), UnaryOpType.Neg: codes.Not(), }.get(self.op_type) assert code is not None, 'Unknown unary operator' code_builder.add(code)
def generate_code(self, code_builder: OpCodeBuilder): while_label = code_builder.fresh_label() end_label = code_builder.fresh_label() code_builder.mark(while_label) self.expression.generate_code(code_builder) code_builder.add(codes.BrFalse(end_label)) self.body.generate_code(code_builder) code_builder.add(codes.Br(while_label)) code_builder.mark(end_label)
def initialize_globals(self, code_builder: OpCodeBuilder): for decl in self.spl_file.declarations: # Extra iteration over decls to add globals to context if isinstance(decl, VarDecl): code_builder.get_global(decl.id_number) for decl in self.spl_file.declarations: if isinstance(decl, VarDecl): assert decl.id_number is not None, 'Var declaration ID should be set during binding analysis' decl.expression.generate_code(code_builder) glob = code_builder.get_global(decl.id_number) code_builder.add(codes.StGlob(glob))
def generate_code(self, code_builder: OpCodeBuilder): end_label = code_builder.fresh_label() else_label = code_builder.fresh_label( ) if self.else_block is not None else end_label self.expression.generate_code(code_builder) code_builder.add(codes.BrFalse(else_label)) self.then_block.generate_code(code_builder) if self.else_block is not None: code_builder.add(codes.Br(end_label)) code_builder.mark(else_label) self.else_block.generate_code(code_builder) code_builder.mark(end_label)
def generate_storage_code(self, code_builder: OpCodeBuilder): if code_builder.is_global(self.id_number): glob = code_builder.get_global(self.id_number) code_builder.add(codes.StGlob(glob)) else: loc = code_builder.get_local(self.id_number) code_builder.add(codes.StLoc(loc))
def generate_code(self, arg_types: List[uni.InferenceType], code_builder: OpCodeBuilder): assert len( arg_types ) == 1, f'len function needs 1 argument, {len(arg_types)} where given' t = arg_types[0] assert isinstance(t, uni.InferenceList), f'Error during code generation of {self.name}: ' \ f'expects argument of type list, but type {t} was given' arg = gen_utils.Local(-1) code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.PushConst(0)) code_builder.add(codes.Eq()) code_builder.add(codes.Ret())
def generate_code(self, code_builder: OpCodeBuilder): self.expr1.generate_code(code_builder) self.expr2.generate_code(code_builder) if self.op_type is BinaryOpType.Eq or self.op_type is BinaryOpType.Neq or self.op_type is BinaryOpType.Add: t1, t2 = code_builder.get_type(self.expr1), code_builder.get_type(self.expr2) subst = t1.unify(t2) # To handle cases with empty list t1, t2 = t1.substitute(subst), t2.substitute(subst) if self.op_type is BinaryOpType.Eq: code = codes.Eq() name = '__refeq' elif self.op_type is BinaryOpType.Neq: code = codes.Ne() name = '__neq' # TODO elif self.op_type is BinaryOpType.Add: if isinstance(t1, InferenceBool) or isinstance(t1, InferenceTuple): raise NoFunctionInstanceError('__add', [t1, t2]) code = codes.Add() name = '__add' if t1.is_scalar() and t2.is_scalar(): # If scalar, compare directly with appropriate instruction code_builder.add(code) else: # Else call custom equality testing function code_builder.add_call( fun_name=name, arg_types=[t1, t2], hide=True ) else: code = { BinaryOpType.Add: codes.Add(), BinaryOpType.Sub: codes.Sub(), BinaryOpType.Mul: codes.Mul(), BinaryOpType.Div: codes.Div(), BinaryOpType.Lt: codes.Lt(), BinaryOpType.Leq: codes.Le(), BinaryOpType.Geq: codes.Ge(), BinaryOpType.Gt: codes.Gt(), BinaryOpType.Mod: codes.Mod(), BinaryOpType.And: codes.And(), BinaryOpType.Or: codes.Or(), BinaryOpType.Cons: codes.CreateListCons(), }.get(self.op_type) assert code is not None, 'Unknown binary operator' code_builder.add(code)
def initialize(self): code_builder = OpCodeBuilder(self.context, self.env) main = gen_utils.FunctionInstance('main', []) self.initialize_globals(code_builder) code_builder.add_call(main.name, main.arg_types) code_builder.add(codes.Halt()) init = gen_utils.FunctionInstance('init', [], hide_from_user=True, entry_point=True) self.functions.append((init, gen_utils.FunctionImpl(code_builder.ops))) self.context.require_fun_instance(main)
def generate_function_impls(self): while len(self.context.needed_fun_instances) > 0: fun_key, fun_inst = self.context.needed_fun_instances.popitem() if fun_key in self.processed_instances: continue # Already generated code code_builder = OpCodeBuilder(self.context, copy.deepcopy( self.env)) # Deep copy env for polymorphic funcs if (fun_decl := self.function_asts.get(fun_inst.name, None)) is not None: # Check argument types subst = Subst.empty() for arg_id, arg_type in zip(fun_decl.arg_ids, fun_inst.arg_types): current = code_builder.env.get_var(arg_id) subst = current.substitute(subst).unify(arg_type).compose( subst) code_builder.env.substitute(subst) # Initialize args as local vars num_args = len(fun_decl.arg_ids) for i, arg_id in enumerate(fun_decl.arg_ids): code_builder.add_local(arg_id, -num_args + i) fun_decl.block.generate_code(code_builder) else: # Check builtins builtin = None for b in self.builtins: if b.name == fun_inst.name: builtin = b if builtin is not None: builtin.generate_code(fun_inst.arg_types, code_builder) else: raise Exception( f'Unknown function \'{fun_inst.name}\' encountered while generating code' ) if not code_builder.ends_with_return(): code_builder.add(codes.RetNoValue( )) # Add return if function doesn't end with return stmt self.functions.append( (fun_inst, gen_utils.FunctionImpl(code_builder.ops))) self.processed_instances.add(fun_key)
def generate_code(self, code_builder: OpCodeBuilder): self.fst.generate_code(code_builder) self.snd.generate_code(code_builder) code_builder.add(codes.CreateTuple())
def generate_code(self, code_builder: OpCodeBuilder): code_builder.add(codes.CreateListNil())
def generate_code(self, code_builder: OpCodeBuilder): if self.value: code_builder.add(codes.PushConst(-1)) # True is encoded as -1 else: code_builder.add(codes.PushConst(0)) # False is encoded as 0
def generate_code(self, code_builder: OpCodeBuilder): code_builder.add(codes.PushConst(ord(self.value)))
def generate_code(self, code_builder: OpCodeBuilder): for c in self.value: code_builder.add(codes.PushConst(ord(c))) code_builder.add(codes.CreateListNil()) for c in self.value: code_builder.add(codes.CreateListCons())
def generate_code(self, code_builder: OpCodeBuilder): self.field.generate_code(code_builder) code_builder.add(codes.LdFld(self.field_type))
def generate_code(self, code_builder: OpCodeBuilder): if isinstance(self.declaration, decl.VarDecl): self.declaration.expression.generate_code(code_builder) loc = code_builder.get_local(self.declaration.id_number) code_builder.add(codes.StLoc(loc))
def generate_code(self, code_builder: OpCodeBuilder): if self.expression is None: code_builder.add(codes.RetNoValue()) else: self.expression.generate_code(code_builder) code_builder.add(codes.Ret())
def generate_code(self, arg_types: List[uni.InferenceType], code_builder: OpCodeBuilder): arg = gen_utils.Local(-1) assert len(arg_types) == 1, \ f'Error during code generation of \'{self.name}\': ' \ f'expected {self.num_args} argument but found {len(arg_types)}' arg_type = arg_types[0] assert not isinstance(arg_type, uni.InferenceTypeVar) and not isinstance(arg_type, uni.InferenceVoid), \ f'Error during code generation: could not generate {self.name} code for type {arg_type}' if isinstance(arg_type, uni.InferenceInt): code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.PrintInt()) if isinstance(arg_type, uni.InferenceBool): false_label = code_builder.fresh_label() end_label = code_builder.fresh_label() code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.BrFalse(false_label)) code_builder.add_print_str('True') code_builder.add(codes.Br(end_label)) code_builder.mark(false_label) code_builder.add_print_str('False') code_builder.mark(end_label) if isinstance(arg_type, uni.InferenceChar): code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.PrintChar()) if isinstance(arg_type, uni.InferenceList): null_label = code_builder.fresh_label() end_label = code_builder.fresh_label() code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.BrFalse(null_label)) if isinstance(arg_type.t, uni.InferenceTypeVar): code_builder.add_print_str('Error: type var list has contents') code_builder.add(codes.Halt()) else: code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.LdFld(FieldType.Hd)) code_builder.add_call(self.name, [arg_type.t]) code_builder.add(codes.Pop()) # If not a str (list of char), then print cons operator in between if not isinstance(arg_type.t, uni.InferenceChar): code_builder.add_print_str(' : ') code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.LdFld(FieldType.Tl)) code_builder.add_call(self.name, [uni.InferenceList(arg_type.t)]) code_builder.add(codes.Pop()) code_builder.add(codes.Br(end_label)) code_builder.mark(null_label) # End with empty list [] if not str if not isinstance(arg_type.t, uni.InferenceChar): code_builder.add_print_str('[]') code_builder.mark(end_label) if isinstance(arg_type, uni.InferenceTuple): code_builder.add_print_str('(') code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.LdFld(FieldType.Fst)) code_builder.add_call(self.name, [arg_type.t1]) code_builder.add(codes.Pop()) code_builder.add_print_str(', ') code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.LdFld(FieldType.Snd)) code_builder.add_call(self.name, [arg_type.t2]) code_builder.add(codes.Pop()) code_builder.add_print_str(')')
def generate_code(self, arg_types: List[uni.InferenceType], code_builder: OpCodeBuilder): assert len(arg_types) == 2, \ f'Error during code generation of \'{self.name}\': ' \ f'expected {self.num_args} arguments but found {len(arg_types)}' t1 = arg_types[0] t2 = arg_types[1] assert t1.is_equal(t2) or \ (isinstance(t1, uni.InferenceList) and isinstance(t1.t, uni.InferenceTypeVar) and isinstance(t2, uni.InferenceList) and isinstance(t2.t, uni.InferenceTypeVar)), \ f'Error during code generation: {self.name} expects both arguments to be of the same type' assert not isinstance(t1, uni.InferenceVoid), \ f'Error during code generation: could not generate {self.name} code for type {t1}' arg1 = gen_utils.Local(-1) arg2 = gen_utils.Local(-2) if isinstance(t1, uni.InferenceInt) or isinstance(t1, uni.InferenceBool) or isinstance(t1, uni.InferenceChar): code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.LdLoc(arg2)) code_builder.add(codes.Eq()) code_builder.add(codes.Ret()) elif isinstance(t1, uni.InferenceList): null_label = code_builder.fresh_label() false_label = code_builder.fresh_label() code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.BrFalse(null_label)) if isinstance(t1.t, uni.InferenceTypeVar): code_builder.add_print_str('Error: type var list has contents') code_builder.add(codes.Halt()) else: code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.LdFld(FieldType.Hd)) code_builder.add(codes.LdLoc(arg2)) code_builder.add(codes.LdFld(FieldType.Hd)) code_builder.add_call(self.name, [t1.t, t1.t]) code_builder.add(codes.BrFalse(false_label)) code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.LdFld(FieldType.Tl)) code_builder.add(codes.LdLoc(arg2)) code_builder.add(codes.LdFld(FieldType.Tl)) tail = uni.InferenceList(t1.t) code_builder.add_call(self.name, [tail, tail]) code_builder.add(codes.Ret()) code_builder.mark(null_label) code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.LdLoc(arg2)) code_builder.add(codes.Eq()) code_builder.add(codes.Ret()) code_builder.mark(false_label) code_builder.add(codes.PushConst(0)) code_builder.add(codes.Ret()) elif isinstance(t1, uni.InferenceTuple): false_label = code_builder.fresh_label() code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.LdFld(FieldType.Fst)) code_builder.add(codes.LdLoc(arg2)) code_builder.add(codes.LdFld(FieldType.Fst)) code_builder.add_call(self.name, [t1.t1, t1.t1]) code_builder.add(codes.BrFalse(false_label)) code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.LdFld(FieldType.Snd)) code_builder.add(codes.LdLoc(arg2)) code_builder.add(codes.LdFld(FieldType.Snd)) code_builder.add_call(self.name, [t1.t2, t1.t2]) code_builder.add(codes.Ret()) code_builder.mark(false_label) code_builder.add(codes.PushConst(0)) code_builder.add(codes.Ret())
def generate_code(self, arg_types: List[uni.InferenceType], code_builder: OpCodeBuilder): assert len(arg_types) == 2, \ f'Error during code generation of \'{self.name}\': ' \ f'expected {self.num_args} arguments but found {len(arg_types)}' t1, t2 = arg_types[0], arg_types[1] assert t1.is_equal(t2) or \ (isinstance(t1, uni.InferenceList) and isinstance(t1.t, uni.InferenceTypeVar) and isinstance(t2, uni.InferenceList) and isinstance(t2.t, uni.InferenceTypeVar)), \ f'Error during code generation: {self.name} expects both arguments to be of the same type' assert not isinstance(t1, uni.InferenceVoid), \ f'Error during code generation: could not generate {self.name} code for type {t1}' arg1 = gen_utils.Local(-2) arg2 = gen_utils.Local(-1) if isinstance(t1, uni.InferenceInt) or isinstance( t1, uni.InferenceChar): code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.LdLoc(arg2)) code_builder.add(codes.Add()) code_builder.add(codes.Ret()) elif isinstance(t1, uni.InferenceList): null_label_1 = code_builder.fresh_label() null_label_2 = code_builder.fresh_label() code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.BrFalse(null_label_1)) code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.LdFld(FieldType.Hd)) code_builder.add(codes.LdLoc(arg1)) code_builder.add(codes.LdFld(FieldType.Tl)) code_builder.add(codes.LdLoc(arg2)) code_builder.add_call(self.name, [t1, t1], hide=True) code_builder.add(codes.CreateListCons()) code_builder.add(codes.Ret()) code_builder.mark(null_label_1) code_builder.add(codes.LdLoc(arg2)) code_builder.add(codes.BrFalse(null_label_2)) if isinstance(t2.t, uni.InferenceTypeVar): code_builder.add_print_str('Error: type var list has contents') code_builder.add(codes.Halt()) code_builder.add(codes.LdLoc(arg2)) code_builder.add(codes.LdFld(FieldType.Hd)) code_builder.add(codes.PushConst(0)) code_builder.add(codes.LdLoc(arg2)) code_builder.add(codes.LdFld(FieldType.Tl)) code_builder.add_call(self.name, [t1, t1], hide=True) code_builder.add(codes.CreateListCons()) code_builder.add(codes.Ret()) code_builder.mark(null_label_2) code_builder.add(codes.CreateListNil()) code_builder.add(codes.Ret()) elif isinstance(t1, uni.InferenceBool) or isinstance( t1, uni.InferenceTuple): raise NoFunctionInstanceError(self.name, arg_types)
def generate_code(self, arg_types: List[uni.InferenceType], code_builder: OpCodeBuilder): empty_label = code_builder.fresh_label() assert len( arg_types ) == 1, f'len function needs 1 argument, {len(arg_types)} where given' t = arg_types[0] assert isinstance(t, uni.InferenceList), f'Error during code generation of {self.name}: ' \ f'expects argument of type list, but type {t} was given' arg = gen_utils.Local(-1) code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.BrFalse(empty_label)) if isinstance(t.t, uni.InferenceTypeVar): code_builder.add_print_str('Error: type var list has contents') code_builder.add(codes.Halt()) code_builder.add(codes.LdLoc(arg)) code_builder.add(codes.LdFld(FieldType.Tl)) code_builder.add_call(self.name, [t]) code_builder.add(codes.PushConst(1)) code_builder.add(codes.Add()) code_builder.add(codes.Ret()) code_builder.mark(empty_label) code_builder.add(codes.PushConst(0)) code_builder.add(codes.Ret())
def generate_code(self, arg_types: List[uni.InferenceType], code_builder: OpCodeBuilder): code_builder.add(codes.LdLoc(gen_utils.Local(-1))) code_builder.add(codes.LdLoc(gen_utils.Local(-2))) code_builder.add(codes.Eq()) code_builder.add(codes.Ret())
def generate_code(self, code_builder: OpCodeBuilder): arg_types = [code_builder.get_type(e) for e in self.expressions] for e in self.expressions: e.generate_code(code_builder) code_builder.add_call(self.function_name.value, arg_types)
def generate_storage_code(self, code_builder: OpCodeBuilder): self.field.generate_code(code_builder) code_builder.add(codes.Swp()) code_builder.add(codes.StFld(self.field_type))
def generate_code(self, code_builder: OpCodeBuilder): self.expression.generate_code(code_builder) code_builder.add(codes.Pop())