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)
Beispiel #3
0
 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)
Beispiel #5
0
 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))
Beispiel #6
0
    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)
Beispiel #8
0
 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)
Beispiel #9
0
 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())
Beispiel #15
0
 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())
Beispiel #18
0
    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(')')
Beispiel #19
0
    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())
Beispiel #20
0
    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)
Beispiel #21
0
    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())
Beispiel #22
0
 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)
Beispiel #24
0
 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())