fix dangling pointer issues in ext2dr
[lunaix-os.git] / lunaix-os / scripts / build-tools / lcfg / api.py
1 from abc import abstractmethod
2
3 class ConfigLoadBaseException(Exception):
4     def __init__(self, msg, node, inner=None) -> None:
5         super().__init__(msg)
6         
7         self.__msg = msg
8         self.__node = node
9         self.__inner = inner
10
11     def __str__(self) -> str:
12         return super().__str__()
13     
14 class ConfigLoadException(ConfigLoadBaseException):
15     def __init__(self, msg, node = None, inner=None) -> None:
16         super().__init__(msg, node, inner)
17
18 class ConfigTypeCheckError(ConfigLoadBaseException):
19     def __init__(self, msg, node, inner=None) -> None:
20         super().__init__(msg, node, inner)
21
22 class ConfigIOProvider:
23     def __init__(self) -> None:
24         pass
25
26     @abstractmethod
27     def export(self, env, config_dict):
28         pass
29     
30     @abstractmethod
31     def save(self, env, config_dict):
32         pass
33
34     @abstractmethod
35     def load(self, env):
36         pass
37
38
39 class TypeProviderBase:
40     def __init__(self, type) -> None:
41         self._type = type
42
43     @abstractmethod
44     def check(self, val):
45         return True
46     
47     @abstractmethod
48     def serialise(self, val):
49         pass
50
51     @abstractmethod
52     def deserialise(self, val):
53         pass
54
55     @abstractmethod
56     def parse_input(self, input_str):
57         pass
58
59     @abstractmethod
60     def to_input(self, val):
61         pass
62
63     def allow_none(self):
64         return False
65     
66     @staticmethod
67     def typedef_matched(typedef):
68         return False
69     
70     @abstractmethod
71     def __str__(self) -> str:
72         pass
73
74 class Renderable:
75     def __init__(self) -> None:
76         pass
77     
78     @abstractmethod
79     def render(self, rctx):
80         pass
81
82 class RenderContext:
83     def __init__(self) -> None:
84         pass
85
86     @abstractmethod
87     def add_expandable(self, label, node, on_expand_cb):
88         pass
89
90     @abstractmethod
91     def add_field(self, label, node):
92         pass
93
94 class InteractiveRenderer(RenderContext):
95     def __init__(self) -> None:
96         super().__init__()
97
98     @abstractmethod
99     def render_loop(self):
100         pass
101
102
103 class LConfigBuiltin:
104     def __init__(self, f, is_contextual, rename=None, caller_type=[]):
105         self.name = f.__name__ if not rename else rename
106         self.__f = f
107         self.__contextual = is_contextual
108         self.__caller_type = caller_type
109
110     def __call__(self, env, *args, **kwds):
111         if not self.__contextual:
112             return self.__f(env, *args, **kwds)
113         
114         caller = env.callframe_at(0)
115         f_name = self.__f.__name__
116
117         if not caller:
118             raise ConfigLoadException(
119                 f"contextual function '{f_name}' can not be called contextless",
120                 None
121             )
122         
123         if self.__caller_type and not any([isinstance(caller, x) for x in self.__caller_type]):
124             raise ConfigLoadException(
125                 f"caller of '{f_name}' ({caller}) must have type of any {self.__caller_type}",
126                 caller
127             )
128     
129         return self.__f(env, caller, *args, **kwds)
130     
131 def contextual(name=None, caller_type=[]):
132     def wrapper(func):
133         return LConfigBuiltin(func, True, name, caller_type)
134     return wrapper
135
136 def builtin(name=None):
137     def wrapper(func):
138         return LConfigBuiltin(func, False, name)
139     return wrapper