Esempio n. 1
0
    def compile_single(self,
                       codeobject: Code,
                       filename: str,
                       element: Node,
                       line_no: int,
                       result_required: bool,
                       scope: list) -> tuple:
        """
        compiles a single Node
        """

        codeobject.set_lineno(element.content[0].line_no)
        if isinstance(element.content[0], (IDNode, SymbolNode)):
            if element.content[0].content == 'defun':
                # wahey! creating a function!
                line_no, codeobject = self.compile_function(
                    codeobject,
                    filename,
                    element,
                    line_no
                )

            elif element.content[0].content == 'lambda':
                raise Exception((element, element.content))

            elif element.content[0].content in ('let',
                                                'defparameter',
                                                'defvar'):
                # inline variable assignments
                line_no, codeobject = self.handle_variable_assignment(
                    codeobject,
                    filename,
                    element,
                    line_no,
                    scope
                )

            else:
                # whahey! calling a function!
                line_no, codeobject = self.call_function(
                    codeobject,
                    filename,
                    element,
                    line_no,
                    scope
                )

                if not result_required:
                    # if the result aint required, clean up the stack
                    codeobject.POP_TOP()
        else:
            raise Exception('{} -> {}'.format(element, element.content))

        return line_no, codeobject
Esempio n. 2
0
    def _generate_code(self):
        self.cache = cache = self.static_cache.copy()

        def callback(*args, **kw):
            types = tuple(
                [getattr(arg, '__class__', type(arg)) for arg in args])
            key = tuple(map(istype, types))
            self.__lock__.acquire()
            try:
                action = self.rules.default_action
                for sig in self.registry:
                    if implies(key, sig):
                        action = combine_actions(action, self.registry[sig])
                f = cache[types] = compile_method(action, self)
            finally:
                self.__lock__.release()
            return f(*args, **kw)

        c = Code.from_function(self.function, copy_lineno=True)
        types = [
            class_or_type_of(Local(name))
            for name in flatten(inspect.getargspec(self.function)[0])
        ]
        target = Call(Const(cache.get), (tuple(types), Const(callback)))
        c.return_(call_thru(self.function, target))
        return c.code()
Esempio n. 3
0
 def _regen_code(self):
     c = Code.from_function(self.function, copy_lineno=True)
     c.return_(
         call_thru(
             self.function,
             Call(
                 Getattr(
                     Call(Const(Dispatching), (Const(self.function), ),
                          fold=False), '_regenerate'))))
     return c.code()
Esempio n. 4
0
def compile(buf, filename, add_return=False):
    lexer = Lexer(buf)
    parser = Parser(lexer)
    ast = parser.parse()

    ast.apply(SemanticAnalyser())

    atoms = ast.getPProgram().getAtom()
    code = Code()

    code.co_filename = filename

    code.LOAD_CONST(None)

    for atom in atoms:
        load_value(atom, code)

    code.RETURN_VALUE()

    return code.code()
Esempio n. 5
0
    def compile_function(self,
                         codeobject: Code,
                         filename: str,
                         element: Node,
                         line_no: int) -> tuple:
        """
        'Compiles' function, using the last functions return value
        in the function body as the return value for the function proper
        """
        _, name, args, *body = element.content

        name = name.content
        args = args.content

        args = [arg.content for arg in args]

        func_code = codeobject.nested(name, args)

        if body and any(el.content for el in body):
            *body, return_func = [el for el in body if el.content]

            # compile all bar the last statement
            for body_frag in body:
                line_no, func_code = self.compile_single(
                    codeobject=func_code,
                    filename=filename,
                    element=body_frag,
                    line_no=line_no,
                    result_required=False,
                    scope=args
                )

            # compile the last statement, and ask for the result value
            line_no, func_code = self.compile_single(
                codeobject=func_code,
                filename=filename,
                element=return_func,
                line_no=line_no,
                result_required=True,
                scope=args
            )
            func_code.RETURN_VALUE()

        else:
            func_code.return_()

        # inject the function into the codeobject
        codeobject = self.inject_function_code(
            codeobject=codeobject,
            function_codeobj=func_code.code(codeobject),
            name=name
        )

        return line_no, codeobject
Esempio n. 6
0
    def as_abstract(self):
        for action in self.rules:
            raise AssertionError("Can't make abstract: rules already exist")

        c = Code.from_function(self.function, copy_lineno=True)
        c.return_(call_thru(self.function, Const(self.rules.default_action)))

        if self.backup is None:
            self.function.func_code = c.code()
        else:
            self.backup = c.code()
        return self.function
Esempio n. 7
0
 def _regen_code(self):
     c = Code.from_function(self.function, copy_lineno=True)
     c.return_(
         call_thru(
             self.function,
             Call(Getattr(
                 Call(Const(Dispatching), (Const(self.function),), fold=False),
                 '_regenerate'
             ))
         )
     )
     return c.code()
Esempio n. 8
0
    def as_abstract(self):
        for action in self.rules:
            raise AssertionError("Can't make abstract: rules already exist")

        c = Code.from_function(self.function, copy_lineno=True)
        c.return_(call_thru(self.function, Const(self.rules.default_action)))

        if self.backup is None:
            setattr(self.function, CODE, c.code())
        else:
            self.backup = c.code()
        return self.function
Esempio n. 9
0
    def compile_parse_tree(self, filename: str, parse_tree) -> Code:
        """
        Takes a filename and a parse_tree and returns a BytecodeAssembler
        Code object

        :param filename: filename of file to compile
        :param parse_tree: parse_tree to compile
        :rtype: Code
        """

        filename = os.path.abspath(filename)

        line_no = -1

        code = Code()
        code.set_lineno(line_no)
        code = self.bootstrap_obj(code)
        line_no += 1

        code.co_filename = filename
        line_no, code = self.compile_parse_tree_internal(
            codeobject=code,
            parse_tree=parse_tree,
            line_no=line_no,
            filename=filename
        )


        code.return_(None)
        return code
Esempio n. 10
0
    def _generate_code(self):
        self.cache = cache = self.static_cache.copy()
        def callback(*args, **kw):
            types = tuple([getattr(arg,'__class__',type(arg)) for arg in args])
            key = tuple(map(istype, types))
            self.__lock__.acquire()
            try:
                action = self.rules.default_action
                for sig in self.registry:
                    if implies(key, sig):
                        action = combine_actions(action, self.registry[sig])
                f = cache[types] = compile_method(action, self)
            finally:
                self.__lock__.release()
            return f(*args, **kw)

        c = Code.from_function(self.function, copy_lineno=True)
        types = [class_or_type_of(Local(name))
                    for name in flatten(inspect.getargspec(self.function)[0])]
        target = Call(Const(cache.get), (tuple(types), Const(callback)))
        c.return_(call_thru(self.function, target))
        return c.code()
Esempio n. 11
0
def compile_atom(atom, c):
    if isinstance(atom, AVectorAtom):
        values = atom.getVector().getAtom()

        for value in values:
            load_value(value, c)

        c.BUILD_LIST(len(values))
        return True


    if isinstance(atom, ADictAtom):
        values = atom.getDict().getAtom()
        n = len(values) / 2

        c.LOAD_GLOBAL('dict')
        for i in range(n):
            load_value(values[i * 2], c)
            load_value(values[i * 2 + 1], c)

        c.CALL_FUNCTION(0, n)
        return True


    if isinstance(atom, AListAtom):
        xs = atom.getList().getAtom()
        head = xs[0]

        if isinstance(head, AListAtom):
            for x in xs:
                load_value(x, c)

            c.CALL_FUNCTION(len(xs) - 1)

            return True

        if isinstance(head, AIdentifierAtom):
            fn = head.getIdentifier().getText()

            c.set_lineno(head.getIdentifier().getLine())

            if fn == 'def':
                var = xs[1].getIdentifier().getText()
                if load_value(xs[2], c):

                    c.STORE_GLOBAL(var)
                    c.LOAD_CONST(var)
                    return True

            if fn == 'print':
                if load_value(xs[1], c):
                    c.PRINT_ITEM()
                    c.PRINT_NEWLINE()
                    c.LOAD_CONST(None)
                    return True

            if fn == 'if' or fn == 'ife':
                false_part = Label()
                finish = Label()

                load_value(xs[1], c) # eval condition

                c(false_part.JUMP_IF_FALSE)
                c.POP_TOP() # discard boolean result
                load_value(xs[2], c)
                c(finish.JUMP_ABSOLUTE)

                c(false_part)
                c.POP_TOP() # discard boolean result

                if len(xs) == 4:
                    load_value(xs[3], c)
                else:
                    c.LOAD_CONST(None)

                c(finish)

                return True

            if fn == 'let':
                pair = xs[1].getVector().getAtom()
                body = xs[2]
                n = len(pair) / 2

                for i in range(n):
                    load_value(pair[i * 2 + 1], c)
                    print pair[i * 2]
                    unpack_var(pair[i * 2], c)

                load_value(body, c)

                # todo: DELETE_FAST

                return True

            if fn == 'for':
                pair = xs[1].getVector().getAtom()
                var = pair[0]
                ls = pair[1]
                body = xs[2]

                for_loop = Label()
                for_end = Label()

                load_value(ls, c)

                c.GET_ITER()
                c(for_loop)
                c(for_end.FOR_ITER)

                unpack_var(pair[0], c)

                load_value(body, c)

                c.POP_TOP()

                c(for_loop.JUMP_ABSOLUTE)
                c(for_end)

                return True


            if fn == 'defn':
                name = xs[1].getIdentifier().getText()
                arguments = xs[2].getVector().getAtom()
                body = xs[3]
                func_code = Code()

                func_code.co_filename = c.co_filename
                func_code.co_name = name
                func_code.co_argcount = len(arguments)
                func_code.co_varnames = [arg.getIdentifier().getText() for arg in arguments]

                load_value(body, func_code)

                func_code.RETURN_VALUE()

                c.LOAD_CONST(func_code.code())
                c.MAKE_FUNCTION(0)
                c.STORE_GLOBAL(name)

                c.LOAD_CONST(name)

                return True

            if fn == 'fn':
                arguments = xs[1].getVector().getAtom()
                body = xs[2]
                func_code = Code()

                func_code.co_filename = c.co_filename
                func_code.co_argcount = len(arguments)
                func_code.co_varnames = [arg.getIdentifier().getText() for arg in arguments]
                # func_code.co_cellvars = []

                load_value(body, func_code)

                func_code.RETURN_VALUE()

                c.LOAD_CONST(func_code.code())
                c.MAKE_FUNCTION(0)

                return True

            if fn == 'import':
                pkg = xs[1].getIdentifier().getText()

                c.LOAD_CONST(-1)

                if len(xs) == 3:

                   names = [t.getIdentifier().getText() for t in xs[2].getVector().getAtom()]
                   imports = tuple(names)

                   c.LOAD_CONST(imports)
                   c.IMPORT_NAME(pkg)

                   for name in names:
                       c.IMPORT_FROM(name)
                       c.STORE_GLOBAL(name)

                else:
                    c.LOAD_CONST(None)
                    c.IMPORT_NAME(pkg)
                    c.STORE_GLOBAL(pkg)

                return True

            if fn == '.':
                if isinstance(xs[1], AIdentifierAtom):
                    load_value(xs[2], c)
                    c.LOAD_ATTR(xs[1].getIdentifier().getText())
                else:
                    c.LOAD_GLOBAL('getattr')
                    load_value(xs[2], c)
                    load_value(xs[1], c)
                    c.CALL_FUNCTION(2)

                return True

            if fn == 'exec':
                load_value(xs[1], c)
                c.MAKE_FUNCTION(0)
                c.CALL_FUNCTION(0)
                return True

            if load_var(head, c):
                for x in xs[1:]:
                    load_value(x, c)

                c.CALL_FUNCTION(len(xs) - 1)
                return True

    return False