88namespace ExtensibleParaser ;
99
1010public class Parser ( Terminal trivia , Log ? log = null )
11- {
11+ {
1212#pragma warning disable IDE0079 // Remove unnecessary suppression
1313#pragma warning disable CA2211 // Non-constant fields should not be visible
1414 /// <summary>
1515 /// Используется только для отладки. Позволяет отображать разобранный код в наследниках Node не храня в нем входной строки.
1616 /// </summary>
17- [ ThreadStatic ]
17+ [ ThreadStatic ]
1818 [ Obsolete ( "This field should be used for debugging purposes only. Do not use it in the visitor parser itself." ) ]
1919 public static string ? Input ;
2020#pragma warning restore CA2211 // Non-constant fields should not be visible
2121#pragma warning restore IDE0079 // Remove unnecessary suppression
2222
23- public int ErrorPos { get ; private set ; }
23+ public int ErrorPos { get ; private set ; }
2424 public FatalError ErrorInfo { get ; private set ; }
2525
2626 private int _recoverySkipPos = - 1 ;
@@ -39,8 +39,8 @@ private void Log(string message, LogImportance importance = LogImportance.Normal
3939 public Dictionary < string , Rule [ ] > Rules { get ; } = new ( ) ;
4040 public Dictionary < string , TdoppRule > TdoppRules { get ; } = new ( ) ;
4141
42- private readonly Dictionary < ( int pos , string rule , int precedence ) , Result > _memo = new ( ) ;
43-
42+ private readonly Dictionary < ( int pos , string rule , int precedence ) , Result > _memo = new ( ) ;
43+
4444 public void BuildTdoppRules ( )
4545 {
4646 var inlineableRules = TdoppRules
@@ -159,8 +159,8 @@ public Result Parse(string input, string startRule, out int triviaLength, int st
159159 var normalResult = ParseRule ( startRule , minPrecedence : 0 , startPos : currentStartPos , input ) ;
160160
161161 if ( normalResult . TryGetSuccess ( out _ , out var newPos ) && newPos == input . Length )
162- return normalResult ;
163-
162+ return normalResult ;
163+
164164 ErrorInfo = ( input , ErrorPos , Location : input . PositionToLineCol ( ErrorPos ) , _expected . ToArray ( ) ) ;
165165
166166 if ( ErrorPos <= oldErrorPos )
@@ -380,6 +380,7 @@ private Result ParseAlternative(
380380 OftenMissed o => ParseOftenMissed ( o , startPos , input ) ,
381381 AndPredicate a => ParseAndPredicate ( a , startPos , input ) ,
382382 NotPredicate n => ParseNotPredicate ( n , startPos , input ) ,
383+ SeparatedList sl => ParseSeparatedList ( sl , startPos , input ) ,
383384 _ => throw new IndexOutOfRangeException ( $ "Unsupported rule type: { rule . GetType ( ) . Name } : { rule } ")
384385 } ;
385386
@@ -627,5 +628,101 @@ private Result ParseSeq(
627628 }
628629
629630 return Result . Success ( new SeqNode ( seq . Kind ?? "Seq" , elements , startPos , newPos ) , newPos , maxFailPos ) ;
630- }
631+ }
632+
633+ // пока сделал разделение что было наглядно на ревью, по идее нужно объединить после обсуждения норм или не норм.
634+ private Result ParseSeparatedList ( SeparatedList listRule , int startPos , string input )
635+ {
636+ Log ( $ "Parsing at { startPos } SeparatedList: { listRule } ") ;
637+
638+ var elements = new List < ISyntaxNode > ( ) ;
639+ var delimiters = new List < ISyntaxNode > ( ) ;
640+
641+ int currentPos = startPos ;
642+
643+ // Первый элемент
644+ var firstResult = ParseAlternative ( listRule . Element , currentPos , input ) ;
645+
646+ if ( ! firstResult . TryGetSuccess ( out var firstNode , out var newPos ) )
647+ {
648+ if ( listRule . CanBeEmpty )
649+ {
650+ // Обработка пустого списка
651+ return Result . Success (
652+ new ListNode ( listRule . Kind , elements , delimiters , startPos , startPos ) ,
653+ newPos : startPos ,
654+ maxFailPos : startPos ) ;
655+ }
656+
657+ Log ( $ "SeparatedList: first element required at { currentPos } ") ;
658+ return Result . Failure ( firstResult . MaxFailPos ) ;
659+ }
660+
661+ var maxFailPos = firstResult . MaxFailPos ;
662+ elements . Add ( firstNode ) ;
663+ currentPos = newPos ;
664+
665+ // Последующие элементы
666+ while ( true )
667+ {
668+ // Парсинг разделителя
669+ var sepResult = ParseAlternative ( listRule . Separator , currentPos , input ) ;
670+ if ( sepResult . MaxFailPos > maxFailPos )
671+ maxFailPos = sepResult . MaxFailPos ;
672+
673+ if ( ! sepResult . TryGetSuccess ( out var sepNode , out newPos ) )
674+ {
675+ if ( listRule . EndBehavior == SeparatorEndBehavior . Required )
676+ {
677+ Log ( $ "Missing separator at { currentPos } .") ;
678+ return Result . Failure ( maxFailPos ) ;
679+ }
680+
681+ break ;
682+ }
683+
684+ // Добавляем разделитель
685+ delimiters . Add ( sepNode ) ;
686+ currentPos = newPos ;
687+
688+ // Парсинг элемента после разделителя
689+ var elemResult = ParseAlternative ( listRule . Element , currentPos , input ) ;
690+ if ( elemResult . MaxFailPos > maxFailPos )
691+ maxFailPos = elemResult . MaxFailPos ;
692+
693+ if ( ! elemResult . TryGetSuccess ( out var elemNode , out newPos ) )
694+ {
695+ if ( listRule . EndBehavior == SeparatorEndBehavior . Forbidden )
696+ {
697+ Log ( $ "End sepearator should not be present { currentPos } .") ;
698+ return Result . Failure ( maxFailPos ) ;
699+ }
700+
701+ break ;
702+ }
703+
704+ elements . Add ( elemNode ) ;
705+ currentPos = newPos ;
706+ }
707+
708+ if ( listRule . EndBehavior == SeparatorEndBehavior . Forbidden )
709+ {
710+ // Парсинг разделителя
711+ var sepResult = ParseAlternative ( listRule . Separator , currentPos , input ) ;
712+ if ( sepResult . MaxFailPos > maxFailPos )
713+ maxFailPos = sepResult . MaxFailPos ;
714+
715+ if ( sepResult . TryGetSuccess ( out var sepNode , out newPos ) )
716+ {
717+ Log ( $ "End sepearator should not be present { currentPos } .") ;
718+ return Result . Failure ( maxFailPos ) ;
719+ }
720+ }
721+
722+ return Result . Success (
723+ new ListNode ( listRule . Kind , elements , delimiters , startPos , currentPos ) ,
724+ newPos : currentPos ,
725+ maxFailPos : maxFailPos
726+ ) ;
727+ }
631728}
0 commit comments