private void ReportUnrecognizedArgument(TokenParseResult result, string argument) { switch (result.State) { case TokenParseResultState.UnknownNamedArgument: ReportLine(Strings.UnrecognizedArgument, argument); if (!string.IsNullOrEmpty(result.NamedArg)) { var possibleArgs = GetSimilarNamedArguments(result.NamedArgType, result.NamedArg).ToList(); if (possibleArgs.Count > 0) { ReportLine( " " + Strings.PossibleIntendedNamedArguments, string.Join(", ", possibleArgs.Select(a => "'" + a + "'"))); } } break; case TokenParseResultState.UnknownPositionalArgument: ReportLine(Strings.UnrecognizedArgument, argument); break; case TokenParseResultState.RequiresOptionArgument: ReportLine(Strings.MissingRequiredOptionArgument, argument); break; } }
public TokenParseResult ParseRule(Grouping group, Token startToken, ParserSettings settings) { List <SyntaxNode> nodes = new List <SyntaxNode>(); TokenParseResult groupResult = TokenParseResult.Failed(startToken); Token token; TokenParseResult ruleResult; token = startToken; foreach (Rule rule in group) { ruleResult = rule.Parse(token, settings); if (ruleResult) { if (!groupResult || settings.AlternateCritera == ParserSettings.SelectionCriteria.First || (groupResult.Node.GetTokenCount() < ruleResult.Node.GetTokenCount())) { groupResult = ruleResult; groupResult.Node.Rule = group; if (settings.AlternateCritera == ParserSettings.SelectionCriteria.First) { break; } } } } return(groupResult); }
/// <summary> /// Calls Rule's Parse and adds as child result if succesful. /// </summary> /// <param name="token"></param> /// <returns></returns> public TokenParseResult ParseRule(Token token, ParserSettings settings) { TokenParseResult result = Rule.Parse(token, settings); if (result.IsSuccesful) { SyntaxNode parentNode = new SyntaxNode(Source, token); parentNode.Add(result.Node); result.Node = parentNode; } return(result); }
public TokenParseResult ParseRule(Token token, ParserSettings settings) { TokenParseResult result; if (TokenType.Name == token.TokenType.Name) { result = TokenParseResult.Success(new SyntaxNode(Source, token), token.Next); } else { result = TokenParseResult.Failed(token); } return(result); }
public override TokenParseResult Parse(Token token, ParserSettings settings) { TokenParseResult result; if (Text == token.Text) { result = TokenParseResult.Success(new SyntaxNode(this, token), token.Next); } else { result = TokenParseResult.Failed(token); } return(result); }
/// <summary> /// Executes a parse. When this method is called, the parsing engine /// reads information from the source text (either a string or a file) /// and then reports what action was taken. This ranges from a token /// being read and recognized from the source, a parse reduction, or a type of error. /// </summary> /// <returns>ParseMessage indicating parser state.</returns> public ParseMessage Parse() { if (m_grammar == null) { return(ParseMessage.NotLoadedError); } while (true) { Token readToken; if (m_inputTokens.Count == 0) { //We must read a token readToken = m_tokenReader.ReadToken(); if (readToken == null) { return(ParseMessage.InternalError); } else if (readToken.SymbolType != SymbolType.Whitespace) { m_inputTokens.Push(readToken); if (m_commentLevel == 0 && readToken.SymbolType != SymbolType.CommentLine && readToken.SymbolType != SymbolType.CommentStart) { return(ParseMessage.TokenRead); } } } else if (m_commentLevel > 0) { //We are in a block comment readToken = m_inputTokens.PopToken(); if (readToken != null) { switch (readToken.SymbolType) { case SymbolType.CommentStart: m_commentLevel++; break; case SymbolType.CommentEnd: m_commentLevel--; break; case SymbolType.End: return(ParseMessage.CommentError); default: //Do nothing, ignore //The 'comment line' symbol is ignored as well break; } } } else { readToken = m_inputTokens.PeekToken(); if (readToken != null) { switch (readToken.SymbolType) { case SymbolType.CommentStart: m_commentLevel++; m_inputTokens.Pop(); //Remove it break; case SymbolType.CommentLine: m_inputTokens.Pop(); //Remove it and rest of line string comment = m_tokenReader.ReadToLineEnd(); m_comments[LineNumber] = comment; break; case SymbolType.Error: return(ParseMessage.LexicalError); default: //FINALLY, we can parse the token TokenParseResult parseResult = ParseToken(readToken); switch (parseResult) { case TokenParseResult.Accept: return(ParseMessage.Accept); case TokenParseResult.InternalError: return(ParseMessage.InternalError); case TokenParseResult.ReduceNormal: return(ParseMessage.Reduction); case TokenParseResult.Shift: m_inputTokens.Pop(); //A simple shift, we must continue //Okay, remove the top token, it is on the stack break; case TokenParseResult.SyntaxError: return(ParseMessage.SyntaxError); } break; } } } } }
/// <summary> /// Executes next step of parser and returns parser state. /// </summary> /// <returns>Parser current state.</returns> public ParseMessage Parse() { if (m_token.m_symbol != null) { switch (m_token.m_symbol.m_symbolType) { case SymbolType.CommentLine: DiscardInputToken(); //Remove it MoveToLineEnd(); break; case SymbolType.CommentStart: ProcessBlockComment(); break; } } while (true) { if (m_token.m_symbol == null) { //We must read a token Symbol readTokenSymbol = ReadToken(); SymbolType symbolType = readTokenSymbol.m_symbolType; if (m_commentLevel == 0 && symbolType != SymbolType.CommentLine && symbolType != SymbolType.CommentStart && symbolType != SymbolType.WhiteSpace) { return(ParseMessage.TokenRead); } } else { //==== Normal parse mode - we have a token and we are not in comment mode switch (m_token.m_symbol.m_symbolType) { case SymbolType.WhiteSpace: DiscardInputToken(); // Discard Whitespace break; case SymbolType.CommentStart: m_commentLevel = 1; // Switch to block comment mode. return(ParseMessage.CommentBlockRead); case SymbolType.CommentLine: return(ParseMessage.CommentLineRead); case SymbolType.Error: return(ParseMessage.LexicalError); default: //Finally, we can parse the token TokenParseResult parseResult = ParseToken(); switch (parseResult) { case TokenParseResult.Accept: return(ParseMessage.Accept); case TokenParseResult.InternalError: return(ParseMessage.InternalError); case TokenParseResult.ReduceNormal: return(ParseMessage.Reduction); case TokenParseResult.Shift: //A simple shift, we must continue DiscardInputToken(); // Okay, remove the top token, it is on the stack break; case TokenParseResult.SyntaxError: return(ParseMessage.SyntaxError); default: //Do nothing break; } break; } } } }
private TokenParseResult TryParseNamedArgument(string argument, string argumentPrefix, NamedArgumentType namedArgType, out IReadOnlyList <ArgumentAndValue> parsedArgs) { var prefixLength = argumentPrefix.Length; Debug.Assert(argument.Length >= prefixLength); // Figure out where the argument name ends. var endIndex = argument.IndexOfAny(_argumentSet.Attribute.ArgumentValueSeparators, prefixLength); // Special case: check for '+' and '-' for booleans. if (endIndex < 0 && argument.Length >= 2) { var lastArgumentChar = argument[argument.Length - 1]; if (ArgumentNameTerminators.Any(t => lastArgumentChar.Equals(t))) { endIndex = argument.Length - 1; } } // If we don't have a separator or terminator, then consume the full string. if (endIndex < 0) { endIndex = argument.Length; } // Extract the argument name(s), separate from the prefix // or optional argument value. var options = argument.Substring(prefixLength, endIndex - prefixLength); // Extract the option argument (a.k.a. value), if there is one. string optionArgument = null; if (argument.Length > prefixLength + options.Length) { // If there's an argument value separator, then extract the value after the separator. if (_argumentSet.Attribute.ArgumentValueSeparators.Any(sep => argument[prefixLength + options.Length] == sep)) { optionArgument = argument.Substring(prefixLength + options.Length + 1); } // Otherwise, it might be a terminator; extract the rest of the string. else { optionArgument = argument.Substring(prefixLength + options.Length); } } // Now try to figure out how many names are present. if (namedArgType == NamedArgumentType.ShortName && (_argumentSet.Attribute.AllowMultipleShortNamesInOneToken || _argumentSet.Attribute.AllowElidingSeparatorAfterShortName)) { Debug.Assert(_argumentSet.Attribute.ShortNamesAreOneCharacterLong); // Since short names are one character long, we parse them one at a // time, preparing for multiple arguments in this one token. var args = new List <ArgumentAndValue>(); for (var index = 0; index < options.Length; ++index) { // Try parsing it as a short name; bail immediately if we find an invalid // one. var possibleShortName = new string(options[index], 1); if (!_argumentSet.TryGetNamedArgument(possibleShortName, out ArgumentDefinition arg)) { parsedArgs = null; return(TokenParseResult.UnknownNamedArgument(namedArgType, possibleShortName)); } // If this parsed as a short name that takes a required option argument, // and we didn't see an option argument, and we allow mushing together // short names and their option arguments, then try parsing the rest of // this token as an option argument. var lastChar = index == options.Length - 1; if (arg.RequiresOptionArgument && _argumentSet.Attribute.AllowElidingSeparatorAfterShortName && optionArgument == null && !lastChar) { optionArgument = options.Substring(index + 1); index = options.Length - 1; lastChar = true; } if (!_argumentSet.Attribute.AllowMultipleShortNamesInOneToken && args.Count > 0) { parsedArgs = null; return(TokenParseResult.UnknownNamedArgument()); } args.Add(new ArgumentAndValue { Arg = arg, Value = lastChar ? optionArgument : null }); } parsedArgs = args; } else { // Try to look up the argument by name. if (!_argumentSet.TryGetNamedArgument(options, out ArgumentDefinition arg)) { parsedArgs = null; return(TokenParseResult.UnknownNamedArgument(namedArgType, options)); } parsedArgs = new[] { new ArgumentAndValue { Arg = arg, Value = optionArgument } }; } // If the last named argument we saw in this token required an // option argument to go with it, then yield that information // so it can be used by the caller (e.g. in completion generation). var lastArg = parsedArgs.GetLastOrDefault(); if (lastArg != null && lastArg.Arg.RequiresOptionArgument && string.IsNullOrEmpty(lastArg.Value)) { return(TokenParseResult.RequiresOptionArgument(lastArg.Arg)); } return(TokenParseResult.Ready); }
private TokenParseResult TryParseNextNamedArgument(IReadOnlyList <string> args, int index, string longNameArgumentPrefix, string shortNameArgumentPrefix, object destination, out int argsConsumed) { argsConsumed = 1; var argument = args[index]; var result = TokenParseResult.UnknownNamedArgument(); IReadOnlyList <ArgumentAndValue> parsedArgs = null; if (result.IsUnknown && longNameArgumentPrefix != null) { result = TryParseNamedArgument(argument, longNameArgumentPrefix, NamedArgumentType.LongName, out parsedArgs); } if (result.IsUnknown && shortNameArgumentPrefix != null) { result = TryParseNamedArgument(argument, shortNameArgumentPrefix, NamedArgumentType.ShortName, out parsedArgs); } // If our policy allows a named argument's value to be placed // in the following token, and if we're missing a required // value, and if there's at least one more token, then try // to parse the next token as the current argument's value. if (result.State == TokenParseResultState.RequiresOptionArgument && _argumentSet.Attribute.AllowNamedArgumentValueAsSucceedingToken && index + 1 < args.Count) { var lastParsedArg = parsedArgs.GetLast(); Debug.Assert(lastParsedArg.Arg.RequiresOptionArgument); Debug.Assert(!lastParsedArg.Arg.TakesRestOfLine); Debug.Assert(string.IsNullOrEmpty(parsedArgs.GetLast().Value)); ++index; ++argsConsumed; lastParsedArg.Value = args[index]; result = TokenParseResult.Ready; } if (!result.IsReady) { ReportUnrecognizedArgument(result, argument); return(result); } foreach (var parsedArg in parsedArgs) { // TODO: Obviate the need to use string.Empty here. var argValue = parsedArg.Value ?? string.Empty; if (parsedArg.Arg.TakesRestOfLine) { if (!parsedArg.Arg.TrySetRestOfLine(argValue, args.Skip(index + 1), destination)) { result = TokenParseResult.FailedParsing; continue; } argsConsumed = args.Count - index; // skip the rest of the line } else { if (!TryParseAndStore(parsedArg.Arg, argValue, destination)) { result = TokenParseResult.FailedParsing; continue; } } } return(result); }
/// <summary> /// Parses a Group who's children are part of a chain and do not alternate /// </summary> /// <param name="group"></param> /// <param name="token"></param> /// <returns></returns> public TokenParseResult ParseRule(Grouping group, Token startToken, ParserSettings settings) { List <SyntaxNode> nodes = new List <SyntaxNode>(); TokenParseResult groupResult = TokenParseResult.Failed(startToken); TokenParseResult ruleResult; int ruleIdx; Rule rule; Token token; // got the minimum results and wasn't an exception bool lastRuleOK; List <SyntaxNode> ruleNodes = new List <SyntaxNode>(); ruleIdx = 0; token = startToken; lastRuleOK = true; while (lastRuleOK && ruleIdx < group.Count && token != null) { // every rule has its own scope rule = group[ruleIdx]; ruleNodes.Clear(); lastRuleOK = false; while (token != null) { if (ruleResult = rule.Parse(token, settings)) { ruleNodes.Add(ruleResult); token = ruleResult.NextToken; if (ruleNodes.Count >= rule.Quantifier.MaxValue) { break; } } else { break; } } lastRuleOK = (rule.Quantifier.MinValue <= ruleNodes.Count) ^ rule.IsException; // if we achieved min qty then add to nodes. if (lastRuleOK) { nodes.AddRange(ruleNodes); ruleIdx++; } } if (lastRuleOK && ruleIdx >= group.LastRequiredRuleIndex && nodes.Count > 0) { SyntaxNode parent = new SyntaxNode(group, startToken); parent.AddRange(nodes); // token should be set to the last succesful nextToken groupResult = TokenParseResult.Success(parent, token); } return(groupResult); }
public override TokenParseResult Parse(Token token, ParserSettings settings) { return(TokenParseResult.Success(this, null, null, token)); }