1e31aef6aSopenharmony_ci"""The optimizer tries to constant fold expressions and modify the AST
2e31aef6aSopenharmony_ciin place so that it should be faster to evaluate.
3e31aef6aSopenharmony_ci
4e31aef6aSopenharmony_ciBecause the AST does not contain all the scoping information and the
5e31aef6aSopenharmony_cicompiler has to find that out, we cannot do all the optimizations we
6e31aef6aSopenharmony_ciwant. For example, loop unrolling doesn't work because unrolled loops
7e31aef6aSopenharmony_ciwould have a different scope. The solution would be a second syntax tree
8e31aef6aSopenharmony_cithat stored the scoping rules.
9e31aef6aSopenharmony_ci"""
10e31aef6aSopenharmony_ciimport typing as t
11e31aef6aSopenharmony_ci
12e31aef6aSopenharmony_cifrom . import nodes
13e31aef6aSopenharmony_cifrom .visitor import NodeTransformer
14e31aef6aSopenharmony_ci
15e31aef6aSopenharmony_ciif t.TYPE_CHECKING:
16e31aef6aSopenharmony_ci    from .environment import Environment
17e31aef6aSopenharmony_ci
18e31aef6aSopenharmony_ci
19e31aef6aSopenharmony_cidef optimize(node: nodes.Node, environment: "Environment") -> nodes.Node:
20e31aef6aSopenharmony_ci    """The context hint can be used to perform an static optimization
21e31aef6aSopenharmony_ci    based on the context given."""
22e31aef6aSopenharmony_ci    optimizer = Optimizer(environment)
23e31aef6aSopenharmony_ci    return t.cast(nodes.Node, optimizer.visit(node))
24e31aef6aSopenharmony_ci
25e31aef6aSopenharmony_ci
26e31aef6aSopenharmony_ciclass Optimizer(NodeTransformer):
27e31aef6aSopenharmony_ci    def __init__(self, environment: "t.Optional[Environment]") -> None:
28e31aef6aSopenharmony_ci        self.environment = environment
29e31aef6aSopenharmony_ci
30e31aef6aSopenharmony_ci    def generic_visit(
31e31aef6aSopenharmony_ci        self, node: nodes.Node, *args: t.Any, **kwargs: t.Any
32e31aef6aSopenharmony_ci    ) -> nodes.Node:
33e31aef6aSopenharmony_ci        node = super().generic_visit(node, *args, **kwargs)
34e31aef6aSopenharmony_ci
35e31aef6aSopenharmony_ci        # Do constant folding. Some other nodes besides Expr have
36e31aef6aSopenharmony_ci        # as_const, but folding them causes errors later on.
37e31aef6aSopenharmony_ci        if isinstance(node, nodes.Expr):
38e31aef6aSopenharmony_ci            try:
39e31aef6aSopenharmony_ci                return nodes.Const.from_untrusted(
40e31aef6aSopenharmony_ci                    node.as_const(args[0] if args else None),
41e31aef6aSopenharmony_ci                    lineno=node.lineno,
42e31aef6aSopenharmony_ci                    environment=self.environment,
43e31aef6aSopenharmony_ci                )
44e31aef6aSopenharmony_ci            except nodes.Impossible:
45e31aef6aSopenharmony_ci                pass
46e31aef6aSopenharmony_ci
47e31aef6aSopenharmony_ci        return node
48