Problem
TRLC requires every type (type/tuple/enum) to be declared before it is referenced. This is explicit, documented language behavior - lrm.trlc.
This makes some perfectly reasonable modeling patterns impossible to express, in particular:
Two (or more) types that reference each other mutually.
Splitting a natural "type + its identifier tuple" pair where the tuple's item field needs to reference the type that uses the tuple (see the mutually-recursive ComponentRequirement/ComponentRequirementId example below).
Minimal reproduction
type Requirement {
derived_from RequirementId [0 .. *] // error: unknown symbol RequirementId
}
tuple RequirementId {
item Requirement
separator @
version Integer
}
Proposal for a solution
Add an explicit forward-declaration statement that creates the type's identity early, without a body:
forward_declaration ::= 'forward' ( 'type' | 'tuple' | 'enum' ) IDENTIFIER ';'
The later full declaration fills in the previously-created stub instead of registering a new type.
Impact: smaller, self-contained change. The parser stays single-pass; forward becomes a new reserved keyword (low collision risk — not used as an identifier anywhere in the current test suite or LRM examples, but is a breaking change for any external .rsl file that happens to use forward as a name). Still requires new explicit cycle-detection (a completed forward declaration can now form a real cycle, e.g. mutually extends-ing types, or mutually-referencing recursive tuples), and a check that every forward declaration is eventually completed. Existing tests are unaffected since nothing currently uses forward.
Minimal example with forward declaration:
forward tuple RequirementId;
type Requirement {
derived_from RequirementId [0 .. *] // now resolves against the forward stub
}
tuple RequirementId {
item Requirement
separator @
version Integer
}
Problem
TRLC requires every type (type/tuple/enum) to be declared before it is referenced. This is explicit, documented language behavior - lrm.trlc.
This makes some perfectly reasonable modeling patterns impossible to express, in particular:
Two (or more) types that reference each other mutually.
Splitting a natural "type + its identifier tuple" pair where the tuple's item field needs to reference the type that uses the tuple (see the mutually-recursive ComponentRequirement/ComponentRequirementId example below).
Minimal reproduction
Proposal for a solution
Add an explicit forward-declaration statement that creates the type's identity early, without a body:
The later full declaration fills in the previously-created stub instead of registering a new type.
Impact: smaller, self-contained change. The parser stays single-pass;
forwardbecomes a new reserved keyword (low collision risk — not used as an identifier anywhere in the current test suite or LRM examples, but is a breaking change for any external.rslfile that happens to useforwardas a name). Still requires new explicit cycle-detection (a completed forward declaration can now form a real cycle, e.g. mutuallyextends-ing types, or mutually-referencing recursive tuples), and a check that every forward declaration is eventually completed. Existing tests are unaffected since nothing currently usesforward.Minimal example with forward declaration: