Today marks a major milestone: full dot-navigation support via the -> operator is now operational. The engine can now "traverse" the type metadata hierarchy, seamlessly moving from the global registry down to specific fields and their internal attributes.
The Goal
Once a type is declared in Lisp (for example, a structure):
(deftype test-vector (basic) ((x int8 1) (y int8 2)) (:methods (new (int8 int8) object) (set (int8 int8) none) (len () int8)))
We needed a way to inspect this type using dot notation. This isn't just manipulating Lisp lists; it is Runtime Reflection over native C++ objects, exposed to the interpreter as NATIVE_REF.
REPL Demonstration
First, we can access the global *type-system* registry. For instance, we can query the pointer size for the current target architecture (in this case, Z80):
soot> (-> *type-system* pointer-size)
=> 2
When querying the structure itself, the system retrieves the BasicType object, which contains vectors for fields and methods:
soot> (-> *type-system* test-vector)
=> [BasicType] test-vector parent: basic size: 5 fields: Field: (type type :offset 0) ... Field: (x int8 :offset 2) ... Field: (y int8 :offset 3) ... methods: Method 0: new (function int8 int8 object) Method 1: set (function int8 int8 none) Method 2: len (function int8)
The -> operator is implemented as a Special Form in C++, allowing us to build deep chains without excessive quoting. We can "drill down" into a specific field to extract its native offset:
;; Access the 'x' field object soot> (-> *type-system* test-vector x) => Field: (x int8 :offset 2) ... ;; Extract a specific attribute (offset) from that field soot> (-> *type-system* test-vector x offset) => 2
A key design detail: navigation respects object boundaries. A field returns a TypeSpec (a type specification/reference), not the type definition object itself. To find the parameters of the underlying data type, we perform a lookup back through the type system:
;; Get the type specification of the field soot> (-> *type-system* test-vector x type) => int8 ;; Resolve that spec to the actual type definition to get its size soot> (-> *type-system* int8 size) => 1
Under the Hood
This navigation is powered by the `Aliasable` system:
- Chain of Responsibility: Virtual make_step_alias calls propagate correctly through the inheritance hierarchy (from Aliasable through StructureType to BasicType), ensuring data access is never lost at different levels of inheritance.
- Unified Interface: The C++ step(key) method handles both meta-property lookups (like size)
- Architecture Agnostic: The system dynamically pulls data based on the initialized architecture (e.g., Z80 vs. Default).
What's Next?
With the code stabilized, we have a solid foundation for the next step: the Static Data Compiler. Now that we can programmatically "see" the offsets and types of every field via introspection, we can begin automating the assembly of structures, constants, and method tables directly into binary buffers.
h2w
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.