@@ -9,15 +9,14 @@ import type { Range } from 'vscode-languageserver-types';
99import type { AbstractElement } from '../languages/generated/ast.js' ;
1010import type { AstNode , CompositeCstNode , CstNode , LeafCstNode , RootCstNode } from '../syntax-tree.js' ;
1111import { Position } from 'vscode-languageserver-types' ;
12- import { isCompositeCstNode } from '../syntax-tree.js' ;
1312import { tokenToRange } from '../utils/cst-utils.js' ;
1413
1514export class CstNodeBuilder {
1615
1716 private rootNode ! : RootCstNodeImpl ;
1817 private nodeStack : CompositeCstNodeImpl [ ] = [ ] ;
1918
20- private get current ( ) : CompositeCstNodeImpl {
19+ get current ( ) : CompositeCstNodeImpl {
2120 return this . nodeStack [ this . nodeStack . length - 1 ] ?? this . rootNode ;
2221 }
2322
@@ -37,8 +36,8 @@ export class CstNodeBuilder {
3736 return compositeNode ;
3837 }
3938
40- buildLeafNode ( token : IToken , feature : AbstractElement ) : LeafCstNode {
41- const leafNode = new LeafCstNodeImpl ( token . startOffset , token . image . length , tokenToRange ( token ) , token . tokenType , false ) ;
39+ buildLeafNode ( token : IToken , feature ? : AbstractElement ) : LeafCstNode {
40+ const leafNode = new LeafCstNodeImpl ( token . startOffset , token . image . length , tokenToRange ( token ) , token . tokenType , ! feature ) ;
4241 leafNode . grammarSource = feature ;
4342 leafNode . root = this . rootNode ;
4443 this . current . content . push ( leafNode ) ;
@@ -55,6 +54,39 @@ export class CstNodeBuilder {
5554 }
5655 }
5756
57+ addHiddenNodes ( tokens : IToken [ ] ) : void {
58+ const nodes : LeafCstNode [ ] = [ ] ;
59+ for ( const token of tokens ) {
60+ const leafNode = new LeafCstNodeImpl ( token . startOffset , token . image . length , tokenToRange ( token ) , token . tokenType , true ) ;
61+ leafNode . root = this . rootNode ;
62+ nodes . push ( leafNode ) ;
63+ }
64+ let current : CompositeCstNode = this . current ;
65+ let added = false ;
66+ // If we are within a composite node, we add the hidden nodes to the content
67+ if ( current . content . length > 0 ) {
68+ current . content . push ( ...nodes ) ;
69+ return ;
70+ }
71+ // Otherwise we are at a newly created node
72+ // Instead of adding the hidden nodes here, we search for the first parent node with content
73+ while ( current . container ) {
74+ const index = current . container . content . indexOf ( current ) ;
75+ if ( index > 0 ) {
76+ // Add the hidden nodes before the current node
77+ current . container . content . splice ( index , 0 , ...nodes ) ;
78+ added = true ;
79+ break ;
80+ }
81+ current = current . container ;
82+ }
83+ // If we arrive at the root node, we add the hidden nodes at the beginning
84+ // This is the case if the hidden nodes are the first nodes in the tree
85+ if ( ! added ) {
86+ this . rootNode . content . unshift ( ...nodes ) ;
87+ }
88+ }
89+
5890 construct ( item : { $type : string | symbol | undefined , $cstNode : CstNode } ) : void {
5991 const current : CstNode = this . current ;
6092 // The specified item could be a datatype ($type is symbol) or a fragment ($type is undefined)
@@ -70,34 +102,6 @@ export class CstNodeBuilder {
70102 this . removeNode ( node ) ;
71103 }
72104 }
73-
74- addHiddenTokens ( hiddenTokens : IToken [ ] ) : void {
75- for ( const token of hiddenTokens ) {
76- const hiddenNode = new LeafCstNodeImpl ( token . startOffset , token . image . length , tokenToRange ( token ) , token . tokenType , true ) ;
77- hiddenNode . root = this . rootNode ;
78- this . addHiddenToken ( this . rootNode , hiddenNode ) ;
79- }
80- }
81-
82- private addHiddenToken ( node : CompositeCstNode , token : LeafCstNode ) : void {
83- const { offset : tokenStart , end : tokenEnd } = token ;
84-
85- for ( let i = 0 ; i < node . content . length ; i ++ ) {
86- const child = node . content [ i ] ;
87- const { offset : childStart , end : childEnd } = child ;
88- if ( isCompositeCstNode ( child ) && tokenStart > childStart && tokenEnd < childEnd ) {
89- this . addHiddenToken ( child , token ) ;
90- return ;
91- } else if ( tokenEnd <= childStart ) {
92- node . content . splice ( i , 0 , token ) ;
93- return ;
94- }
95- }
96-
97- // We know that we haven't found a suited position for the token
98- // So we simply add it to the end of the current node
99- node . content . push ( token ) ;
100- }
101105}
102106
103107export abstract class AbstractCstNode implements CstNode {
@@ -107,7 +111,7 @@ export abstract class AbstractCstNode implements CstNode {
107111 abstract get range ( ) : Range ;
108112
109113 container ?: CompositeCstNode ;
110- grammarSource : AbstractElement ;
114+ grammarSource ? : AbstractElement ;
111115 root : RootCstNode ;
112116 private _astNode ?: AstNode ;
113117
@@ -117,7 +121,7 @@ export abstract class AbstractCstNode implements CstNode {
117121 }
118122
119123 /** @deprecated use `grammarSource` instead. */
120- get feature ( ) : AbstractElement {
124+ get feature ( ) : AbstractElement | undefined {
121125 return this . grammarSource ;
122126 }
123127
0 commit comments