Exemple #1
0
    def exec_ast_nodes(self, ast_nodes):
        container_code = ast.parse("""def _container1():
            def _container2():
                print(x)
            return _container2
            x = 1
        """)
        container1_body = container_code.body[0].body
        if isinstance(ast_nodes[-1], ast.Expr):
            ast_nodes[-1] = ast.Return(value=ast_nodes[-1].value)
        container1_body[0].body = ast_nodes
        container1_body[2].targets = [
            ast.Name(id=name, ctx=ast.Store())
                for name in self.locals_cells.keys()]

        # 1st call of python compiler gets the values of local vars
        compiled_code = compile(ast.fix_missing_locations(container_code),
            '<string>', 'exec')
        ld = {}
        eval(compiled_code, {}, ld)
        func = ld['_container1']()
        declared_vars = func.__code__.co_varnames

        if declared_vars:
            # There are assignments inside the user_code. Need to create new
            # cells in locals_cells and make sure the assignments target those cells
            for name in declared_vars:
                if name not in self.locals_cells:
                    self.locals_cells[name] = self.create_empty_cell()
            container1_body[0].body.insert(0, ast.Nonlocal(names=list(declared_vars)))
            container1_body[2].targets = [
                ast.Name(id=name, ctx=ast.Store())
                    for name in list(func.__code__.co_freevars) + list(declared_vars)]
            compiled_code = compile(ast.fix_missing_locations(container_code),
                '<string>', 'exec')
            ld = {}
            eval(compiled_code, {}, ld)
            func = ld['_container1']()
            assert len(func.__code__.co_varnames) == 0

        # Get the cells for the relevant vars
        closure = tuple(self.locals_cells[name] for name in func.__code__.co_freevars)
        res = types.FunctionType(func.__code__,
            self.globals_dict,
            func.__name__,
            func.__defaults__,
            closure)

        return res()
Exemple #2
0
    def test_simple_statements(self):
        # Simple statements can be put on a single line as long as the scope
        # has not changed.
        for body, expect in [
            (ast.Expr(ast.Num(42)), '42'),
            (ast.Import([ast.alias('a', None)]), 'import a'),
            (ast.ImportFrom('b', [ast.alias('a', None)],
                            1), 'from .b import a'),
            (ast.Break(), 'break'),
            (ast.Continue(), 'continue'),
            (ast.Pass(), 'pass'),
            (ast.Assign([ast.Name('X', ast.Store())], ast.Num(42)), 'X=42'),
            (ast.Delete([ast.Name('X', ast.Del())]), 'del X'),
            (ast.Raise(None, None), 'raise'),
            (ast.Return(None), 'return'),
            (ast.AugAssign(ast.Name('X', ast.Store()), ast.Add(),
                           ast.Num(42)), 'X+=42'),
            (ast.Assert(ast.Num(42), None), 'assert 42'),
            (ast.Global(['x']), 'global x'),
            (ast.Nonlocal(['x']), 'nonlocal x'),
        ]:
            if_simple = ast.If(ast.Num(42), [body], None)
            self.verify(if_simple, 'if 42:{}'.format(expect))

        if_multiple_simples = ast.If(ast.Num(42),
                                     [ast.Pass(), ast.Pass()], None)
        self.verify(if_multiple_simples, 'if 42:pass;pass')
        inner_if = ast.If(ast.Num(6), [ast.Pass()], None)
        funky_if = ast.If(ast.Num(42), [
            ast.Break(),
            ast.Continue(), inner_if,
            ast.Break(),
            ast.Continue()
        ], None)
        self.verify(funky_if,
                    'if 42:\n break;continue\n if 6:pass\n break;continue')
Exemple #3
0
 def test_Nonlocal(self):
     nonlocal_ = ast.Nonlocal(['X'])
     self.verify(nonlocal_, 'nonlocal X')
     many_nonlocal = ast.Nonlocal(['X', 'Y'])
     self.verify(many_nonlocal, 'nonlocal X,Y')
Exemple #4
0
 def test_nonlocal(self):
     self.stmt(ast.Nonlocal([]), "empty names on Nonlocal")
Exemple #5
0
 def p_nonlocal_stmt1(self, p):
     ''' nonlocal_stmt : NONLOCAL NAME'''
     nonlocal_stmt = ast.Nonlocal()
     nonlocal_stmt.names = [p[2]]
     nonlocal_stmt.lineno = p.lineno(1)
     p[0] = nonlocal_stmt
def parse_block(s, context=globals()):
    """
    s : a (possibly multiline) string containing lambdascript code
    context : the context in which the functions are to be mirrored
    internal : lambdascript global variables
    """
    # A lambdascript cell is like a Python dictionary without enclosing braces
    node = ast.parse('{'+s+'}', mode='eval').body
    # Extraction of names (some of them are reserved symbols
    names, reserved = {}, {}
    nonlambda = []
    for k, v in zip([k.id for k in node.keys], node.values):
        if len(k) >= 2 and k[:2] == "__":
            if k in reserved:
                raise DuplicateDeclarationError(
                        # TODO: find a better sentence
                        "Several uses of the special symbol '%s'"
                        + " in the same environment"
                        % k )
            reserved[k] = v
        else:
            if k in names:
                raise DuplicateDeclarationError(
                        "Several declarations for the symbol '%s'"
                        + " in the same environment"
                        % k )
            names[k] = v
            if not isinstance(v, ast.Lambda):
                nonlambda.append(k)
            else: # TODO
                pass
                # parse content of Lambda in order to find the tail-recursion
                # symbol ...( *args )  with Ellipsis(). See:
                # ast.dump(ast.parse("...(3)", mode='eval'))
                # 'Expression(body=Call(func=Ellipsis(), args=[Num(n=3)], keywords=[], starargs=None, kwargs=None))'
                # On pourra aussi chercher ...[k](3)  pour la continuation
    # Extraction of free variables (but not global ones)
    freevars = {}
    body = [
            ast.Assign(targets=[ast.Name(id=k, ctx=ast.Store())],
                       value=ast.Lambda(args=ast.arguments(
                           args=[], vararg=None, kwonlyargs=[],
                           kw_defaults=[], kwarg=None, defaults=[]),
                       body=ast.Num(n=0)))
            for k in names ]
    c = {} # local context
    for k in names:
        # We append a 'Lambda' in front of the expression in case it isn't a Lambda
        # itself (in order to avoid getting the expression evaluated)
        body.append(ast.Return(
            value=ast.Lambda(args=ast.arguments(
                args=[], varargs=None, kwonlyargs=[],
                kw_defaults=[], kwarg=None, defaults=[]), body=names[k])))
        M = ast.Module(body=[ast.FunctionDef(name='__lambdascript__',
            args=ast.arguments(args=[], vararg=None, kwonlyargs=[],
                kw_defaults=[], kwarg=None, defaults=[]), body=body,
            decorator_list=[], returns=None)])
        M = ast.fix_missing_locations(M)
        exec(compile(M, '<string>', mode='exec'), context, c)
        body.pop()
        freevars[k] = c['__lambdascript__']().__code__.co_freevars
    # An O(n^2) algorithm for checking that non-lambda expressions are not
    # involved in circular dependancies (lambda expressions are allowed to be)
    for k in names:
        if k in nonlambda:
            checked = { k:False for k in names }
            stack = [k]
            while stack:
                i = stack.pop()
                checked[i] = True
                j = freevars[i]
                for e in j:
                    if e==k:
                        raise CircularReferenceError(
        "Symbol '"+k+"' involved in a circular reference relation"
                                )
                    if not checked[e]: stack.append(e)
    # Tail-recursion
    for k in names:
        if k not in nonlambda and __ast_check_tail_recursive__(names[k], k):
            for w in ast.walk(names[k]):
                if isinstance(w, ast.Name) and w.id==k:
                    w.id = k
            names[k] = ast.Lambda(args = ast.arguments(
                args=[ast.arg(arg=k, annotation=None)], vararg=None,
                kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]),
                body= names[k])
            names[k] = ast.Call(func=ast.Name(id='__make_tail_recursive__',
                ctx = ast.Load()), args=[names[k]],
                 keywords=[], starargs=None, kwargs=None)
    # Curry
    for k in names:
        if k not in nonlambda:
            names[k] = ast.Call(func=ast.Name(id='__make_curry__',
                ctx = ast.Load()), args=[names[k]],
                 keywords=[], starargs=None, kwargs=None)
    # Reference of a lambda in another lambda can now be safely removed
    # from the dictionary 'freevars' because sorting the declarations not
    # care about order between two lambda expressions.
    for k in names:
        if k not in nonlambda:
            freevars[k] = tuple( i for i in freevars[k] if i in nonlambda )
    # Sort the declarations
    D = []
    tmp = list(names)
    while tmp:
        for i in range(len(tmp)):
            e = tmp[i]
            ev = freevars[e]
            if all(i in D for i in ev):
                D.append(tmp.pop(i))
                break
        # for/else: raise # useless after previous check
    # Compile all expressions
    body_outer = list(preamble)
    body_inner = []
    for k in nonlambda:
        body_inner.append(ast.Nonlocal(names=[k]))
    for k in D:
        if k in nonlambda:
            body_outer.append(ast.Assign(targets=[ast.Name(id=k,
                                                  ctx=ast.Store())],
                                         value=ast.Num(n=0)))
            body_inner.append(ast.Assign(targets=[ast.Name(id=k,
                                                  ctx=ast.Store())],
                                         value=names[k]))
        else:
            body_outer.append(ast.Assign(
                targets=[ast.Name(id=k, ctx=ast.Store())], value=names[k]))
            body_inner.append(ast.Assign(
                targets=[ast.Attribute(value=ast.Name(id=k, ctx=ast.Load()),
                                       attr='__code__', ctx=ast.Store())],
                value=ast.Attribute(value=names[k],
                                       attr='__code__', ctx=ast.Load())))
    body_inner.append(ast.Return(value=ast.Dict(
        keys=[ast.Str(s=k) for k in D],
        values=[ast.Name(id=k, ctx=ast.Load()) for k in D])))
    body_outer.append(ast.FunctionDef(name='__inner__', args=ast.arguments(
                            args=[], vararg=None, kwonlyargs=[],
                            kw_defaults=[], kwarg=None, defaults=[]),
                          body=body_inner, decorator_list=[], returns=None))
    body_outer.append(ast.Return(value=ast.Call(
                               func=ast.Name(id='__inner__', ctx=ast.Load()),
                          args=[], keywords=[], starargs=None, kwargs=None)))
    M = ast.Module(body=[ast.FunctionDef(name='__lambdascript__',
        args=ast.arguments(args=[], vararg=None, kwonlyargs=[],
            kw_defaults=[], kwarg=None, defaults=[]), body=body_outer,
        decorator_list=[], returns=None)])
    M = ast.fix_missing_locations(M)
    exec(compile(M, '<string>', mode='exec'), context, c)
    S = c['__lambdascript__']()
    # mirror all symbols in context (generally globals())
    # don't mirror private symbols
    for k in D:
        if k[0] != '_': context[k] = S[k]
    # Parse special symbols (AFTER)
    for k in reserved:
        if k == "__print__":
            E = ast.Expression(body=reserved[k])
            print(eval(compile(E, '<string>', mode='eval'), context, c))
Exemple #7
0
def Nonlocal(draw) -> ast.Nonlocal:
    return ast.Nonlocal(draw(lists(name(), min_size=1, max_size=3)))
Exemple #8
0
 def visitNonlocal(self, n, *args):
     return ast.Nonlocal(names=n.names)
    def visit_Nonlocal(self, node: Nonlocal, *args, **kwargs) -> C.Nonlocal:
        names = self.visit(node.names, *args, **kwargs)

        return C.Nonlocal(names=names, )
Exemple #10
0
def generate_nonlocal(max_depth=None):
    num_names = random.choice([1, 1, 1, 1, 1, 2, 2, 3])
    names = [generate_variable_name() for _ in range(num_names)]
    return ast.Nonlocal(names)