Ejemplo n.º 1
0
    def stencil_id(self) -> StencilID:
        fingerprint = {
            "__main__": self.builder.definition._gtscript_["canonical_ast"],
            "docstring": inspect.getdoc(self.builder.definition),
            "api_annotations": f"[{', '.join(self._extract_api_annotations())}]",
            **self._extract_externals(),
        }

        # typeignore because attrclass StencilID has generated constructor
        return StencilID(  # type: ignore
            self.builder.options.qualified_name,
            gt_utils.shashed_id(gt_utils.shashed_id(fingerprint), self.options_id),
        )
Ejemplo n.º 2
0
def compile_definition(
    definition_func,
    name: str,
    module: str,
    *,
    externals: dict = None,
    dtypes: dict = None,
    rebuild=False,
    **kwargs,
):
    _, original_annotations = gtscript._set_arg_dtypes(definition_func, dtypes=dtypes or {})
    build_options = gt_definitions.BuildOptions(
        name=name, module=module, rebuild=rebuild, backend_opts=kwargs, build_info=None
    )

    options_id = gt_utils.shashed_id(build_options)
    stencil_id = frontend.get_stencil_id(
        build_options.qualified_name, definition_func, externals, options_id
    )
    definition_ir = gt_frontend.GTScriptParser(
        definition_func, externals=externals or {}, options=build_options
    ).run()

    setattr(definition_func, "__annotations__", original_annotations)

    return stencil_id, definition_ir
Ejemplo n.º 3
0
    def get_stencil_id(cls, qualified_name, definition, externals, options_id):
        GTScriptParser.annotate_definition(definition)
        resolved_externals = GTScriptParser.resolve_external_symbols(
            definition._gtscript_["nonlocals"],
            definition._gtscript_["imported"], externals)
        definition._gtscript_["externals"] = resolved_externals

        fingerprint = {"__main__": definition._gtscript_["canonical_ast"]}
        for name, value in resolved_externals.items():
            fingerprint[name] = (value._gtscript_["canonical_ast"] if hasattr(
                value, "_gtscript_") else value)

        definition_id = gt_utils.shashed_id(fingerprint)
        version = gt_utils.shashed_id(definition_id, options_id)
        stencil_id = gt_definitions.StencilID(qualified_name, version)

        return stencil_id
Ejemplo n.º 4
0
def compile_definition(
    definition_func, name: str, module: str, *, externals: dict, rebuild=False, **kwargs
):
    build_options = gt_definitions.BuildOptions(
        name=name, module=module, rebuild=rebuild, backend_opts=kwargs, build_info=None
    )

    options_id = gt_utils.shashed_id(build_options)
    _ = frontend.get_stencil_id(
        build_options.qualified_name, definition_func, externals, options_id
    )
    gt_frontend.GTScriptParser(definition_func, externals=externals, options=build_options).run()
Ejemplo n.º 5
0
    def shashed_id(self):
        result = gt_utils.shashed_id(
            self.name, self.module, self.format_source, *tuple(sorted(self.backend_opts.items()))
        )

        return result
Ejemplo n.º 6
0
def id_version():
    return gt_utils.shashed_id(str(datetime.datetime.now()))
Ejemplo n.º 7
0
    def visit_Call(self, node: ast.Call, *, target_node=None):
        call_name = node.func.id
        assert call_name in self.context and hasattr(self.context[call_name],
                                                     "_gtscript_")

        # Recursively inline any possible nested subroutine call
        call_info = self.context[call_name]._gtscript_
        call_ast = copy.deepcopy(call_info["ast"])
        CallInliner.apply(call_ast, call_info["local_context"])

        # Extract call arguments
        call_signature = call_info["api_signature"]
        arg_infos = {arg.name: arg.default for arg in call_signature}
        try:
            assert len(node.args) <= len(call_signature)
            call_args = {}
            for i, arg_value in enumerate(node.args):
                assert not call_signature[i].is_keyword
                call_args[call_signature[i].name] = arg_value
            for kwarg in node.keywords:
                assert kwarg.arg in arg_infos
                call_args[kwarg.arg] = kwarg.value

            # Add default values for missing args when possible
            for name in arg_infos:
                if name not in call_args:
                    assert arg_infos[name] != gt_ir.Empty
                    if ((arg_infos[name] is True) or arg_infos[name] is False
                            or arg_infos[name] is None):
                        call_args[name] = ast.Num(
                            n=0.0)  # ast.NameConstant(value=arg_infos[name])
                    else:
                        call_args[name] = ast.Num(n=arg_infos[name])
        except Exception:
            raise GTScriptSyntaxError(message="Invalid call signature",
                                      loc=gt_ir.Location.from_ast_node(node))

        # Rename local names in subroutine to avoid conflicts with caller context names
        assign_targets = gt_meta.collect_assign_targets(call_ast)
        assert all(
            len(target) == 1 and isinstance(target[0], ast.Name)
            for target in assign_targets)
        assigned_symbols = set(target[0].id for target in assign_targets)
        name_mapping = {
            name: value.id
            for name, value in call_args.items()
            if isinstance(value, ast.Name) and name not in assigned_symbols
        }

        call_id = gt_utils.shashed_id(call_name)[:3]
        call_id_suffix = f"{call_id}_{node.lineno}_{node.col_offset}"
        template_fmt = "{name}__" + call_id_suffix

        gt_meta.map_symbol_names(call_ast,
                                 name_mapping,
                                 template_fmt=template_fmt,
                                 skip_names=self.all_skip_names)

        # Replace returns by assignments in subroutine
        if target_node is None:
            target_node = ast.Name(
                ctx=ast.Store(),
                lineno=node.lineno,
                col_offset=node.col_offset,
                id=template_fmt.format(name="RETURN_VALUE"),
            )

        assert isinstance(target_node, (ast.Name, ast.Tuple)) and isinstance(
            target_node.ctx, ast.Store)

        ReturnReplacer.apply(call_ast, target_node)

        # Add subroutine sources prepending the required arg assignments
        inlined_stmts = []
        for arg_name, arg_value in call_args.items():
            if arg_name not in name_mapping:
                inlined_stmts.append(
                    ast.Assign(
                        lineno=node.lineno,
                        col_offset=node.col_offset,
                        targets=[
                            ast.Name(
                                ctx=ast.Store(),
                                lineno=node.lineno,
                                col_offset=node.col_offset,
                                id=template_fmt.format(name=arg_name),
                            )
                        ],
                        value=arg_value,
                    ))

        # Add inlined statements to the current block and return name node with the result
        inlined_stmts.extend(call_ast.body)
        self.current_block.extend(inlined_stmts)
        if isinstance(target_node, ast.Name):
            result_node = ast.Name(
                ctx=ast.Load(),
                lineno=target_node.lineno,
                col_offset=target_node.col_offset,
                id=target_node.id,
            )
        else:
            result_node = ast.Tuple(
                ctx=ast.Load(),
                lineno=target_node.lineno,
                col_offset=target_node.col_offset,
                elts=target_node.elts,
            )

        return result_node