44using MuConvert . utils ;
55using static MuConvert . utils . Alert . LEVEL ;
66using L = MuConvert . Antlr . SimaiLexer ;
7+ using P = MuConvert . Antlr . SimaiParser ;
78
89namespace MuConvert . parser . simai ;
910
@@ -152,6 +153,8 @@ protected override void ReportMissingToken(Parser recognizer)
152153
153154 public override void Recover ( Parser recognizer , RecognitionException e )
154155 {
156+ if ( SpecificRecover ( ( P ) recognizer , e ) ) return ; // 是特定类型的错误、已通过SpecificRecover修复完成
157+
155158 if ( this . lastErrorIndex == recognizer . InputStream . Index && this . lastErrorStates != null && this . lastErrorStates . Contains ( recognizer . State ) )
156159 recognizer . Consume ( ) ;
157160 this . lastErrorIndex = recognizer . InputStream . Index ;
@@ -165,6 +168,48 @@ public override void Recover(Parser recognizer, RecognitionException e)
165168
166169 this . ConsumeUntil ( recognizer , errorRecoverySet ) ;
167170 }
171+
172+ /**
173+ * 尝试修复一些特定类型的错误。
174+ * - beats中,':'误打为'-'
175+ */
176+ protected virtual bool SpecificRecover ( P parser , RecognitionException e )
177+ {
178+ var ctx = parser . Context ;
179+ var rule = ctx . RuleIndex ;
180+ if ( rule == P . RULE_beats && e is InputMismatchException &&
181+ e . OffendingToken . Text == "-" && e . GetExpectedTokens ( ) . Contains ( _literals [ ":" ] ) )
182+ { // [4:1]中,错把:打成-了
183+ simaiParser . alerts . Last ( ) . Level = Warning ; // Error改为Warning,因为恢复了
184+ simaiParser . alerts . Last ( ) . Description += Locale . Fixed ;
185+ parser . Match ( L . SLIDE_TYPE ) ;
186+ ctx . exception = null ;
187+ parser . @int ( ) ;
188+ return true ;
189+ }
190+ return false ;
191+ }
192+
193+ /**
194+ * 重新执行func对应的解析函数,并把结果合并进oldContext。
195+ */
196+ protected void Rerun < T > ( P parser , Func < T > func , T oldContext ) where T : ParserRuleContext
197+ {
198+ // 缓存全局变量,便于稍后恢复现场
199+ var savedState = parser . State ;
200+ var savedContext = parser . Context ;
201+ // 设置现场为父级的状态,从而为再次调用解析函数做好准备
202+ parser . State = oldContext . invokingState ;
203+ parser . Context = ( ParserRuleContext ) oldContext . Parent ;
204+ // 再次调用解析函数,得到的结果(子节点)合并进oldContext、新节点删除之
205+ var newContext = func ( ) ;
206+ parser . Context ? . RemoveLastChild ( ) ; // func返回时会调用ExitRule,从而context还是oldContext.Parent不变,直接RemoveLastChild()即可移除newContext
207+ oldContext . children = oldContext . children . Concat ( newContext . children ) . ToList ( ) ;
208+ oldContext . exception = null ;
209+ // 恢复现场
210+ parser . State = savedState ;
211+ parser . Context = savedContext ;
212+ }
168213}
169214
170215/**
@@ -174,5 +219,9 @@ public class ModerateErrorStrategy(SimaiParser simaiParser) : LaxErrorStrategy(s
174219{
175220 private BailErrorStrategy _bail = new ( ) ;
176221
177- public override void Recover ( Parser recognizer , RecognitionException e ) => _bail . Recover ( recognizer , e ) ; // 不准recover,只准recoverInline
222+ public override void Recover ( Parser recognizer , RecognitionException e )
223+ {
224+ if ( SpecificRecover ( ( P ) recognizer , e ) ) return ; // 是特定类型的错误、已通过SpecificRecover修复完成,则ok
225+ _bail . Recover ( recognizer , e ) ; // 否则,不准recover(通过bail strategy的recover方法来抛异常),只准recoverInline
226+ }
178227}
0 commit comments