update readme on build system
authorLunaixsky <lunaixsky@qq.com>
Sat, 10 May 2025 17:55:19 +0000 (18:55 +0100)
committerLunaixsky <lunaixsky@qq.com>
Sat, 10 May 2025 17:55:19 +0000 (18:55 +0100)
* clean up: unused node property
* clean up: add space after node directives for clarity
* clean up: reduce the size of whitelist of non-trivial-value rule

16 files changed:
lunaix-os/LConfig
lunaix-os/README.md
lunaix-os/arch/x86/LConfig
lunaix-os/hal/LConfig
lunaix-os/hal/ahci/LConfig
lunaix-os/hal/bus/LConfig
lunaix-os/hal/char/uart/LConfig
lunaix-os/kernel/fs/ext2/LConfig
lunaix-os/kernel/mm/LConfig
lunaix-os/scripts/build-tools/README.lbuild.md
lunaix-os/scripts/build-tools/README.lconfig.md [new file with mode: 0644]
lunaix-os/scripts/build-tools/README.md [new file with mode: 0644]
lunaix-os/scripts/build-tools/lcfg2/common.py
lunaix-os/scripts/build-tools/lcfg2/config.py
lunaix-os/scripts/build-tools/lcfg2/rewriter.py
lunaix-os/scripts/build-tools/lcfg2/rules.py

index 56cc436361714c787f59f195675a4df2db5ec63c..65cfb07f68eddbdea37fbb89b15ff9b74d7b33e7 100644 (file)
@@ -50,7 +50,7 @@ def debug_and_testing():
         Set the maximum time (in seconds) spent in kernel before considered
         to be stalled.
         """
-        require(check_stall)
+        require (check_stall)
 
         return 10
     
@@ -62,7 +62,7 @@ def debug_and_testing():
 
         Setting it to 0 disable this check
         """
-        require(check_stall)
+        require (check_stall)
 
         return 0
 
index 95df5cb0703e6905ede2ac03cb792c45cf243737..a5a2cdabfd5f8651bc80a190cf617509fd91512e 100644 (file)
@@ -1,26 +1,23 @@
-# LunaixOS 源代码
+# Luniax Kernel
 
-我知道这个目录结构看起来相当的劝退。特别是并没有像初代Linux那种一个文件夹里就只是一堆文件的简单朴素。但至少,就我而言,把结构细分一点儿总是好的。
+This is the source code tree for lunaix kernel.
 
-## 目录结构
+## Organisation
+
+| Directory | Description |
+| -------   | ------      |
+| `arch`    | ISA specific code |
+| `hal`     | drivers |
+| `includes`| headers |
+| `kernel`  | kernel source files |
+| `link`    | linker scripts |
+| `libs`    | kernel library |
+| `makeinc` | includes for makefile |
+| `scripts` | auxiliary scripts |
+| `tests`   | kernel test cases |
+| `usr`     | stock user space environment (debug only) |
+
+## Build System
+
+See: [Build system of Lunaix](./scripts/build-tools/README.md)
 
-+ `arch` 平台,CPU架构相关代码。
-+ `hal`  硬件抽象层,包含了平台设备基本驱动的实现。
-+ `includes`  所有头文件
-+ `makeinc` makefile配置文件
-+ `kernel` 这里就是内核了
-  + `block` 块IO抽象层
-  + `debug`  内核调试服务器
-  + `device` 设备(通用)抽象层
-  + `ds` 提供一些基本的数据结构支持。
-  + `exe` 可执行文件的解析与加载。
-  + `fs` 文件系统。
-  + `mm` 各类内存管理器。
-  + `peripheral` 外部设备驱动(如键盘)。
-  + `process` 进程相关
-  + `time` 为内核提供基本的时间,计时服务。
-  + `tty` 提供基本的,CGA服务。
-+ `libs` 一些内核使用的运行时库,主要提供是内核模式下的一些C标准库里的实现。
-+ `link` 链接器脚本
-+ `scripts` 其他脚本(如:用于代码生成)
-+ `usr` 用户空间代码库,包含了一些实用的用户程序,编译过程独立与内核。
index 0e4d46382e8cc85af95df950e9869303159cbf04..6720ccddbd6ddd370650db87b51b7760acb3a5be 100644 (file)
@@ -2,7 +2,7 @@
 @(parent := architecture_support)
 def x86_configurations():
 
-    require(arch_x86)
+    require (arch_x86)
 
     @flag
     def x86_bl_mb() -> bool:
index b2e00fa77c7b659a6147b79aa9dddde55b98658e..ab7e99e5ac91265a7ae4bc9d6ab98f7211d2df3c 100644 (file)
@@ -16,7 +16,7 @@ def hal():
             devicetree might be mandatory and perhaps the only
             way.
         """
-        require(not arch_x86)
+        require (not arch_x86)
 
         return False
 
@@ -26,6 +26,6 @@ def hal():
         """
             Maximum size for a firmware provided device tree blob
         """
-        require(use_devicetree)
+        require (use_devicetree)
 
         return 256
\ No newline at end of file
index 31277f26165d9a4baa068197f9ca278fcb5e1947..ea0b305bc0adbece3026e1d8295a4540f96504ea 100644 (file)
@@ -6,8 +6,8 @@ def sata_ahci():
     @"Enable AHCI support"
     def ahci_enable() -> bool:
         """ Enable the support of SATA AHCI. 
-            Must require PCI at current stage """
-        require(pci_enable)
+            Must require  PCI at current stage """
+        require (pci_enable)
         
         return True
 
index 769072a3cc964a4c05b9ba255e543b4a6788ff4d..82d97f812f1d227ada2392616f22569fe9e514a8 100644 (file)
@@ -12,14 +12,14 @@ def bus_if():
     @"PCI Express"
     def pcie_ext() -> bool:
         """ Enable support of PCI-Express extension """
-        require(pci_enable)
+        require (pci_enable)
 
         return False
 
     @"Use PMIO for PCI"
     def pci_pmio() -> bool:
         """ Use port-mapped I/O interface for controlling PCI """
-        require(not pcie_ext and pci_enable)
-        require(arch_x86)
+        require (not pcie_ext and pci_enable)
+        require (arch_x86)
 
         return True
index 10a74f51ab2c84674d545e585bf9a0996d51dc09..61014ad159cf8e8f5e848d1be19d524b70c326a2 100644 (file)
@@ -7,7 +7,7 @@ def uart_16x50():
     @"16x50 XT-Compat"
     def xt_16x50() -> bool:
         """ Enable the 16x50 for PC-compatible platform  """
-        require(arch_x86)
+        require (arch_x86)
         
         return True
     
index aa160b37b258419e57763bffbb31f5477cbfc057..435832166bd19bf5580f309c30c16a82701430aa 100644 (file)
@@ -3,7 +3,7 @@
 @(parent := file_system)
 def ext2_fs():
 
-    require(fs_ext2)
+    require (fs_ext2)
 
     @"Debug Messages"
     def ext2_debug_msg() -> bool:
index fa7c431055201217f09511e6b60ed354f802a5f9..c6502bd08c56bfdacda39b3b07a5b4d4a032de7d 100644 (file)
@@ -29,7 +29,7 @@ def memory_subsystem():
         @"PMalloc Thresholds"
         def pmalloc_simple_po_thresholds():
 
-            require (pmalloc_method_simple)
+            require  (pmalloc_method_simple)
             
             @"Maximum cached order-0 free pages"
             def pmalloc_simple_max_po0() -> int:
index 8a25a8e64ffe5da52c3e219643a2c231ec50a4fb..d391973885b8f259b27220e5d7e2febfcae08d2d 100644 (file)
@@ -3,99 +3,85 @@
 LunaBuild is programmable source file selection tool. It does not build things
 by itself, rather, it selects which source file should be feed as input to
 other tranditional build tools such as make. The selection logic is completely
-programmable and convey through `LBuild` file which is essentially a python
-script. As the primary design goal for LunaBuild is simple, lightweight and
-standalone. It just plain python, with some extra predefined functions and
-automatic variables, so does not force user to learn some other weird domain
-specific language (yes, that's you, CMake!).
+programmable and convey through `LBuild` using python syntax. 
+Since the primary design goal for LunaBuild is simple, lightweight and
+standalone. It introduce minimal customisations on the python syntax for better
+readbility and it is essentially modified python.
 
-## Usage
+## Functionalities
 
-Invoke `./luna_build.py <root_lbuild> -o <out_dir>`. It will output two file
-to the `<out_dir>`: `sources.list` and `headers.list`. Contains all the source
-files and header files to be used by the build process.
+### Native Python Environment
 
-## Core Functions
+LunaBuild is a superset of python, meaning that all existing functionalities of 
+python language is still intacted and supported.
 
-LunaBuild provide following function to help user select source files.
+This will gives you maximum flexibility on defining your build logic.
 
-### [func] `use(lbuild_path)`
+### Import other `LBuild`
 
-Include another LBuild file. `lbuild_path` is the path relative to current
-directory, pointed to the file. It can be also pointed to a directory, for
-which the LBuild file is inferred as `$lbuild_path/LBuild`.
+Multiple `LBuild`s may be defined across different sub-directory in large scale
+project for better maintainability
 
-For example:
+LunaBuild allow you to import content of other LBuild using python's relative import
+feature:
 
 ```py
-use("dir")
-use("dir/LBuild")
+from . import subdirectory
 ```
 
-both are equivalent.
+This import mechanism works like `#include` directive in C preprocessor,
+the `from . import` construct will automatically intercepted by the LBuild interpreter and 
+be replaced with the content from `./subdirectory/LBuild`
 
-### [func] `sources(src_list)`
-
-Select a list of source files, all paths used are relative to current
-directory. For example,
+You can also address file in the deeper hierarchy of the directory tree, for example
 
 ```py
-sources([ "a.c", "b.c", "c.c" ])
+from .sub1.sub2 import sub3
 ```
 
-### [func] `headers(src_list)`
+This will be translated into `./sub1/sub2/sub3/LBuild`
 
-Select a list of header file or include directory, all paths used are
-relative to current directory. For example,
+It can also be used in any valid python conditional branches to support 
+conditional import
 
 ```py
-headers([ "includes/", "includes/some.h" ])
+if feature1_enabled:
+    from . import feature1
+elif feature3_enabled
+    from . import feature3
 ```
 
-### [func] `configured(name)`
-
-Check whether a configuration is present, the name for the configuration
-is defined by external configuration provider.
-
-### [func] `config(name)`
-
-Read the value of a configuration, raise exception is not exists.
 
-### [var] `_script`
+### Scoped Data Banks
 
-Automatic variable, a path to the current build file.
+Almost every build systems is evolved around the list data structure, as its
+main task is to collect all interested source files, headers or other build 
+process relative information. This is also true for LunaBuild.
 
-## Short-hands
+To better represent this in a more readable way, LunaBuild introduce the concept 
+of scoped data banks, represented as a automatic global object in the script.
 
-LunaBuild provide some useful short-hand notations
-
-### Conditional Select
-
-Suppose you have two source files `src_a.c` and `src_b.c`, for which
-their selection will be depends on the value of a configuration
-`WHICH_SRC`. A common way is to use `if-else` construct
+Take a look in the example:
 
 ```py
-if config("WHICH_SRC") == "select_a":
-    sources("src_a.c")
-elif config("WHICH_SRC") == "select_b":
-    sources("src_b.c")
+src.c += "source1.c", "source2.c"
 ```
 
-LunaBuild allow you to short hand it as such:
+This will append `"source1.c"` and `"source2.c"` into the list named `c` under
+the scope of `src`. Which can be clearly interpreted as "collection of c source files"
 
-```py
-sources({
-    config("WHICH_SRC"): {
-        "select_a": "src_a.c",
-        "select_b": "src_b.c",
-        # more...
-    }
-})
-```
+It is also important to notice that not all databanks are in the forms of list.
+Some data banks served special purpose, as we will see below.
 
-It can also be extended easily for multiple choices and allow nesting.
+LunaBuild defines the following databanks and scope:
 
-You may also notice we no longer wrap the parameter with square bracket,
-this is also another short-hand, the array notation is not needed when
-there is only one element to add.
++ `src` (source files):
+    + `c` (c files, type: `[]`)
+    + `h` (headers or include directories, type: `[]`)
++ `flag` (source files):
+    + `cc` (compiler flags, type: `[]`)
+    + `ld` (linker flags, type: `[]`)
++ `config` (configuration options from `LConfig`)
+    + `CONFIG_<OptionName>` (any valid config name, type: `Any`)
++ `env` (environmental variables)
+    + `<Name>` (any valid env variable name, type: `Any`)
diff --git a/lunaix-os/scripts/build-tools/README.lconfig.md b/lunaix-os/scripts/build-tools/README.lconfig.md
new file mode 100644 (file)
index 0000000..05fb7db
--- /dev/null
@@ -0,0 +1,339 @@
+# LunaConfig
+
+LunaConfig is a configuration language build on top of python. It allows user 
+to define options and the dependencies then reuse these options in their source 
+code for customisable build.
+
+Lunaix use LunaConfig to toggle various optional modules, subsystems or features
+and allow parameterised kernel build.
+
+
+## Design Motivation
+
+LunaConfig is designed to be an improvement over the old-school Kconfig, which in
+particular to address the issue of lacking hierchical representation. This is 
+because Kconfig organise options into a big flat list, while the options are 
+organised into menu which is hierachical in nature. It is very difficult to 
+identify membership of a config without diving into menuconfig.
+
+## Basic Concepts
+
+LunaConfig is presented as a file named `LConfig` and thus limited to one LConfig per directory. This is because LunaConfig enforce user to organise each directory to be a module or logical packaging of set of relavent functionalities.
+
+In each LunaConfig files, these major concepts you will usually seen.
+
+1. Config Component: `Terms` and `Groups`
+2. Config Import
+3. Native Python
+
+We will describe them in details in the following sections
+
+### Terms
+
+> The object that hold the value for customisation
+
+```py
+def feature1() -> bool:
+    return True
+```
+
+This defined an option named `feature1` with type of `bool` and the default
+value of `True`.
+
+### Groups
+
+> The logical object that is used to organise the `terms` or other `groups`
+
+A group is similar to term but without return type indication and return statement
+
+And it is usually nested with other groups or terms.
+
+```py
+def group1():
+    def feature1() -> bool:
+        return True
+```
+
+### LunaConfig Import
+
+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
+feature:
+
+```py
+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 
+be replaced with the content from `./module/LConfig`
+
+You can also address file in the deeper hierarchy of the directory tree, for example
+
+```py
+from .sub1.sub2 import module
+```
+
+This will be translated into `./sub1/sub2/module/LConfig`
+
+It can also be used in any valid python conditional branches to support 
+conditional import
+
+```py
+if condition_1:
+    from . import module1
+elif condition_2:
+    from . import module2
+```
+
+### Native Python
+
+Native Python code is fully supported in LunaConfig, this include everything like packages import, functions, and class definitions. LunaConfig has the ability to distinguish these code transparently from legitimate config code.
+
+However, there is one exception for this ability. Since LunaConfig treat function definition as declaration of config component, to define a python native function you will need to decorate it with `@native`. For example:
+
+```py
+@native
+def add(a, b):
+    return a + b
+
+def feature1() -> int:
+    return add(1, 2)
+```
+
+If a native function is nested in a config component, it will not be affected by the scope and still avaliable globally. But this is not the case if it is nested by another native function.
+
+If a config component is nested in a native function, then it is ignored by LunaConfig
+
+## Term Typing
+
+A config term require it's value type to be specified explicitly. The type can be a literal type, primitive type or composite type
+
+### Literal Typing
+
+A term can take a literal as it's type, doing this will ensure the value taken by the term to be exactly same as the given type
+
+```py
+# OK
+def feature1() -> "value":
+    return "value"
+    # return "value2"
+
+# Error
+def feature1() -> "value":
+    return "abc"
+```
+
+### Primitive Typing
+
+A term can take any python's primitive type, the value taken by the term will be type checked rather than value checked
+
+```py
+# OK
+def feature1() -> int:
+    return 123
+
+# Error
+def feature1() -> int:
+    return "abc"
+```
+
+### Composite Typing
+
+Any literal type or primitive type can be composite together via some structure to form composite type. The checking on these type is depends on the composite structure used. 
+
+#### Union Structure
+
+A Union structure realised through binary disjunctive connector `|`. The term value must satisfy the type check against one of the composite type:
+
+```py
+def feature1() -> "a" | "b" | int
+    # value can be either:
+    #  "a" or "b" or any integer
+    return "a"
+```
+
+## Component Attributes
+
+Each component have set of attributes to modify its behaviour and apperance, these
+attributes are conveyed through decorators
+
+### Labels
+
+> usage: `Groups` and `Terms`
+
+Label provide a user friendly name for a component, which will be the first choice
+of the name displayed by the interactive configuration tool
+
+```py
+@"This is feature 1"
+def feature1() -> bool:
+    return True
+```
+
+### Readonly
+
+> usage: `Terms`
+
+Marking a term to be readonly prevent explicit value update, that is, manual update by user. Implicit value update initiated by `constrains` (more on this later) is still allowed. 
+
+```py
+@readonly
+def feature1() -> bool:
+    return True
+```
+
+### Visibility
+
+> usage: `Groups` and `Terms`
+
+A component can be marked to be hidden thus prevent it from displayed by the configuration tool, it does not affect the visibility in the code.
+
+If the decorated target is a group, then it is inheritated by all it's subordinates.
+
+```py
+@hidden
+def feature1() -> bool:
+    return True
+```
+
+### Flag
+
+> usage: `Terms`
+
+This is a short hand of both `@hidden` and `@readonly`
+
+```py
+@flag
+def feature1() -> bool:
+    return True
+```
+
+is same as
+
+```py
+@hidden
+@readonly
+def feature1() -> bool:
+    return True
+```
+
+### Parent
+
+> usage: `Groups` and `Terms`
+
+Any component can be defined outside of the logical hierachial structure (i.e., the nested function) but still attached to it's physical hierachial structure.
+
+```py
+@parent := parent_group
+def feature1() -> bool:
+    return True
+
+def parent_group():
+    def feature2() -> bool:
+        return False
+```
+
+This will assigned `feature1` to be a subordinate of `parent_group`. Note that the reference to `parent_group` does not required to be after the declaration.
+
+It is equivalent to 
+
+```py
+def parent_group():
+    def feature2() -> bool:
+        return False
+    
+    def feature1() -> bool:
+        return True
+```
+
+### Help Message
+
+> usage: `Groups` and `Terms`
+
+A help message will provide explainantion or comment of a component, to be used and displayed by the configuration tool.
+
+The form of message is expressed using python's doc-string
+
+```py
+def feature1() -> bool:
+    """
+    This is help message for feature1
+    """
+
+    return True
+```
+
+## Directives
+
+There are builtin directives that is used inside the component.
+
+### Dependency
+
+> usage: `Groups` and `Terms`
+
+The dependency between components is described by various `require(...)` directives. 
+
+This directive follows the python function call syntax and accept one argument of a boolean expression as depedency predicate.
+
+Multiple `require` directives will be chainned together with logical conjunction (i.e., `and`)
+
+```py
+def feature1() -> bool:
+    require (feature2 or feature3)
+    require (feature5)
+    
+    return True
+```
+
+This composition is equivalent to `feature5 and (feature2 or feature3)`, indicate that the `feature1` require presences of both `feature5` and at least one of `feature2` or `feature3`.
+
+If a dependency can not be satisfied, then the feature is disabled. This will cause it neither to be shown in configuration tool nor referencable in source code.
+
+Note that the dependency check only perform on the enablement of the node but not visibility.
+
+### Auto Toggling
+
+> usage: `Terms` with `bool` value type
+
+The `when(...)` directive allow changing the default value based on the predicate evaluation on the value of other terms. Therefore, it can be only used by `Terms` with `bool` as value type.
+
+Similar to `require`, it is based on the function call syntax and takes one argument of conjunctive expression (i.e., boolean expression with only `and` connectors).
+
+Multiple `when` will be chained together using logical disjunction (i.e., `or`)
+
+```py
+def feature1() -> bool:
+    when (feature2 is "value1" and feature5 is "value1")
+    when (feature3)
+```
+
+Which means `feature1` will takes value of `True` if one of the following is satisfied:
+ + both `feature2` and `feature5` has value of `"value1"`
+ + `feature3` has value of True
+
+Notice that we do not have `return` statement at the end as the precense of `when` will add a return automatically (or replace it if one exists)
+
+
+## Validation
+
+For configuration language being a python superset will have a risk of abusing due to the high flexibility. This include complex logic, non-trivial operation being used in a component to derive the final value. Thus shifting the style from declarative to imperative and greatly reduce the overall reability.
+
+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:
+
++ `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.
++ `class-def`: The presence of class definition
++ `complex-struct`: The present of complicated data structure such as `dict`.
++ `side-effect`: The presence of dynamic assignment of other config terms value.
++ `non-trivial-value`: The presence of non-trivial value being used as default value. This include every things other than:
+    + constant
+    + variable reference
+    + comparison between constant or variable
+    + single boolean operation
+    + ternary operator with constant/refernece and trivial boolean operation
+
diff --git a/lunaix-os/scripts/build-tools/README.md b/lunaix-os/scripts/build-tools/README.md
new file mode 100644 (file)
index 0000000..12f49a3
--- /dev/null
@@ -0,0 +1,8 @@
+# Lunaix Build System
+
+The build system used by Lunaix is a hybird approach, with:
+
++ [LunaConfig](./README.lconfig.md) as compile-time configuration and build parameterisation
++ [LunaBuild](./README.lbuild.md) as soruce file collection and compiler/linker flags setting
++ Makefile for the file dependency check, auto-updating and other top-level managements.
+
index 21e75b166ddf5dc75e4a2f369518e331dbf2bbb5..94cdcea201bfb4a2ccd8c4b91229fdf1d64fdfd2 100644 (file)
@@ -19,7 +19,6 @@ class NodeProperty:
     Enabled     = PropertyAccessor("$enabled")
     Status      = PropertyAccessor("$status")
     Dependency  = PropertyAccessor("$depends")
-    WhenToggle  = PropertyAccessor("$when")
     Hidden      = PropertyAccessor("hidden")
     Parent      = PropertyAccessor("parent")
     Label       = PropertyAccessor("label")
index cef5559d44363796011493557231c94f386dbfcc..9eda9e0e36718a98828abe7d2a5d68ff15bb698a 100644 (file)
@@ -109,6 +109,4 @@ class ConfigEnvironment:
     def terms(self):
         for node in self.__node_table.values():
             if isinstance(node, TermNode):
-                yield node
-
-import json
\ No newline at end of file
+                yield node
\ No newline at end of file
index d2003eb8d4c8ef637667bbd403b838741c6e047b..4134bce7f62447ef155ea993257aba1c364ab185 100644 (file)
@@ -31,6 +31,8 @@ class ConfigNodeASTRewriter(ast.NodeTransformer):
 
         self.__cfg_node = cfg_node
 
+        self.__when_epxr = None
+
     def __subscript_accessor(self, name, ctx, token):
         return ast.Subscript(
             value=ast.Name("__lzLut__", ctx=ast.Load()),
@@ -92,12 +94,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)
@@ -131,11 +133,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
index 35f770f8e494d085f8a8bc094f1d6e5f18f50d03..0297b554c874139be8d072eaa86db8bcb33eedb6 100644 (file)
@@ -9,21 +9,15 @@ class SyntaxRule(RuleCollection):
                             ctx=ast.Store)
     TrivialValue = Schema(Schema.Union(
         ast.Constant, 
-        ast.Name, 
-        Schema(ast.Subscript, 
-               value=Schema(ast.Name, id='__lzLut__'), 
-               slice=ast.Constant)
+        ast.Name
     ))
 
     BoolOperators = Schema(Schema.Union(ast.Or, ast.And))
     
     TrivialTest    = Schema(ast.Compare, 
                           left=TrivialValue, 
-                          ops=[Schema.Union(ast.Eq, ast.In)],
-                          comparators=[Schema.Union(
-                              ast.Constant, 
-                              Schema(ast.List, elts=Schema.List(ast.Constant))
-                          )])
+                          ops=[Schema.Union(ast.Eq)],
+                          comparators=[ast.Constant])
     
     InlineIf       = Schema(ast.IfExp, 
                             test=Schema.Union(TrivialTest, TrivialValue), 
@@ -38,8 +32,8 @@ class SyntaxRule(RuleCollection):
     
     TrivialReturn  = Schema(Schema.Union(
         TrivialValue,
+        TrivialTest,
         InlineIf,
-        TrivialLogic,
         ast.JoinedStr
     ))