@@ -10,7 +10,7 @@ import type { AbstractElement, Action, Assignment, InfixRule, ParserRule } from
10
10
import { isInfixRule } from '../languages/generated/ast.js' ;
11
11
import type { Linker } from '../references/linker.js' ;
12
12
import type { LangiumCoreServices } from '../services.js' ;
13
- import type { AstNode , AstReflection , CompositeCstNode , CstNode , Mutable } from '../syntax-tree.js' ;
13
+ import type { AstNode , AstReflection , CompositeCstNode , CstNode } from '../syntax-tree.js' ;
14
14
import type { Lexer , LexerResult } from './lexer.js' ;
15
15
import type { IParserConfig } from './parser-config.js' ;
16
16
import type { ValueConverter } from './value-converter.js' ;
@@ -427,45 +427,55 @@ export class LangiumParser extends AbstractLangiumParser {
427
427
// Simply return the expression as is.
428
428
return obj . parts [ 0 ] ;
429
429
}
430
- let expression = {
431
- $type : obj . $type ,
432
- left : obj . parts [ 0 ] ,
433
- operator : obj . operators [ 0 ] ,
434
- right : obj . parts [ 1 ]
435
- } ;
436
- let lastPrecedence = precedence . get ( expression . operator ) ?? 0 ;
437
- for ( let i = 1 ; i < obj . operators . length ; i ++ ) {
438
- const op = obj . operators [ i ] ;
439
- const next = obj . parts [ i + 1 ] ;
440
- const currentPrecedence = precedence . get ( op ) ?? 0 ;
441
- if ( currentPrecedence <= lastPrecedence ) {
442
- // If the current precendence is higher (i.e. the rank is lower)
443
- // We simply create a new node and append the previous expression to the left
444
- expression = {
445
- $type : obj . $type ,
446
- left : expression ,
447
- operator : op ,
448
- right : next
449
- } ;
450
- } else {
451
- // If the precedence is lower, we need to rewrite the previous node
452
- // For that, we move the previous right node to the left side of the new node
453
- const rewrite = {
454
- $type : obj . $type ,
455
- left : expression . right ,
456
- operator : op ,
457
- right : next
458
- } ;
459
- // This new node now becomes the right side of the previous node
460
- expression . right = rewrite ;
430
+ // Find the operator with the lowest precedence (highest value in precedence map)
431
+ let lowestPrecedenceIdx = 0 ;
432
+ let lowestPrecedenceValue = - 1 ;
433
+
434
+ for ( let i = 0 ; i < obj . operators . length ; i ++ ) {
435
+ const operator = obj . operators [ i ] ;
436
+ const precedenceValue = precedence . get ( operator ) ?? Infinity ;
437
+
438
+ // If we find an operator with lower precedence or equal precedence
439
+ // (for left-to-right evaluation), update our tracking
440
+ if ( precedenceValue > lowestPrecedenceValue ) {
441
+ lowestPrecedenceValue = precedenceValue ;
442
+ lowestPrecedenceIdx = i ;
461
443
}
462
- lastPrecedence = currentPrecedence ;
463
444
}
464
- // In theory, we could rebuild the CST for the infix expression
465
- // However, there is no real benefit for it, and it might be costly (performance-wise)
466
- // We might want to revisit this decision in the future.
467
- ( expression as Mutable < AstNode > ) . $cstNode = obj . $cstNode ;
468
- return expression ;
445
+
446
+ // Split the expression at the lowest precedence operator
447
+ const leftOperators = obj . operators . slice ( 0 , lowestPrecedenceIdx ) ;
448
+ const rightOperators = obj . operators . slice ( lowestPrecedenceIdx + 1 ) ;
449
+
450
+ const leftParts = obj . parts . slice ( 0 , lowestPrecedenceIdx + 1 ) ;
451
+ const rightParts = obj . parts . slice ( lowestPrecedenceIdx + 1 ) ;
452
+
453
+ // Create sub-expressions
454
+ const leftInfix : InfixElement = {
455
+ $type : obj . $type ,
456
+ $cstNode : obj . $cstNode ,
457
+ parts : leftParts ,
458
+ operators : leftOperators
459
+ } ;
460
+ const rightInfix : InfixElement = {
461
+ $type : obj . $type ,
462
+ $cstNode : obj . $cstNode ,
463
+ parts : rightParts ,
464
+ operators : rightOperators
465
+ } ;
466
+
467
+ // Recursively build the left and right subtrees
468
+ const leftTree = this . constructInfix ( leftInfix , precedence ) ;
469
+ const rightTree = this . constructInfix ( rightInfix , precedence ) ;
470
+
471
+ // Create the final binary expression
472
+ return {
473
+ $type : obj . $type ,
474
+ $cstNode : obj . $cstNode ,
475
+ left : leftTree ,
476
+ operator : obj . operators [ lowestPrecedenceIdx ] ,
477
+ right : rightTree
478
+ } ;
469
479
}
470
480
471
481
private getAssignment ( feature : AbstractElement ) : AssignmentElement {
0 commit comments