Пример #1
0
 def generate_code(self):
     self.body = ""
     self.in_try_block = False
     self.indent = 4
     self.retval = Code(tp=None, code="_retval", is_pointer=True)
     self.all_paths_return = False
     self.context.clear_temp_vars()
     # clear struct if class init
     if self.is_init():
         self.start_line(f"*self = ({self.args[0].tp.c_type}){{0}};\n")
     for n in self.primary_node.body:
         self.visit(n)
     if not self.all_paths_return:
         self.retval.assign_type(TypeDB.get_type_by_value(None),
                                 " as return value")
Пример #2
0
 def get_attr_code(self, attr: str, obj: Code) -> Code:
     if attr in self.cls.class_vars:
         return self.cls.class_vars[attr]
     else:
         try:
             val = self.cls.members[attr]
             text = f"{obj.as_accessor()}{attr}"
             return Code(tp=val.tp, code=text)
         except KeyError:
             raise StaticTypeError(f"Instance of {self.name} has no attribute {attr}")
Пример #3
0
 def get_code(self, context, *args: Code) -> Code:
     self.check_code(args)
     # noinspection PyUnusedLocal
     for i, arg in enumerate(args):
         if i == 0:
             if arg.priority > self.priority:
                 arg.code = f"({arg.code})"
         else:
             if arg.priority >= self.priority:
                 arg.code = f"({arg.code})"
     return Code(tp=self.retval, code=eval(f"f'{self.template}'"), priority=self.priority)
Пример #4
0
 def visit_Assign(self, node: ast.Assign):
     right = get_constant_code(node.value, self.context)
     for n in node.targets:
         if isinstance(n, ast.Name):
             if n.id in self.context:
                 raise StaticTypeError("Cannot redefine global variables")
             self.context[n.id] = Code(tp=right.tp, code=n.id)
             left = self.context[n.id]
             self.globals += [
                 f"{left.tp.c_type} {n.id} = {right.as_value()};\n"
             ]
         else:
             raise InvalidOperation("Can only initialise global variables")
Пример #5
0
 def __init__(self, node: ast.FunctionDef, type_sig: "TypeSig",
              context: Context):
     self.body: str
     self.indent: int
     self.retval: Code
     self.all_paths_return: bool
     self.primary_node = node
     self.context = Context(context)
     self.args = []
     self.libraries: Set[str] = set()
     for arg, arg_type in zip(node.args.args, type_sig):
         code = Code(arg_type,
                     is_arg=True,
                     is_pointer=not arg_type.pass_by_value,
                     code=arg.arg)
         self.context[arg.arg] = code
         self.args.append(code)
     self.generate_code()
Пример #6
0
    def get_code(self, context: Context, *args: Code) -> Code:
        prepends = []
        format_strs = []
        codes = []
        for arg in args:
            if arg.tp == "int":
                format_strs.append("%d")
                codes.append(arg.code)
            elif arg.tp == "float":
                format_strs.append("%f")
                codes.append(arg.code)
            elif arg.tp.name.strip("str__"):
                format_strs.append("%s")
                codes.append(f"{arg.as_accessor()}text")

        codes = [f'"{" ".join(format_strs)}\\n"'] + codes
        return_code = Code(tp=TypeDB.get_type_by_value(None),
                           code=f"printf({', '.join(codes)})",
                           libraries=["stdio"],
                           prepends=prepends)
        return return_code
Пример #7
0
 def visit_ClassDef(self, node: ast.ClassDef):
     cls = ClassParser(node, self)
     self.context[node.name] = Code(tp=cls.get_type(), code=node.name)
     tp = cls.get_type()
     TypeDB.add_type(tp)
     TypeDB.add_type(tp.instance)
Пример #8
0
 def visit_FunctionDef(self, node: ast.FunctionDef):
     tp = MultiFunction(node, self.context)
     self.context[node.name] = Code(tp=tp, code=node.name)
     TypeDB.add_type(tp)
Пример #9
0
 def visit_List(self, node):
     types_and_codes = [self.visit(n) for n in node.elts]
     tp = TypeDB.get_list([t.tp for t in types_and_codes])
     code = tp.as_literal([t.code for t in types_and_codes])
     return Code(tp=tp, code=code)
Пример #10
0
 def visit_NameConstant(self, node):
     return Code(tp=TypeDB.get_type_by_value(node.value),
                 code=self.CONSTANTS_MAP[node.value])
Пример #11
0
 def visit_Bytes(self, node):
     tp = TypeDB.get_string()
     return Code(tp=tp, code=tp.as_literal(str(node.s, 'utf-8')))
Пример #12
0
 def visit_Str(self, node):
     tp = TypeDB.get_string()
     return Code(tp=tp, code=tp.as_literal(node.s))
Пример #13
0
 def visit_Num(self, node):
     return Code(tp=TypeDB.get_type_by_value(node.n), code=str(node.n))
Пример #14
0
 def visit_IfExp(self, node):
     test, body, orelse = [
         self.visit(x) for x in (node.test, node.body, node.orelse)
     ]
     code = "%s ? %s : %s" % (test.code, body.code, orelse.code)
     return Code(tp=itypes.combine_types(body.tp, orelse.tp), code=code)
Пример #15
0
class FunctionImplementation(ast.NodeVisitor):
    def __init__(self, node: ast.FunctionDef, type_sig: "TypeSig",
                 context: Context):
        self.body: str
        self.indent: int
        self.retval: Code
        self.all_paths_return: bool
        self.primary_node = node
        self.context = Context(context)
        self.args = []
        self.libraries: Set[str] = set()
        for arg, arg_type in zip(node.args.args, type_sig):
            code = Code(arg_type,
                        is_arg=True,
                        is_pointer=not arg_type.pass_by_value,
                        code=arg.arg)
            self.context[arg.arg] = code
            self.args.append(code)
        self.generate_code()

    def is_init(self):
        if self.primary_node.name == "__init__":
            first_arg = self.args[0]
            if first_arg.code == "self" and isinstance(first_arg.tp,
                                                       ClassInstance):
                return True
        return False

    # noinspection PyAttributeOutsideInit
    def generate_code(self):
        self.body = ""
        self.in_try_block = False
        self.indent = 4
        self.retval = Code(tp=None, code="_retval", is_pointer=True)
        self.all_paths_return = False
        self.context.clear_temp_vars()
        # clear struct if class init
        if self.is_init():
            self.start_line(f"*self = ({self.args[0].tp.c_type}){{0}};\n")
        for n in self.primary_node.body:
            self.visit(n)
        if not self.all_paths_return:
            self.retval.assign_type(TypeDB.get_type_by_value(None),
                                    " as return value")

    def retval_in_c(self):
        if self.retval.tp.pass_by_value:
            return self.retval.tp.c_type
        else:
            return "void"

    def params(self):
        if self.retval.tp.pass_by_value:
            return self.args
        else:
            return self.args + [self.retval]

    def start_line(self, text: str) -> None:
        self.body += " " * self.indent
        self.body += text

    # noinspection PyAttributeOutsideInit
    def visit_If(self, node: ast.If) -> None:
        test = self.get_expression_code(node.test)
        self.start_line("if ({}) {{\n".format(test.code))
        self.indent += 2
        for n in node.body:
            self.visit(n)
        body_returns = self.all_paths_return
        self.all_paths_return = False
        if node.orelse:
            self.indent -= 2
            self.start_line("} else {\n")
            self.indent += 2
            for n in node.orelse:
                self.visit(n)
            self.all_paths_return = body_returns and self.all_paths_return

        self.indent -= 2
        self.start_line("}\n")

    def visit_Return(self, node: ast.Return) -> None:
        if self.in_try_block:
            raise InvalidOperation("Cannot return from within try block")
        result = self.get_expression_code(node.value)
        self.retval.assign_type(result.tp, " as return value")
        if self.retval.tp.pass_by_value:
            self.start_line(f"return {result.code};\n")
        else:
            self.start_line(f"{self.retval.as_value()} = {result.code};\n")
            self.start_line("return;\n")
        # noinspection PyAttributeOutsideInit
        self.all_paths_return = True

    def visit_Expr(self, node: ast.Expr) -> None:
        result = self.get_expression_code(node.value)
        self.start_line(result.code + ";\n")

    # noinspection PyAttributeOutsideInit
    def visit_For(self, node: ast.For) -> None:
        # create list to iterate over
        lst_name = self.context.get_temp_name()
        assign_node = ast.Assign(
            targets=[ast.Name(id=lst_name, ctx=ast.Store())], value=node.iter)
        self.visit(assign_node)

        lst = self.context[lst_name]
        index = self.context.get_temp_var(TypeDB.get_type_by_name("int"))
        length = lst.tp.get_method("len")
        length_code = length.get_code(self.context, lst).code

        # construct for statement
        self.start_line(
            f"for({index.code}=0; {index.code} < {length_code}; {index.code}++) {{\n"
        )
        self.indent += 4
        assign_node = ast.Assign(
            targets=[node.target],
            value=ast.Subscript(
                value=ast.Name(id=lst_name, ctx=ast.Load()),
                slice=ast.Index(value=ast.Name(id=index.code, ctx=ast.Load())),
                ctx=ast.Load()))
        self.visit(assign_node)
        for statement in node.body:
            self.visit(statement)
        self.indent -= 4
        self.start_line("}\n")
        self.all_paths_return = False

    def visit_Assign(self, node: ast.Assign) -> None:
        right = self.get_expression_code(node.value)
        for n in node.targets:
            self.assign_target(n, right)

    def assign_target(self, node, value):
        if isinstance(value.tp, EmptyList):
            func_node = ast.Expr(value=ast.Call(
                func=ast.Attribute(value=node, attr="clear"), args=[]))
            try:
                self.visit(func_node)
            except UnknownVariable:
                raise StaticTypeError(
                    "Must specify a list type when assigning an empty list")
            return
        if isinstance(node, ast.Name):
            left = self.context.assign_type(node.id, value.tp)
            self.start_line("{} = {};\n".format(left.code, value.as_value()))
        elif isinstance(node, ast.Subscript):
            container = self.get_expression_code(node.value)
            if isinstance(node.slice, ast.Index):
                index = self.get_expression_code(node.slice.value)
                setter = container.tp.get_method("set_item")
                code = setter.get_code(self.context, container, index, value)
                self.start_line(f"{code.code};\n")
            else:
                raise UnimplementedFeature("Slices not yet implemented")
        elif isinstance(node, ast.Attribute):
            owner = self.get_expression_code(node.value)
            owner.tp.set_attr(node.attr, value)
            left = self.get_expression_code(node)
            self.start_line(f"{left.code} = {value.code};\n")

    def visit_AnnAssign(self, node: ast.AnnAssign):
        if isinstance(node.target, ast.Name):
            self.context.assign_type(node.target.id,
                                     annotations.get_type(node.annotation))
        if node.value is not None:
            value = self.get_expression_code(node.value)
            self.assign_target(node.target, value)

    def visit_Try(self, node: ast.Try):
        if node.orelse:
            raise UnimplementedFeature("Can't have an else section to try")
        if node.finalbody:
            raise UnimplementedFeature("Can't have an finally section to try")
        self.start_line("Try {\n")
        self.indent += 4
        self.in_try_block = True
        for n in node.body:
            self.visit(n)
        # noinspection PyAttributeOutsideInit
        self.in_try_block = False
        self.indent -= 4
        exception_name = self.context.get_temp_var(
            TypeDB.get_type_by_name("int"))
        self.start_line(f"}} Catch({exception_name.code}) {{\n")
        self.indent += 4
        self.start_line(f"switch ({exception_name.code}) {{\n")
        for handler in node.handlers:
            if handler.type is None:
                self.start_line("case default:\n")
            else:
                self.start_line(f"case {handler.type.id}:\n")
            self.indent += 4
            for n in handler.body:
                self.visit(n)
            self.start_line("break;\n")
            self.indent -= 4
        self.start_line("}")
        self.indent -= 4
        self.start_line("}")

    def visit_Pass(self, node):
        return

    def visit_Raise(self, node):
        self.start_line(f"Throw({node.exc.id});\n")

    def get_expression_code(self, node: ast.AST) -> Code:
        code, prepends = get_expression_code(node, self.context)
        for line in prepends:
            if isinstance(line, str):
                self.start_line(line)  # if is a string, add string
            else:
                self.visit(line)  # otherwise treat as a node
        self.libraries.update(code.libraries)
        return code

    def generic_visit(self, node):
        raise UnhandledNode(node)

    def get_variable_definitions(self):
        text = ""
        for name, var in self.context.locals():
            if not var.is_arg:
                text += var.tp.declare(name)
        return text
Пример #16
0
 def get_code(self, context, *args: Code) -> Code:
     self.check_code(args)
     arg_strings = [arg.as_function_arg() for arg in args]
     return Code(tp=self.retval, code=f"{self.name}({', '.join(arg_strings)})")