clean up redundant lines
[lunaix-os.git] / lunaix-os / scripts / build-tools / lcfg2 / common.py
1 import ast
2
3 from lib.utils  import SourceLogger, Schema
4
5 class NodeProperty:
6     class PropertyAccessor:
7         def __init__(self, key):
8             self.__key = key
9         def __getitem__(self, node):
10             return node.get_property(self.__key)
11         def __setitem__(self, node, value):
12             node.set_property(self.__key, value)
13         def __delitem__(self, node):
14             node.set_property(self.__key, None)
15
16     Token       = PropertyAccessor("$token")
17     Value       = PropertyAccessor("$value")
18     Type        = PropertyAccessor("$type")
19     Enabled     = PropertyAccessor("$enabled")
20     Status      = PropertyAccessor("$status")
21     Dependency  = PropertyAccessor("$depends")
22     Hidden      = PropertyAccessor("hidden")
23     Parent      = PropertyAccessor("parent")
24     Label       = PropertyAccessor("label")
25     Readonly    = PropertyAccessor("readonly")
26     HelpText    = PropertyAccessor("help")
27
28 class ConfigNodeError(Exception):
29     def __init__(self, node, *args):
30         super().__init__(*args)
31
32         self.__node = node
33         self.__msg = " ".join([str(x) for x in args])
34
35     def __str__(self):
36         node = self.__node
37         tok: ast.stmt = NodeProperty.Token[node]
38         return (
39             f"{node._filename}:{tok.lineno}:{tok.col_offset}:" +
40             f" fatal error: {node._name}: {self.__msg}"
41         )
42
43
44 class ValueTypeConstrain:
45     TypeMap = {
46         "str": str,
47         "int": int,
48         "bool": bool,
49     }
50
51     BinOpOr = Schema(ast.BinOp, op=ast.BitOr)
52
53     def __init__(self, node, rettype):
54         self.__node = node
55         self.__raw = rettype
56         
57         if isinstance(rettype, ast.Expr):
58             value = rettype.value
59         else:
60             value = rettype
61         
62         if isinstance(value, ast.Constant):
63             self.schema = Schema(value.value)
64         
65         elif isinstance(value, ast.Name):
66             self.schema = Schema(self.__parse_type(value.id))
67         
68         elif isinstance(value, ast.BinOp):
69             unions = self.__parse_binop(value)
70             self.schema = Schema(Schema.Union(*unions))
71         
72         else:
73             raise Exception(
74                 f"unsupported type definition: {ast.unparse(rettype)}")
75
76     def __parse_type(self, type):
77         if type not in ValueTypeConstrain.TypeMap:
78             raise Exception(f"unknown type: {type}")
79         
80         return ValueTypeConstrain.TypeMap[type]
81     
82     def __parse_binop(self, oproot):
83         if isinstance(oproot, ast.Constant):
84             return [oproot.value]
85         
86         if ValueTypeConstrain.BinOpOr != oproot:
87             SourceLogger.warn(
88                 self.__node, self.__raw, 
89                 "only OR is allowed. Ignoring...")
90             return []
91         
92         return self.__parse_binop(oproot.left) \
93              + self.__parse_binop(oproot.right)
94     
95     def check_type(self, value):
96         return self.schema.match(value)
97     
98     def ensure_type(self, node, val):
99         if self.check_type(val):
100            return
101
102         raise node.config_error(
103                 f"unmatched type:",
104                 f"expect: '{self.schema}',",
105                 f"got: '{val}' ({type(val)})") 
106
107 class NodeDependency:
108     class SimpleWalker(ast.NodeVisitor):
109         def __init__(self, deps):
110             super().__init__()
111             self.__deps = deps
112         
113         def visit_Name(self, node):
114             self.__deps._names.append(node.id)
115     
116     def __init__(self, nodes, expr: ast.expr):
117         self._names = []
118         self._expr  = ast.unparse(expr)
119
120         expr = ast.fix_missing_locations(expr)
121         self.__exec  = compile(ast.Expression(expr), "", mode='eval')
122
123         NodeDependency.SimpleWalker(self).visit(expr)
124
125     def evaluate(self, value_tables) -> bool:        
126         return eval(self.__exec, value_tables)
127     
128     @staticmethod
129     def try_create(node):
130         expr = NodeProperty.Dependency[node]
131         if not isinstance(expr, ast.expr):
132             return
133         
134         dep = NodeDependency(node, expr)
135         NodeProperty.Dependency[node] = dep