Exemple #1
0
    def assert_ast_like(self, f, target):
        from lambdex.utils.ast import (
            ast_from_source,
            pformat,
            pprint,
            recursively_set_attr,
        )

        ast_f = f.__ast__
        recursively_set_attr(ast_f, "type_comment", None)
        ast_target = ast_from_source(target, "def")
        ast_target.name = ast_f.name

        try:
            assert_ast_like(ast_f, ast_target)
        except AssertionError as cause:
            msg = "\n".join(
                [
                    "",
                    "===> Compiled:",
                    pformat(ast_f),
                    "===> Target:",
                    pformat(ast_target),
                ]
            )
            raise AssertionError(msg) from cause
Exemple #2
0
    def assert_ast_like(self, f, target):
        from lambdex.utils.ast import ast_from_source, pformat, pprint, recursively_set_attr
        ast_f = f.__ast__
        recursively_set_attr(ast_f, 'type_comment', None)
        ast_target = ast_from_source(target, 'async def')
        ast_target.name = ast_f.name

        try:
            assert_ast_like(ast_f, ast_target)
        except AssertionError as cause:
            msg = '\n'.join(['', '===> Compiled:', pformat(ast_f), '===> Target:', pformat(ast_target)])
            raise AssertionError(msg) from cause
Exemple #3
0
    def assert_ast_like(self, f, target):
        ast_f = f.__ast__
        recursively_set_attr(ast_f, "type_comment", None)
        if is_coroutine_ast(ast_f):
            keyword = "async def"
        else:
            keyword = "def"
        ast_target = ast_from_source(target, keyword)
        ast_target.name = ast_f.name

        try:
            assert_ast_like(ast_f, ast_target)
        except AssertionError as cause:
            msg = "\n".join([
                "",
                "===> Compiled:",
                pformat(ast_f),
                "===> Target:",
                pformat(ast_target),
            ])
            raise AssertionError(msg) from cause
Exemple #4
0
def _compile(
    ast_node: ast.AST,
    filename: str,
    freevars: typing.Sequence[str],
    globals: typing.Optional[dict] = None,
) -> typing.Tuple[types.CodeType, ast.AST, typing.Sequence[int]]:
    """
    An internal function that do the compilation.
    """
    if globals is None:
        globals = {}

    context = Context(
        compile_node,
        globals,
        filename,
    )
    lambdex_node = compile_node(
        ast_node,
        ctx=context,
        flag=ContextFlag.outermost_lambdex,
    )

    # A name in `lambdex_node` should be compiled as nonlocal instead of
    # global (default) if it appears in `freevars`.
    #
    # This is done by wrapping `lambdex_node` in another FunctionDef, and
    # let names in `freevars` become local variables in the wrapper.
    wrapper_name = context.select_name_and_use("wrapper")
    if freevars:
        wrapper_body = [
            ast.Assign(
                targets=[
                    ast.Name(id=name, ctx=ast.Store()) for name in freevars
                ],
                value=None_node,
            ),
            lambdex_node,
        ]
    else:
        wrapper_body = [lambdex_node]

    wrapper_node = ast.FunctionDef(
        name=wrapper_name,
        args=empty_arguments,
        body=wrapper_body,
        decorator_list=[],
        returns=None,
    )
    module_node = ast.Module(
        body=[wrapper_node],
        type_ignores=[],
    )
    module_node = ast.fix_missing_locations(module_node)

    if __DEBUG__:
        try:
            module_code = compile(module_node, filename, "exec")
        except Exception as e:
            raise SyntaxError(pformat(module_node)) from e
    else:
        module_code = compile(module_node, filename, "exec")

    # unwrap the outer FunctionDef.
    # since no other definition in the module, it should be co_consts[0]
    wrapper_code = module_code.co_consts[0]

    # the desired code object should be in `module_code.co_consts`
    # we use `.co_name` to identify
    for obj in wrapper_code.co_consts:
        if inspect.iscode(obj) and obj.co_name == lambdex_node.name:
            lambdex_code = obj
            break

    # Append code object name to its co_freevars, so that lambdex
    # can always access itself via its name `anonymous_...`
    callee_name = lambdex_code.co_name
    try:
        callee_index = lambdex_code.co_freevars.index(callee_name)
    except ValueError:
        callee_index = len(lambdex_code.co_freevars)
        lambdex_code = compat.code_replace(
            lambdex_code,
            co_freevars=(*lambdex_code.co_freevars, callee_name),
        )
    freevars_mapping = _resolve_freevars_mapping(freevars,
                                                 lambdex_code.co_freevars)

    lambdex_code = _rename_code_object(lambdex_code, context)

    return lambdex_code, lambdex_node, freevars_mapping