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): 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 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_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 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_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): 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(')')