Rewrite the lunabuild toolchain with enhanced feature (#60)
[lunaix-os.git] / lunaix-os / scripts / build-tools / lbuild / scope.py
diff --git a/lunaix-os/scripts/build-tools/lbuild/scope.py b/lunaix-os/scripts/build-tools/lbuild/scope.py
new file mode 100644 (file)
index 0000000..149aa5a
--- /dev/null
@@ -0,0 +1,96 @@
+import inspect
+from lib.utils import Schema
+from .common import DirectoryTracker
+
+class ScopeProvider:
+    Enumerables = Schema(Schema.Union(list, tuple))
+    Primitives = Schema(Schema.Union(str, int, bool))
+    
+    def __init__(self, name):
+        super().__init__()
+        self.name = name
+        self.__accessors = {}
+
+    def __add_accessor(self, accessor, type):
+        acc = accessor
+        if isinstance(accessor, str):
+            acc = type(accessor)
+        self.__accessors[acc.name] = acc
+
+    def subscope(self, accessor):
+        self.__add_accessor(accessor, ScopeAccessor)
+
+    def file_subscope(self, accessor):
+        self.__add_accessor(accessor, FileScopeAccessor)
+
+    def accessors(self):
+        return self.__accessors.values()
+    
+    def reset(self):
+        for v in self.__accessors.values():
+            v.reset()
+
+    def context_name(self):
+        return f"__SC{self.name}"
+
+    def __getitem__(self, name):
+        if name not in self.__accessors:
+            return None
+        return self.__accessors[name]
+    
+    def __setitem__(self, name, val):
+        pass
+
+class ScopeAccessor:
+    def __init__(self, name):
+        super().__init__()
+        self.name = name
+        self.__values = []
+        self._active_context = None
+
+    def values(self):
+        return self.__values
+    
+    def reset(self):
+        self.__values.clear()
+
+    def add(self, x):
+        self.__load_build_context()
+
+        if ScopeProvider.Enumerables == x:
+            for v in x:
+                self.add(v)
+            return
+        
+        if ScopeProvider.Primitives == x:
+            self.put_value(x)
+            return
+        
+        raise Exception(f"invalid value '{x}' of type ('{type(x).__name__}')")
+    
+    def put_value(self, x):
+        self.__values.append(x)
+
+    def __load_build_context(self):
+        self._active_context = None
+        for f in inspect.stack():
+            if "__LBUILD__" not in f.frame.f_globals:
+                continue
+            self._active_context = f.frame.f_globals
+        
+        if not self._active_context:
+            raise Exception(
+                f"unable to modify '{self.name}' outside build context)")
+
+    def __iadd__(self, other):
+        self.add(other)
+
+class FileScopeAccessor(ScopeAccessor):
+    def __init__(self, name):
+        super().__init__(name)
+
+    def put_value(self, x):
+        tracker = DirectoryTracker.get(self._active_context)
+        x = str(tracker.active_relative() / x)
+        return super().put_value(x)
+