11using Parlot . Compilation ;
2- using Parlot . Rewriting ;
32using Parlot . SourceGeneration ;
43using System ;
54using System . Collections . Generic ;
@@ -42,10 +41,12 @@ public override bool Parse(ParseContext context, ref ParseResult<T> result)
4241 }
4342
4443 var value = result . Value ;
44+ var end = result . End ;
4545
4646 // Parse zero or more (operator operand) pairs
4747 while ( true )
4848 {
49+ var operatorPosition = context . Scanner . Cursor . Position ;
4950 var operatorResult = new ParseResult < TInput > ( ) ;
5051 Func < T , T , T > ? matchedFactory = null ;
5152
@@ -69,16 +70,17 @@ public override bool Parse(ParseContext context, ref ParseResult<T> result)
6970 var rightResult = new ParseResult < T > ( ) ;
7071 if ( ! _parser . Parse ( context , ref rightResult ) )
7172 {
72- // Operator matched but no right operand - this is an error
73- // For now we just stop parsing here
73+ // Operator matched but no right operand - rollback operator consumption.
74+ context . Scanner . Cursor . ResetPosition ( operatorPosition ) ;
7475 break ;
7576 }
7677
7778 // Apply the operator
7879 value = matchedFactory ( value , rightResult . Value ) ;
80+ end = rightResult . End ;
7981 }
8082
81- result = new ParseResult < T > ( result . Start , result . End , value ) ;
83+ result = new ParseResult < T > ( result . Start , end , value ) ;
8284
8385 context . ExitParser ( this ) ;
8486 return true ;
@@ -92,6 +94,7 @@ public CompilationResult Compile(CompilationContext context)
9294 var nextNum = context . NextNumber ;
9395 var currentValue = result . DeclareVariable < T > ( $ "leftAssocValue{ nextNum } ") ;
9496 var matchedFactory = result . DeclareVariable < Func < T , T , T > > ( $ "matchedFactory{ nextNum } ") ;
97+ var operatorPosition = result . DeclareVariable < TextPosition > ( $ "leftAssocPos{ nextNum } ") ;
9598
9699 var breakLabel = Expression . Label ( $ "leftAssocBreak{ nextNum } ") ;
97100
@@ -152,13 +155,20 @@ public CompilationResult Compile(CompilationContext context)
152155 operatorChecks . AddRange ( checkBlock ) ;
153156 }
154157
158+ var scanner = Expression . Field ( context . ParseContext , nameof ( ParseContext . Scanner ) ) ;
159+ var cursor = Expression . Field ( scanner , nameof ( Scanner . Cursor ) ) ;
160+ var cursorPosition = Expression . Property ( cursor , nameof ( Cursor . Position ) ) ;
161+ var resetPosition = typeof ( Cursor ) . GetMethod ( nameof ( Cursor . ResetPosition ) , [ typeof ( TextPosition ) . MakeByRefType ( ) ] ) ! ;
162+
155163 // Build the loop body with its own variable scope
156164 var loopBody = Expression . Block (
157165 // Include operator variables and right parser variables in the loop scope
158166 allOperatorVariables . Concat ( rightParserResult . Variables ) ,
159167 new Expression [ ] {
160168 // Reset matchedFactory
161- Expression . Assign ( matchedFactory , Expression . Constant ( null , typeof ( Func < T , T , T > ) ) )
169+ Expression . Assign ( matchedFactory , Expression . Constant ( null , typeof ( Func < T , T , T > ) ) ) ,
170+ // Capture cursor position before attempting to match an operator
171+ Expression . Assign ( operatorPosition , cursorPosition )
162172 }
163173 . Concat ( operatorChecks )
164174 . Concat ( [
@@ -173,7 +183,10 @@ public CompilationResult Compile(CompilationContext context)
173183 // If right operand failed, break
174184 Expression . IfThen (
175185 Expression . Not ( rightParserResult . Success ) ,
176- Expression . Break ( breakLabel )
186+ Expression . Block (
187+ Expression . Call ( cursor , resetPosition , operatorPosition ) ,
188+ Expression . Break ( breakLabel )
189+ )
177190 ) ,
178191
179192 // Apply operator: currentValue = matchedFactory(currentValue, rightValue)
@@ -222,6 +235,7 @@ public SourceResult GenerateSource(SourceGenerationContext context)
222235
223236 var result = context . CreateResult ( typeof ( T ) ) ;
224237 var ctx = context . ParseContextName ;
238+ var cursorName = context . CursorName ;
225239 var valueTypeName = SourceGenerationContext . GetTypeName ( typeof ( T ) ) ;
226240 var inputTypeName = SourceGenerationContext . GetTypeName ( typeof ( TInput ) ) ;
227241
@@ -265,6 +279,8 @@ static Type GetParserValueType(object parser)
265279 result . Body . Add ( " while (true)" ) ;
266280 result . Body . Add ( " {" ) ;
267281 result . Body . Add ( $ " { operatorMatchedName } = false;") ;
282+ var operatorPositionName = $ "opPos{ context . NextNumber ( ) } ";
283+ result . Body . Add ( $ " var { operatorPositionName } = { cursorName } .Position;") ;
268284
269285 // Generate operator matching for each operator
270286 for ( int i = 0 ; i < _operators . Length ; i ++ )
@@ -301,11 +317,10 @@ static Type GetParserValueType(object parser)
301317
302318 var innerIndent = i == 0 ? indent : $ "{ indent } ";
303319 result . Body . Add ( $ "{ innerIndent } {{") ;
304- result . Body . Add ( $ "{ innerIndent } { operatorMatchedName } = true;") ;
305-
306320 // Parse right operand using helper
307321 result . Body . Add ( $ "{ innerIndent } if ({ baseHelperName } ({ ctx } , out var { opResultName } RightValue))") ;
308322 result . Body . Add ( $ "{ innerIndent } {{") ;
323+ result . Body . Add ( $ "{ innerIndent } { operatorMatchedName } = true;") ;
309324 if ( ! context . DiscardResult )
310325 {
311326 result . Body . Add ( $ "{ innerIndent } { result . ValueVariable } = { factoryFieldName } ({ result . ValueVariable } , { opResultName } RightValue);") ;
@@ -315,6 +330,11 @@ static Type GetParserValueType(object parser)
315330 result . Body . Add ( $ "{ innerIndent } { factoryFieldName } ({ result . ValueVariable } , { opResultName } RightValue);") ;
316331 }
317332 result . Body . Add ( $ "{ innerIndent } }}") ;
333+ result . Body . Add ( $ "{ innerIndent } else") ;
334+ result . Body . Add ( $ "{ innerIndent } {{") ;
335+ result . Body . Add ( $ "{ innerIndent } { cursorName } .ResetPosition({ operatorPositionName } );") ;
336+ result . Body . Add ( $ "{ innerIndent } break;") ;
337+ result . Body . Add ( $ "{ innerIndent } }}") ;
318338 result . Body . Add ( $ "{ innerIndent } }}") ;
319339
320340 if ( i > 0 )
0 commit comments