shconfig: add `link` command to view the inverse dependency
[lunaix-os.git] / lunaix-os / scripts / build-tools / lcfg2 / rewriter.py
index d2003eb8d4c8ef637667bbd403b838741c6e047b..a86ab52852079cbe5f801f9f7bde8f2363350156 100644 (file)
@@ -2,7 +2,7 @@ import ast
 
 from lib.utils  import Schema
 from .lazy       import Lazy
-from .common     import NodeProperty
+from .common     import NodeProperty, NodeInverseDependency
 
 class RewriteRule:
     MaybeBuiltin = Schema(
@@ -31,6 +31,18 @@ class ConfigNodeASTRewriter(ast.NodeTransformer):
 
         self.__cfg_node = cfg_node
 
+        self.__when_epxr = None
+
+    def __put_linkage(self, to_node, item):
+        node = self.__cfg_node._env.get_node(to_node)
+        link = NodeProperty.Linkage[node]
+        
+        if not link:
+            link = NodeInverseDependency()
+            NodeProperty.Linkage[node] = link
+        
+        link.add_linkage(self.__cfg_node._name, ast.unparse(item))
+
     def __subscript_accessor(self, name, ctx, token):
         return ast.Subscript(
             value=ast.Name("__lzLut__", ctx=ast.Load()),
@@ -65,7 +77,7 @@ class ConfigNodeASTRewriter(ast.NodeTransformer):
 
         if RewriteRule.WhenToggler != node:
             raise cfgn.config_error(
-                f"invalid when(...) expression: {ast.unparse(node)}")
+                f"when(...): invalid expression: {ast.unparse(node)}")
 
         if RewriteRule.WhenTogglerItem == node:
             and_list.append(node)
@@ -75,10 +87,16 @@ class ConfigNodeASTRewriter(ast.NodeTransformer):
         for i in range(len(and_list)):
             item = and_list[i]
             operator = item.ops[0]
+
+            if RewriteRule.WhenTogglerItem != item:
+                raise cfgn.config_error(
+                        f"when(...): non-trivial subclause : {ast.unparse(node)}")
             
             name = Lazy.from_type(cfgn, Lazy.NodeValue, item.left.id)
             acc = self.__subscript_accessor(name, ast.Load(), node)
             
+            self.__put_linkage(item.left.id, item)
+
             if isinstance(operator, ast.Is):
                 operator = ast.Eq()
             else:
@@ -92,12 +110,12 @@ class ConfigNodeASTRewriter(ast.NodeTransformer):
                         op=ast.And(), 
                         values=[ast.Constant(True), *and_list])
         
-        expr = NodeProperty.WhenToggle[cfgn]
+        expr = self.__when_epxr
         if expr:
             assert isinstance(expr, ast.expr)
             current = ast.BoolOp(op=ast.Or(), values=[expr, current])
 
-        NodeProperty.WhenToggle[cfgn] = current
+        self.__when_epxr = current
 
     def visit_Attribute(self, node):
         return self.__gen_accessor(node)
@@ -120,7 +138,7 @@ class ConfigNodeASTRewriter(ast.NodeTransformer):
         return None
     
     def visit_Return(self, node):
-        if NodeProperty.WhenToggle[self.__cfg_node]:
+        if self.__when_epxr:
             return None
         return self.generic_visit(node)
     
@@ -131,11 +149,9 @@ class ConfigNodeASTRewriter(ast.NodeTransformer):
         assert isinstance(node, ast.Module)
         node = self.visit(node)
 
-        expr = NodeProperty.WhenToggle[self.__cfg_node]
+        expr = self.__when_epxr
         if not expr:
             return node
-        
-        del NodeProperty.WhenToggle[self.__cfg_node]
-        
+
         node.body.append(ast.Return(expr, lineno=0, col_offset=0))
         return node