Close

Implementing Dot-Navigation (Introspection) for the Type System

A project log for XiAleste

XiAleste Next is an 8-bit home computer, which is compatible with software for the Amstrad CPC6128 released on 13 June 1985

h2wh2w 01/29/2026 at 15:480 Comments

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:

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.

Discussions