Namespaces
Namespaces are only relevant during compilation in order to keep track of all declared objects available in the current scope.
There are three distinct namespaces:
- Type Namespace
Component definitions
enum/struct types
- Element Namespace
Component instances
Parameters
- Property Namespace
Contains builtin and user-defined properties
Each has slightly different lookup rules:
- Type
Resolved by searching local scope, and traversing up until a match is found.
- Element
Resolve in local scope only.
Only exception is a ‘signal’ instance that effectively uses ‘type’ namespace search rules.
- Property
Global namespace
User-defined properties can only be added in the root namespace.
Implementation
A single namespace registry class exists throughout compilation that manages namespaces. This single instance is carried through the compiler everywhere.
As objects are defined/instantiated, they are registered with the namespace using the following methods:
.register_element(name, ref)
.register_type(name, ref)
.register_property(name, ref)
At any point, the compiler can query the namespace:
.lookup_element(name)
.lookup_type(name)
.lookup_property(name)
The above return None if not found.
Changing scope when entering/exiting a component definition:
- .enter_scope()
pushes a blank scope onto the type-stack and element-stack
- .exit_scope()
pop and discard top of type-stack and element-stack
Hierarchical references are handled elsewhere. Component instances are traversed manually.