-
Notifications
You must be signed in to change notification settings - Fork 87
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
.langiumfile with the code below npm run langium:generate- Check the code in the
ast.tsfile
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.