-
Notifications
You must be signed in to change notification settings - Fork 84
Description
In at least one situation (that I don't know how to generalize yet), an incorrect TypeScript interface gets generated. This happens for an inferred type from a parser rule that uses tree-rewriting actions. The result is a TypeScript interface that contains a field with a type that is too specific, i.e. the field type was not "abstract enough" to properly represent what the field could actually contain.
I guess, the example below is more telling than this description.
Langium version: 4.0.0
Package name: langium
Steps To Reproduce
yo langium
- Replace the
.langium
file with the code below npm run langium:generate
- Check the code in the
ast.ts
file
Code example:
grammar Demo
entry Model:
Expression;
Expression infers AbstractExpressionChainMember:
{infer AtomicExpression} atom=Atom (
({infer MemberAccess.predecessor=current} '.' member=ID)
)*
;
Atom:
name=ID
;
terminal ID: /[_a-zA-Z][\w_]*/;
hidden terminal WS: /\s+/;
The current behavior
For the MemberAccess
parser rule, the following interface gets generated - note the type of the predecessor
field:
export interface MemberAccess extends langium.AstNode {
readonly $type: 'MemberAccess';
member: string;
predecessor: AtomicExpression;
}
The expected behavior
The predecessor
field should actually be of type AbstractExpressionChainMember
.
Reason for why the expected behavior is expected
The reason can be demonstrated with this input example:
test.test.test.test
In this example, the syntax tree looks like this:
{
$type:"MemberAccess",
predecessor: {
$type:"MemberAccess",
predecessor: {
$type:"MemberAccess",
predecessor: {
$type:"AtomicExpression",
atom: {
$type:"Atom",
name:"test"
}
},
member:"test"
},
member:"test"
},
member:"test"
}
You can see: The predecessor
field will points to objects that are either of type MemberAccess
or of type AtomicExpression
. So this example disproves the assumption that the predecessor
field will always point to AtomicExpression
-typed objects. But this is what the generated TypeScript interface definition implies.