From 2b0380cba5e5adc73299bbaccdc7d20b84825cc1 Mon Sep 17 00:00:00 2001 From: Lunaixsky Date: Sat, 10 May 2025 20:18:39 +0100 Subject: [PATCH 1/1] shconfig: add `link` command to view the inverse dependency * fix some typos --- lunaix-os/arch/LConfig | 15 ++++++- lunaix-os/hal/LBuild | 5 ++- lunaix-os/hal/LConfig | 9 +++- lunaix-os/hal/char/LConfig | 8 +++- .../scripts/build-tools/README.lconfig.md | 8 ++-- .../scripts/build-tools/lcfg2/builder.py | 3 ++ lunaix-os/scripts/build-tools/lcfg2/common.py | 17 ++++++- lunaix-os/scripts/build-tools/lcfg2/nodes.py | 11 +++-- .../scripts/build-tools/lcfg2/rewriter.py | 22 ++++++++-- lunaix-os/scripts/build-tools/lcfg2/rules.py | 2 - .../build-tools/shared/shconfig/commands.py | 44 ++++++++++++++----- 11 files changed, 115 insertions(+), 29 deletions(-) diff --git a/lunaix-os/arch/LConfig b/lunaix-os/arch/LConfig index bb22a10..a78038f 100644 --- a/lunaix-os/arch/LConfig +++ b/lunaix-os/arch/LConfig @@ -24,8 +24,19 @@ def architecture_support(): """ Config ISA support """ - _arch = env("ARCH") - return _arch if _arch else "x86_64" + + match env("ARCH"): + case "i386": + return "i386" + case "aarch64": + return "aarch64" + case "rv64": + return "rv64" + case "x86_64": + return "x86_64" + + print("unknown ARCH:", env("ARCH"), "default to x86_64") + return "x86_64" @"Base operand size" @readonly diff --git a/lunaix-os/hal/LBuild b/lunaix-os/hal/LBuild index 5a50d0e..d0475ee 100644 --- a/lunaix-os/hal/LBuild +++ b/lunaix-os/hal/LBuild @@ -1,6 +1,9 @@ -from . import acpi, ahci, char, gfxa, rtc, term, timer, bus +from . import acpi, ahci, char, rtc, term, timer, bus if config.use_devicetree: from . import devtree +if config.use_graphic_dev: + from . import gfxa + src.c += "irq.c" \ No newline at end of file diff --git a/lunaix-os/hal/LConfig b/lunaix-os/hal/LConfig index ab7e99e..5b6a86f 100644 --- a/lunaix-os/hal/LConfig +++ b/lunaix-os/hal/LConfig @@ -28,4 +28,11 @@ def hal(): """ require (use_devicetree) - return 256 \ No newline at end of file + return 256 + + @"Graphic Devices" + def use_graphic_dev() -> int: + """ + Support of graphical devices and display protocol + """ + return False \ No newline at end of file diff --git a/lunaix-os/hal/char/LConfig b/lunaix-os/hal/char/LConfig index b4ecff1..dd2fa0f 100644 --- a/lunaix-os/hal/char/LConfig +++ b/lunaix-os/hal/char/LConfig @@ -7,8 +7,11 @@ def char_device(): @"VGA 80x25 text-mode console" def vga_console() -> bool: - """ Enable VGA console device (text mode only) """ - + """ + Enable VGA console device (text mode only) + """ + require (use_graphic_dev) + return True @"VGA character game device" @@ -18,5 +21,6 @@ def char_device(): You normally don't need to include this, unless you want some user space fun ;) """ + require (vga_console) return False \ No newline at end of file diff --git a/lunaix-os/scripts/build-tools/README.lconfig.md b/lunaix-os/scripts/build-tools/README.lconfig.md index 05fb7db..457db72 100644 --- a/lunaix-os/scripts/build-tools/README.lconfig.md +++ b/lunaix-os/scripts/build-tools/README.lconfig.md @@ -59,7 +59,7 @@ def group1(): Multiple `LConfig`s may be defined across different sub-directory in large scale project for better maintainability -LunaConfig allow you to import content of other LBuild using python's relative import +LunaConfig allow you to import content of other LConfig using python's relative import feature: ```py @@ -67,7 +67,7 @@ from . import module ``` This import mechanism works like `#include` directive in C preprocessor, -the `from . import` construct will automatically intercepted by the LBuild interpreter and +the `from . import` construct will automatically intercepted by the LConfig interpreter and be replaced with the content from `./module/LConfig` You can also address file in the deeper hierarchy of the directory tree, for example @@ -294,7 +294,7 @@ If a dependency can not be satisfied, then the feature is disabled. This will ca Note that the dependency check only perform on the enablement of the node but not visibility. -### Auto Toggling +### Auto Toggling (Inverse Dependency) > usage: `Terms` with `bool` value type @@ -323,7 +323,7 @@ For configuration language being a python superset will have a risk of abusing d For prevention of this potential drawback, LunaConfig implemented a syntactical validator to identify these possible bad-practice and issue warning (or rise a fatal-error depending on the user setting). -Currently, LunaConfig detect the misuses based on these rule rules: +Currently, LunaConfig detect the misuses based on these rules: + `dynamic-logic`: The presence of conditional branching that could lead to complex logic. However, pattern matching is allowed. + `while-loop`, `for-loop`: The presence of any loop structure. diff --git a/lunaix-os/scripts/build-tools/lcfg2/builder.py b/lunaix-os/scripts/build-tools/lcfg2/builder.py index 40fabfb..235126c 100644 --- a/lunaix-os/scripts/build-tools/lcfg2/builder.py +++ b/lunaix-os/scripts/build-tools/lcfg2/builder.py @@ -106,5 +106,8 @@ class NodeBuilder(ConfigASTVisitor): ast.visit(TreeSanitiser()) ast.visit(build) + for node in env.nodes(): + node.apply_node_body() + env.set_exec_context(build.__noncfg_astns) env.relocate_children() \ No newline at end of file diff --git a/lunaix-os/scripts/build-tools/lcfg2/common.py b/lunaix-os/scripts/build-tools/lcfg2/common.py index 94cdcea..d968e67 100644 --- a/lunaix-os/scripts/build-tools/lcfg2/common.py +++ b/lunaix-os/scripts/build-tools/lcfg2/common.py @@ -19,6 +19,7 @@ class NodeProperty: Enabled = PropertyAccessor("$enabled") Status = PropertyAccessor("$status") Dependency = PropertyAccessor("$depends") + Linkage = PropertyAccessor("$linkage") Hidden = PropertyAccessor("hidden") Parent = PropertyAccessor("parent") Label = PropertyAccessor("label") @@ -132,4 +133,18 @@ class NodeDependency: return dep = NodeDependency(node, expr) - NodeProperty.Dependency[node] = dep \ No newline at end of file + NodeProperty.Dependency[node] = dep + + +class NodeInverseDependency: + def __init__(self): + self.__map = {} + + def add_linkage(self, name, expr): + if name not in self.__map: + self.__map[name] = [expr] + else: + self.__map[name].append(expr) + + def linkages(self): + return self.__map.items() \ No newline at end of file diff --git a/lunaix-os/scripts/build-tools/lcfg2/nodes.py b/lunaix-os/scripts/build-tools/lcfg2/nodes.py index 19ead50..3b42394 100644 --- a/lunaix-os/scripts/build-tools/lcfg2/nodes.py +++ b/lunaix-os/scripts/build-tools/lcfg2/nodes.py @@ -1,6 +1,6 @@ import ast -from lib.utils import SourceLogger, Schema +from lib.utils import SourceLogger, Schema from .common import NodeProperty, ConfigNodeError, NodeDependency from .lazy import LazyLookup from .rewriter import ConfigNodeASTRewriter @@ -40,8 +40,13 @@ class ConfigNode: NodeProperty.Readonly[self] = False NodeProperty.Status[self] = "Empty" - def set_node_body(self, ast_nodes, rewriter = ConfigNodeASTRewriter): - new_ast = ast.Module(ast_nodes, []) + def set_node_body(self, ast_nodes): + self.__exec = ast.Module(ast_nodes, []) + + def apply_node_body(self, rewriter = ConfigNodeASTRewriter): + assert isinstance(self.__exec, ast.Module) + + new_ast = self.__exec validator.validate(self, new_ast) new_ast = rewriter(self).rewrite(new_ast) diff --git a/lunaix-os/scripts/build-tools/lcfg2/rewriter.py b/lunaix-os/scripts/build-tools/lcfg2/rewriter.py index 4134bce..a86ab52 100644 --- a/lunaix-os/scripts/build-tools/lcfg2/rewriter.py +++ b/lunaix-os/scripts/build-tools/lcfg2/rewriter.py @@ -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( @@ -33,6 +33,16 @@ class ConfigNodeASTRewriter(ast.NodeTransformer): 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()), @@ -67,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) @@ -77,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: @@ -122,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) diff --git a/lunaix-os/scripts/build-tools/lcfg2/rules.py b/lunaix-os/scripts/build-tools/lcfg2/rules.py index 0297b55..3bf5683 100644 --- a/lunaix-os/scripts/build-tools/lcfg2/rules.py +++ b/lunaix-os/scripts/build-tools/lcfg2/rules.py @@ -32,8 +32,6 @@ class SyntaxRule(RuleCollection): TrivialReturn = Schema(Schema.Union( TrivialValue, - TrivialTest, - InlineIf, ast.JoinedStr )) diff --git a/lunaix-os/scripts/build-tools/shared/shconfig/commands.py b/lunaix-os/scripts/build-tools/shared/shconfig/commands.py index 8c4e670..825ffa9 100644 --- a/lunaix-os/scripts/build-tools/shared/shconfig/commands.py +++ b/lunaix-os/scripts/build-tools/shared/shconfig/commands.py @@ -20,7 +20,7 @@ class Commands(CmdTable): raise ShconfigException(f"no such config: {name}") return node - def __get_opt_line(self, node): + def __get_opt_line(self, node, color_hint = False): aligned = 40 name = f"CONFIG_{node._name.upper()}" value = NodeProperty.Value[node] @@ -36,7 +36,11 @@ class Commands(CmdTable): line = f"[{status}] {name}" to_pad = max(aligned - len(line), 4) - return f"{line} {'.' * to_pad} {val_txt}" + line = f"{line} {'.' * to_pad} {val_txt}" + + if color_hint and not enabled: + line = f"\x1b[90;49m{line}\x1b[0m" + return line @cmd("help", "h") def __fn_help(self): @@ -70,7 +74,7 @@ class Commands(CmdTable): ] for node in self.__env.terms(): - lines.append(self.__get_opt_line(node)) + lines.append(self.__get_opt_line(node, True)) pydoc.pager("\n".join(lines)) @@ -99,21 +103,22 @@ class Commands(CmdTable): Show the dependency chain and boolean conditionals """ - def __print_dep_recursive(env, node, level = 0): - indent = " "*(level * 4) + def __print_dep_recursive(env, node, inds = 0): + indent = " "*inds dep: NodeDependency = NodeProperty.Dependency[node] - - print(f"{indent}+ {node._name} -> {NodeProperty.Value[node]}") + + state = 'enabled' if NodeProperty.Value[node] else 'disabled' + print(f"{indent}* {node._name} (currently {state})") if dep is None: return - print(f"{indent}= {dep._expr}") + print(f" {indent}predicate: {dep._expr}") + print(f" {indent}dependents:") for name in dep._names: n = env.get_node(name) - __print_dep_recursive(env, n, level + 1) + __print_dep_recursive(env, n, inds + 6) node = self.__get_node(name) - print(node._name) __print_dep_recursive(self.__env, node) @cmd("opt", "val", "v") @@ -138,4 +143,23 @@ class Commands(CmdTable): print() print(textwrap.indent(help.strip(), " |\t", lambda _:True)) print() + + + @cmd("effect", "link") + def __fn_effect(self, name: str): + """ + Show the effects of this option on other options + """ + + node = self.__get_node(name) + link = NodeProperty.Linkage[node] + + if not link: + return + + for other, exprs in link.linkages(): + print(f" {other}:") + for expr in exprs: + print(f" > when {expr}") + print() \ No newline at end of file -- 2.27.0