@@ -17,9 +17,8 @@ import { DefaultScopeProvider } from '../../references/scope-provider.js';
1717import { findRootNode , getContainerOfType , getDocument , streamAllContents } from '../../utils/ast-utils.js' ;
1818import { toDocumentSegment } from '../../utils/cst-utils.js' ;
1919import { stream } from '../../utils/stream.js' ;
20- import { AbstractType , Interface , isAction , isGrammar , isParserRule , isReturnType , Type } from '../../languages/generated/ast.js' ;
20+ import { AbstractType , InferredType , Interface , isAction , isGrammar , isParserRule , isReturnType , Type } from '../../languages/generated/ast.js' ;
2121import { resolveImportUri } from '../internal-grammar-util.js' ;
22- import { getActionType } from '../../utils/grammar-utils.js' ;
2322
2423export class LangiumGrammarScopeProvider extends DefaultScopeProvider {
2524
@@ -46,7 +45,7 @@ export class LangiumGrammarScopeProvider extends DefaultScopeProvider {
4645 if ( precomputed && rootNode ) {
4746 const allDescriptions = precomputed . get ( rootNode ) ;
4847 if ( allDescriptions . length > 0 ) {
49- localScope = stream ( allDescriptions ) . filter ( des => des . type === Interface || des . type === Type ) ;
48+ localScope = stream ( allDescriptions ) . filter ( des => des . type === Interface || des . type === Type || des . type === InferredType ) ;
5049 }
5150 }
5251
@@ -67,7 +66,7 @@ export class LangiumGrammarScopeProvider extends DefaultScopeProvider {
6766 this . gatherImports ( grammar , importedUris ) ;
6867 let importedElements = this . indexManager . allElements ( referenceType , importedUris ) ;
6968 if ( referenceType === AbstractType ) {
70- importedElements = importedElements . filter ( des => des . type === Interface || des . type === Type ) ;
69+ importedElements = importedElements . filter ( des => des . type === Interface || des . type === Type || des . type === InferredType ) ;
7170 }
7271 return new MapScope ( importedElements ) ;
7372 }
@@ -99,60 +98,74 @@ export class LangiumGrammarScopeComputation extends DefaultScopeComputation {
9998 }
10099
101100 protected override exportNode ( node : AstNode , exports : AstNodeDescription [ ] , document : LangiumDocument ) : void {
101+ // this function is called in order to export nodes to the GLOBAL scope
102+
103+ /* Among others, TYPES need to be exported.
104+ * There are three ways to define types:
105+ * - explicit "type" declarations
106+ * - explicit "interface" declarations
107+ * - "inferred types", which can be distinguished into ...
108+ * - inferred types with explicitly declared names, i.e. parser rules with "infers", actions with "infer"
109+ * Note, that multiple explicitly inferred types might have the same name! Cross-references to such types are resolved to the first declaration.
110+ * - implicitly inferred types, i.e. parser rules without "infers" and without "returns",
111+ * which implicitly declare a type with the same name as the parser rule
112+ * Note, that implicitly inferred types are unique, since names of parser rules must be unique.
113+ */
114+
115+ // export the top-level elements: parser rules, terminal rules, types, interfaces
102116 super . exportNode ( node , exports , document ) ;
117+
118+ // additionally, export inferred types:
103119 if ( isParserRule ( node ) ) {
104120 if ( ! node . returnType && ! node . dataType ) {
105- // Export inferred rule type as interface
121+ // Export implicitly and explicitly inferred type from parser rule
106122 const typeNode = node . inferredType ?? node ;
107- exports . push ( this . createInterfaceDescription ( typeNode , typeNode . name , document ) ) ;
123+ exports . push ( this . createInferredTypeDescription ( typeNode , typeNode . name , document ) ) ;
108124 }
109125 streamAllContents ( node ) . forEach ( childNode => {
110126 if ( isAction ( childNode ) && childNode . inferredType ) {
111- const typeName = getActionType ( childNode ) ;
112- if ( typeName ) {
113- // Export inferred action type as interface
114- exports . push ( this . createInterfaceDescription ( childNode , typeName , document ) ) ;
115- }
127+ // Export explicitly inferred type from action
128+ exports . push ( this . createInferredTypeDescription ( childNode . inferredType , childNode . inferredType . name , document ) ) ;
116129 }
117130 } ) ;
118131 }
119132 }
120133
121134 protected override processNode ( node : AstNode , document : LangiumDocument , scopes : PrecomputedScopes ) : void {
122- if ( isReturnType ( node ) ) return ;
135+ // for the precompution of the local scope
136+ if ( isReturnType ( node ) ) {
137+ return ;
138+ }
123139 this . processTypeNode ( node , document , scopes ) ;
124140 this . processActionNode ( node , document , scopes ) ;
125141 super . processNode ( node , document , scopes ) ;
126142 }
127143
128144 /**
129- * Add synthetic Interface in case of explicitly or implicitly inferred type:<br>
145+ * Add synthetic type into the scope in case of explicitly or implicitly inferred type:<br>
130146 * cases: `ParserRule: ...;` or `ParserRule infers Type: ...;`
131147 */
132148 protected processTypeNode ( node : AstNode , document : LangiumDocument , scopes : PrecomputedScopes ) : void {
133149 const container = node . $container ;
134150 if ( container && isParserRule ( node ) && ! node . returnType && ! node . dataType ) {
135151 const typeNode = node . inferredType ?? node ;
136- scopes . add ( container , this . createInterfaceDescription ( typeNode , typeNode . name , document ) ) ;
152+ scopes . add ( container , this . createInferredTypeDescription ( typeNode , typeNode . name , document ) ) ;
137153 }
138154 }
139155
140156 /**
141- * Add synthetic Interface in case of explicitly inferred type:
157+ * Add synthetic type into the scope in case of explicitly inferred type:
142158 *
143159 * case: `{infer Action}`
144160 */
145161 protected processActionNode ( node : AstNode , document : LangiumDocument , scopes : PrecomputedScopes ) : void {
146162 const container = findRootNode ( node ) ;
147163 if ( container && isAction ( node ) && node . inferredType ) {
148- const typeName = getActionType ( node ) ;
149- if ( typeName ) {
150- scopes . add ( container , this . createInterfaceDescription ( node , typeName , document ) ) ;
151- }
164+ scopes . add ( container , this . createInferredTypeDescription ( node . inferredType , node . inferredType . name , document ) ) ;
152165 }
153166 }
154167
155- protected createInterfaceDescription ( node : AstNode , name : string , document : LangiumDocument = getDocument ( node ) ) : AstNodeDescription {
168+ protected createInferredTypeDescription ( node : AstNode , name : string , document : LangiumDocument = getDocument ( node ) ) : AstNodeDescription {
156169 let nameNodeSegment : DocumentSegment | undefined ;
157170 const nameSegmentGetter = ( ) => nameNodeSegment ??= toDocumentSegment ( this . nameProvider . getNameNode ( node ) ?? node . $cstNode ) ;
158171 return {
@@ -162,7 +175,7 @@ export class LangiumGrammarScopeComputation extends DefaultScopeComputation {
162175 return nameSegmentGetter ( ) ;
163176 } ,
164177 selectionSegment : toDocumentSegment ( node . $cstNode ) ,
165- type : 'Interface' ,
178+ type : InferredType ,
166179 documentUri : document . uri ,
167180 path : this . astNodeLocator . getAstNodePath ( node )
168181 } ;
0 commit comments