3 from lib.utils import Schema
5 from .common import NodeProperty, NodeInverseDependency
10 func=Schema(ast.Name),
13 WhenTogglerItem = Schema(
16 ops=[Schema.Union(ast.Is, ast.IsNot)],
17 comparators=[ast.Constant])
24 values=Schema.List(WhenTogglerItem))))
26 class ConfigNodeASTRewriter(ast.NodeTransformer):
29 def __init__(self, cfg_node):
32 self.__cfg_node = cfg_node
34 self.__when_epxr = None
36 def __put_linkage(self, to_node, item):
37 node = self.__cfg_node._env.get_node(to_node)
38 link = NodeProperty.Linkage[node]
41 link = NodeInverseDependency()
42 NodeProperty.Linkage[node] = link
44 link.add_linkage(self.__cfg_node._name, ast.unparse(item))
46 def __subscript_accessor(self, name, ctx, token):
48 value=ast.Name("__lzLut__", ctx=ast.Load()),
49 slice=ast.Constant(name),
53 def __gen_accessor(self, orig):
54 key = Lazy.from_astn(self.__cfg_node, orig)
56 return self.generic_visit(orig)
58 return self.__subscript_accessor(key, orig.ctx, orig)
60 def __gen_dependency(self, node):
61 cfgn = self.__cfg_node
62 dep_expr = NodeProperty.Dependency[cfgn]
64 NodeProperty.Dependency[cfgn] = node
67 if not isinstance(dep_expr, ast.expr):
68 raise cfgn.config_error(
69 f"invalid dependency state: {dep_expr}")
71 dep_expr = ast.BoolOp(ast.And(), [dep_expr, node])
72 NodeProperty.Dependency[cfgn] = dep_expr
74 def __gen_when_expr(self, node):
76 cfgn = self.__cfg_node
78 if RewriteRule.WhenToggler != node:
79 raise cfgn.config_error(
80 f"when(...): invalid expression: {ast.unparse(node)}")
82 if RewriteRule.WhenTogglerItem == node:
85 and_list += node.values
87 for i in range(len(and_list)):
89 operator = item.ops[0]
91 if RewriteRule.WhenTogglerItem != item:
92 raise cfgn.config_error(
93 f"when(...): non-trivial subclause : {ast.unparse(node)}")
95 name = Lazy.from_type(cfgn, Lazy.NodeValue, item.left.id)
96 acc = self.__subscript_accessor(name, ast.Load(), node)
98 self.__put_linkage(item.left.id, item)
100 if isinstance(operator, ast.Is):
103 operator = ast.NotEq()
106 item.ops = [operator]
109 current = ast.BoolOp(
111 values=[ast.Constant(True), *and_list])
113 expr = self.__when_epxr
115 assert isinstance(expr, ast.expr)
116 current = ast.BoolOp(op=ast.Or(), values=[expr, current])
118 self.__when_epxr = current
120 def visit_Attribute(self, node):
121 return self.__gen_accessor(node)
123 def visit_Expr(self, node):
126 if RewriteRule.MaybeBuiltin != val:
127 return self.generic_visit(node)
129 # Process marker functions
131 if name == "require":
132 self.__gen_dependency(val.args[0])
134 self.__gen_when_expr(val.args[0])
136 return self.generic_visit(node)
140 def visit_Return(self, node):
143 return self.generic_visit(node)
145 def visit_Is(self, node):
148 def rewrite(self, node):
149 assert isinstance(node, ast.Module)
150 node = self.visit(node)
152 expr = self.__when_epxr
156 node.body.append(ast.Return(expr, lineno=0, col_offset=0))