@@ -10,7 +10,7 @@ import type { AbstractElement, Action, Assignment, ParserRule } from '../languag
1010import type { Linker } from '../references/linker.js' ;
1111import type { LangiumCoreServices } from '../services.js' ;
1212import type { AstNode , AstReflection , CompositeCstNode , CstNode } from '../syntax-tree.js' ;
13- import type { Lexer } from './lexer.js' ;
13+ import type { Lexer , LexerResult } from './lexer.js' ;
1414import type { IParserConfig } from './parser-config.js' ;
1515import type { ValueConverter } from './value-converter.js' ;
1616import { defaultParserErrorProvider , EmbeddedActionsParser , LLkLookaheadStrategy } from 'chevrotain' ;
@@ -21,6 +21,7 @@ import { assignMandatoryProperties, getContainerOfType, linkContentToContainer }
2121import { CstNodeBuilder } from './cst-node-builder.js' ;
2222import type { LexingReport } from './token-builder.js' ;
2323import { toDocumentSegment } from '../utils/cst-utils.js' ;
24+ import type { CommentProvider } from '../documentation/comment-provider.js' ;
2425
2526export type ParseResult < T = AstNode > = {
2627 value : T ,
@@ -123,6 +124,7 @@ const withRuleSuffix = (name: string): string => name.endsWith(ruleSuffix) ? nam
123124export abstract class AbstractLangiumParser implements BaseParser {
124125
125126 protected readonly lexer : Lexer ;
127+ protected readonly commentProvider : CommentProvider ;
126128 protected readonly wrapper : ChevrotainWrapper ;
127129 protected _unorderedGroups : Map < string , boolean [ ] > = new Map < string , boolean [ ] > ( ) ;
128130
@@ -138,6 +140,7 @@ export abstract class AbstractLangiumParser implements BaseParser {
138140 skipValidations : production ,
139141 errorMessageProvider : services . parser . ParserErrorMessageProvider
140142 } ) ;
143+ this . commentProvider = services . documentation . CommentProvider ;
141144 }
142145
143146 alternatives ( idx : number , choices : Array < IOrAlt < any > > ) : void {
@@ -197,6 +200,7 @@ export class LangiumParser extends AbstractLangiumParser {
197200 private readonly converter : ValueConverter ;
198201 private readonly astReflection : AstReflection ;
199202 private readonly nodeBuilder = new CstNodeBuilder ( ) ;
203+ private lexerResult ?: LexerResult ;
200204 private stack : any [ ] = [ ] ;
201205 private assignmentMap = new Map < AbstractElement , AssignmentElement | undefined > ( ) ;
202206 private currentMode : CstParserMode = CstParserMode . Retain ;
@@ -236,17 +240,15 @@ export class LangiumParser extends AbstractLangiumParser {
236240 parse < T extends AstNode = AstNode > ( input : string , options : ParserOptions = { } ) : ParseResult < T > {
237241 this . currentMode = options . cst ?? CstParserMode . Retain ;
238242 this . nodeBuilder . buildRootNode ( input ) ;
239- const lexerResult = this . lexer . tokenize ( input ) ;
243+ const lexerResult = this . lexerResult = this . lexer . tokenize ( input ) ;
240244 this . wrapper . input = lexerResult . tokens ;
241245 const ruleMethod = options . rule ? this . allRules . get ( options . rule ) : this . mainRule ;
242246 if ( ! ruleMethod ) {
243247 throw new Error ( options . rule ? `No rule found with name '${ options . rule } '` : 'No main rule available.' ) ;
244248 }
245249 const result = ruleMethod . call ( this . wrapper , { } ) ;
246- if ( this . currentMode === CstParserMode . Retain ) {
247- this . nodeBuilder . addHiddenTokens ( lexerResult . hidden ) ;
248- }
249250 this . unorderedGroups . clear ( ) ;
251+ this . lexerResult = undefined ;
250252 return {
251253 value : result ,
252254 lexerErrors : lexerResult . errors ,
@@ -277,9 +279,32 @@ export class LangiumParser extends AbstractLangiumParser {
277279 } ;
278280 }
279281
282+ private appendHiddenTokens ( tokens : IToken [ ] ) : void {
283+ for ( const token of tokens ) {
284+ this . nodeBuilder . buildLeafNode ( token ) ;
285+ }
286+ }
287+
288+ private getHiddenTokens ( token : IToken ) : IToken [ ] {
289+ const hiddenTokens = this . lexerResult ! . hidden ;
290+ if ( ! hiddenTokens . length ) {
291+ return [ ] ;
292+ }
293+ const offset = token . startOffset ;
294+ for ( let i = 0 ; i < hiddenTokens . length ; i ++ ) {
295+ const token = hiddenTokens [ i ] ;
296+ if ( token . startOffset > offset ) {
297+ return hiddenTokens . splice ( 0 , i ) ;
298+ }
299+ }
300+ return hiddenTokens . splice ( 0 , hiddenTokens . length ) ;
301+ }
302+
280303 consume ( idx : number , tokenType : TokenType , feature : AbstractElement ) : void {
281304 const token = this . wrapper . wrapConsume ( idx , tokenType ) ;
282305 if ( ! this . isRecording ( ) && this . isValidToken ( token ) ) {
306+ const hiddenTokens = this . getHiddenTokens ( token ) ;
307+ this . appendHiddenTokens ( hiddenTokens ) ;
283308 const leafNode = this . nodeBuilder . buildLeafNode ( token , feature ) ;
284309 const { assignment, isCrossRef } = this . getAssignment ( feature ) ;
285310 const current = this . current ;
@@ -374,9 +399,12 @@ export class LangiumParser extends AbstractLangiumParser {
374399 } else {
375400 assignMandatoryProperties ( this . astReflection , obj ) ;
376401 }
402+ obj . $cstNode = cstNode ;
403+ delete obj . $segments . comment ;
404+ obj . $segments . comment = this . commentProvider . getComment ( obj ) ;
377405 obj . $segments . full = toDocumentSegment ( cstNode ) ;
378- if ( this . currentMode === CstParserMode . Retain ) {
379- obj . $cstNode = cstNode ;
406+ if ( this . currentMode === CstParserMode . Discard ) {
407+ obj . $cstNode = undefined ;
380408 }
381409 return [ obj , cstNode ] ;
382410 }
0 commit comments