@@ -82,6 +82,30 @@ export class ASTNode {
8282 this . args = args
8383 }
8484
85+ static infix ( input , pos , op , left , right ) {
86+ return new ASTNode ( input , pos , left . #meta. start , right . #meta. end , op , [ left , right ] )
87+ }
88+
89+ static ternary ( input , pos , op , expression , consequent , alternate ) {
90+ return new ASTNode ( input , pos , expression . #meta. start , alternate . #meta. end , op , [
91+ expression ,
92+ consequent ,
93+ alternate
94+ ] )
95+ }
96+
97+ static unary ( input , pos , op , arg ) {
98+ return new ASTNode ( input , pos , pos , arg . #meta. end , op , arg )
99+ }
100+
101+ static access ( input , pos , op , left , right , end ) {
102+ return new ASTNode ( input , pos , left . #meta. start , end , op , [ left , right ] )
103+ }
104+
105+ static receiverCallStart ( args ) {
106+ return args [ 1 ] . #meta. start
107+ }
108+
85109 clone ( op , args ) {
86110 const meta = this . #meta
87111 return new ASTNode ( meta . input , meta . pos , meta . start , meta . end , op , args )
@@ -195,7 +219,6 @@ class Lexer {
195219 length
196220
197221 tokenPos
198- tokenEnd
199222 tokenType
200223 tokenValue
201224
@@ -206,9 +229,8 @@ class Lexer {
206229 return input
207230 }
208231
209- token ( pos , type , value , end = this . pos ) {
232+ token ( pos , type , value ) {
210233 this . tokenPos = pos
211- this . tokenEnd = end
212234 this . tokenType = type
213235 this . tokenValue = value
214236 return this
@@ -595,7 +617,6 @@ export class Parser {
595617
596618 type = null
597619 pos = null
598- end = null
599620
600621 constructor ( limits , registry ) {
601622 this . limits = limits
@@ -617,10 +638,33 @@ export class Parser {
617638 return node
618639 }
619640
641+ #infixNode( pos , op , left , right ) {
642+ const node = ASTNode . infix ( this . input , pos , op , left , right )
643+ if ( ! this . astNodesRemaining -- ) this . #limitExceeded( 'maxAstNodes' , pos )
644+ return node
645+ }
646+
647+ #ternaryNode( pos , expression , consequent , alternate ) {
648+ const node = ASTNode . ternary ( this . input , pos , OPS . ternary , expression , consequent , alternate )
649+ if ( ! this . astNodesRemaining -- ) this . #limitExceeded( 'maxAstNodes' , pos )
650+ return node
651+ }
652+
653+ #unaryNode( pos , op , arg ) {
654+ const node = ASTNode . unary ( this . input , pos , op , arg )
655+ if ( ! this . astNodesRemaining -- ) this . #limitExceeded( 'maxAstNodes' , pos )
656+ return node
657+ }
658+
659+ #accessNode( pos , op , left , right , end ) {
660+ const node = ASTNode . access ( this . input , pos , op , left , right , end )
661+ if ( ! this . astNodesRemaining -- ) this . #limitExceeded( 'maxAstNodes' , pos )
662+ return node
663+ }
664+
620665 #advanceToken( returnValue = this . pos ) {
621666 const l = this . lexer . nextToken ( )
622667 this . pos = l . tokenPos
623- this . end = l . tokenEnd
624668 this . type = l . tokenType
625669 return returnValue
626670 }
@@ -636,7 +680,7 @@ export class Parser {
636680 throw parseError (
637681 'expected_token' ,
638682 `Expected ${ TOKEN_BY_NUMBER [ expectedType ] } , got ${ TOKEN_BY_NUMBER [ this . type ] } ` ,
639- { pos : this . pos , start : this . pos , end : this . end , input : this . input }
683+ { pos : this . pos , start : this . pos , end : this . lexer . pos , input : this . input }
640684 )
641685 }
642686
@@ -660,13 +704,16 @@ export class Parser {
660704 throw parseError ( 'unexpected_character' , `Unexpected character: '${ this . input [ this . lexer . pos - 1 ] } '` , {
661705 pos : this . pos ,
662706 start : this . pos ,
663- end : this . end ,
707+ end : this . lexer . pos ,
664708 input : this . input
665709 } )
666710 }
667711
668- #expandMacro( pos , op , args , start = pos , end = start ) {
712+ #expandMacro( pos , op , args , start , end ) {
669713 const [ methodName , receiver , fnArgs ] = op === OPS . rcall ? args : [ args [ 0 ] , null , args [ 1 ] ]
714+ if ( start === undefined && op === OPS . rcall ) start = ASTNode . receiverCallStart ( args )
715+ if ( start === undefined ) start = pos
716+ if ( end === undefined ) end = start
670717 const decl = this . registry . findMacro ( methodName , ! ! receiver , fnArgs . length )
671718 const ast = this . #node( pos , op , args , start , end )
672719 if ( ! decl ) return ast
@@ -686,7 +733,7 @@ export class Parser {
686733 this . consume ( TOKEN . COLON )
687734 const alternate = this . parseExpression ( )
688735 this . maxDepthRemaining ++
689- return this . #node ( questionPos , OPS . ternary , [ expr , consequent , alternate ] , expr . start , alternate . end )
736+ return this . #ternaryNode ( questionPos , expr , consequent , alternate )
690737 }
691738
692739 // LogicalOr ::= LogicalAnd ('||' LogicalAnd)*
@@ -695,7 +742,7 @@ export class Parser {
695742 while ( this . match ( TOKEN . OR ) ) {
696743 const opPos = this . #advanceToken( )
697744 const right = this . parseLogicalAnd ( )
698- expr = this . #node ( opPos , OPS [ '||' ] , [ expr , right ] , expr . start , right . end )
745+ expr = this . #infixNode ( opPos , OPS [ '||' ] , expr , right )
699746 }
700747 return expr
701748 }
@@ -706,7 +753,7 @@ export class Parser {
706753 while ( this . match ( TOKEN . AND ) ) {
707754 const opPos = this . #advanceToken( )
708755 const right = this . parseEquality ( )
709- expr = this . #node ( opPos , OPS [ '&&' ] , [ expr , right ] , expr . start , right . end )
756+ expr = this . #infixNode ( opPos , OPS [ '&&' ] , expr , right )
710757 }
711758 return expr
712759 }
@@ -718,7 +765,7 @@ export class Parser {
718765 const op = OP_FOR_TOKEN [ this . type ]
719766 const opPos = this . #advanceToken( )
720767 const right = this . parseRelational ( )
721- expr = this . #node ( opPos , op , [ expr , right ] , expr . start , right . end )
768+ expr = this . #infixNode ( opPos , op , expr , right )
722769 }
723770 return expr
724771 }
@@ -736,7 +783,7 @@ export class Parser {
736783 const op = OP_FOR_TOKEN [ this . type ]
737784 const opPos = this . #advanceToken( )
738785 const right = this . parseAdditive ( )
739- expr = this . #node ( opPos , op , [ expr , right ] , expr . start , right . end )
786+ expr = this . #infixNode ( opPos , op , expr , right )
740787 }
741788 return expr
742789 }
@@ -748,7 +795,7 @@ export class Parser {
748795 const op = OP_FOR_TOKEN [ this . type ]
749796 const opPos = this . #advanceToken( )
750797 const right = this . parseMultiplicative ( )
751- expr = this . #node ( opPos , op , [ expr , right ] , expr . start , right . end )
798+ expr = this . #infixNode ( opPos , op , expr , right )
752799 }
753800 return expr
754801 }
@@ -760,7 +807,7 @@ export class Parser {
760807 const op = OP_FOR_TOKEN [ this . type ]
761808 const opPos = this . #advanceToken( )
762809 const right = this . parseUnary ( )
763- expr = this . #node ( opPos , op , [ expr , right ] , expr . start , right . end )
810+ expr = this . #infixNode ( opPos , op , expr , right )
764811 }
765812 return expr
766813 }
@@ -770,12 +817,12 @@ export class Parser {
770817 if ( this . type === TOKEN . NOT ) {
771818 const pos = this . #advanceToken( )
772819 const arg = this . parseUnary ( )
773- return this . #node ( pos , OPS . unaryNot , arg , pos , arg . end )
820+ return this . #unaryNode ( pos , OPS . unaryNot , arg )
774821 }
775822 if ( this . type === TOKEN . MINUS ) {
776823 const pos = this . #advanceToken( )
777824 const arg = this . parseUnary ( )
778- return this . #node ( pos , OPS . unaryMinus , arg , pos , arg . end )
825+ return this . #unaryNode ( pos , OPS . unaryMinus , arg )
779826 }
780827 return this . parsePostfix ( )
781828 }
@@ -796,15 +843,15 @@ export class Parser {
796843
797844 const propertyValue = this . value
798845 const propertyPos = this . pos
799- const propertyEnd = this . end
846+ const propertyEnd = this . lexer . pos
800847 this . consume ( TOKEN . IDENTIFIER )
801848 if ( op === OPS . fieldAccess && this . match ( TOKEN . LPAREN ) && this . #advanceToken( ) ) {
802849 const args = this . parseArgumentList ( )
803- const closeEnd = this . end
850+ const closeEnd = this . lexer . pos
804851 this . consume ( TOKEN . RPAREN )
805- expr = this . #expandMacro( propertyPos , OPS . rcall , [ propertyValue , expr , args ] , expr . start , closeEnd )
852+ expr = this . #expandMacro( propertyPos , OPS . rcall , [ propertyValue , expr , args ] , undefined , closeEnd )
806853 } else {
807- expr = this . #node ( propertyPos , op , [ expr , propertyValue ] , expr . start , propertyEnd )
854+ expr = this . #accessNode ( propertyPos , op , expr , propertyValue , propertyEnd )
808855 }
809856 continue
810857 }
@@ -819,9 +866,9 @@ export class Parser {
819866 : OPS . bracketAccess
820867
821868 const index = this . parseExpression ( )
822- const closeEnd = this . end
869+ const closeEnd = this . lexer . pos
823870 this . consume ( TOKEN . RBRACKET )
824- expr = this . #node ( bracket , op , [ expr , index ] , expr . start , closeEnd )
871+ expr = this . #accessNode ( bracket , op , expr , index , closeEnd )
825872 continue
826873 }
827874 break
@@ -852,19 +899,19 @@ export class Parser {
852899 throw parseError ( 'unexpected_token' , `Unexpected token: ${ TOKEN_BY_NUMBER [ this . type ] } ` , {
853900 pos : this . pos ,
854901 start : this . pos ,
855- end : this . end ,
902+ end : this . lexer . pos ,
856903 input : this . input
857904 } )
858905 }
859906
860907 #consumeLiteral( ) {
861- return this . #advanceToken( this . #node( this . pos , OPS . value , this . value , this . pos , this . end ) )
908+ return this . #advanceToken( this . #node( this . pos , OPS . value , this . value , this . pos , this . lexer . pos ) )
862909 }
863910
864911 #parseIdentifierPrimary( ) {
865912 const value = this . value
866913 const pos = this . pos
867- const end = this . end
914+ const end = this . lexer . pos
868915 this . consume ( TOKEN . IDENTIFIER )
869916 if ( RESERVED . has ( value ) ) {
870917 throw parseError ( 'reserved_identifier' , `Reserved identifier: ${ value } ` , {
@@ -878,7 +925,7 @@ export class Parser {
878925 if ( ! this . match ( TOKEN . LPAREN ) ) return this . #node( pos , OPS . id , value , pos , end )
879926 this . #advanceToken( )
880927 const args = this . parseArgumentList ( )
881- const closeEnd = this . end
928+ const closeEnd = this . lexer . pos
882929 this . consume ( TOKEN . RPAREN )
883930 return this . #expandMacro( pos , OPS . call , [ value , args ] , pos , closeEnd )
884931 }
@@ -906,7 +953,7 @@ export class Parser {
906953 }
907954 }
908955
909- const closeEnd = this . end
956+ const closeEnd = this . lexer . pos
910957 this . consume ( TOKEN . RBRACKET )
911958 return this . #node( token , OPS . list , elements , token , closeEnd )
912959 }
@@ -927,7 +974,7 @@ export class Parser {
927974 }
928975 }
929976
930- const closeEnd = this . end
977+ const closeEnd = this . lexer . pos
931978 this . consume ( TOKEN . RBRACE )
932979 return this . #node( token , OPS . map , props , token , closeEnd )
933980 }
0 commit comments