private static RuleResult WithType(Token t, TokenType type, Action <string> setter) { if (t.Type != type) { string msg = $@"Expected a {type}, but got the {t.Type} ""{t.Content}"" instead."; return(RuleResult.Failed(t.Position, msg)); } // It was the correct type, so extract its content using the setter. setter(t.Content); return(RuleResult.GoodSoFar()); // TODO: Consider adding an overload that returns RuleResult.Complete(), just like Expect. }
private IEnumerable <RuleResult> ImplCoroutine(CurrentTokenCallback t) { while (_shouldKeepLooping(t())) { _rules.Reset(); // Keep feeding tokens until one of the rules completes, or // until there's an error. RuleResult result = RuleResult.GoodSoFar(); while (result.status == RuleStatus.GoodSoFar) { result = _rules.FeedToken(t()); if (result.status == RuleStatus.GoodSoFar) { yield return(result); } } switch (result.status) { case RuleStatus.Complete: yield return(RuleResult.GoodSoFar()); continue; case RuleStatus.Failed: IsFinished = true; yield return(result); yield break; default: IsFinished = true; yield return(RuleResult.Failed(t().Position, "Unexpected rule result " + result.status)); yield break; } } IsFinished = true; yield return(RuleResult.Complete(_node)); }
private static RuleResult SpecificToken( Token t, TokenType type, string content, object node = null ) { if (t.Type != type || t.Content != content) { string msg = $@"Expected the {type} ""{content}"", but got the {t.Type} ""{t.Content}"" instead."; return(RuleResult.Failed(t.Position, msg)); } // If a node was provided, return a Completed result instead of GoodSoFar if (node != null) { return(RuleResult.Complete(node)); } return(RuleResult.GoodSoFar()); }
public RuleResult FeedToken(Token t) { if (!_isInitialized) { Initialize(); } if (_isFinished) { throw new Exception("Tried to feed a token to an already-finished MultiRuleParser."); } if (_remainingRules.Count == 0) { throw new Exception("Tried to feed a token to an unfinished yet empty MultiRuleParser."); } // Feed the token to each rule var ruleResults = _remainingRules .Select(r => (rule: r, result: r.FeedToken(t))) .ToArray(); // Eliminate all of the rules that failed foreach (var p in ruleResults) { if (p.result.status == RuleStatus.Failed) { _remainingRules.Remove(p.rule); // If that was the last subrule, then the whole // ruleset fails. if (_remainingRules.Count == 0) { return(p.result); } } } // If one of the rules succeeds, crown it the winner. // Its result will be returned and its callback will be // invoked. // If more than one rule succeeds, the first rule added // to the list gets priority. var completedRules = ruleResults .Where(p => p.result.status == RuleStatus.Complete); if (completedRules.Any()) { _isFinished = true; var winner = completedRules.First(); var node = winner.result.node; _ruleCallbacks[winner.rule](node); return(winner.result); } // None of them succeeded, but not all of them failed. // That's the definition of being "good so far". return(RuleResult.GoodSoFar()); }