コード例 #1
0
ファイル: Len.py プロジェクト: davidkerkkamp/spl-compiler
    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())
コード例 #2
0
ファイル: Add.py プロジェクト: davidkerkkamp/spl-compiler
    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)
コード例 #3
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)
コード例 #4
0
    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)
コード例 #5
0
 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)
コード例 #6
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())
コード例 #7
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(')')