private void ScanStackedOptions( ElementsCursor <SyntaxToken> cursor, List <SyntaxError> errors, SyntaxToken nameMarker, SyntaxToken name, IReadOnlyList <string> commandName, List <ArgumentSyntax> arguments) { var builder = new SyntaxTokenBuilder(); var optionsSpan = name.Span; string optionNames = name.StringValue; int optionsCount = optionNames.Length; GetShortOptionName(errors, builder, optionsSpan, optionNames, 0); var shortName = builder.Build(); var option = new OptionSyntax(nameMarker, shortName, valueMarker: null, value: null); arguments.Add(option); nameMarker = null; for (int i = 1; i < optionsCount - 1; i++) { GetShortOptionName(errors, builder, optionsSpan, optionNames, i); shortName = builder.Build(); option = new OptionSyntax(nameMarker, shortName, valueMarker: null, value: null); arguments.Add(option); } GetShortOptionName(errors, builder, optionsSpan, optionNames, optionsCount - 1); if (name.HasTrailingTrivia) { builder.TrailingTrivia = name.TrailingTrivia; } name = builder.Build(); option = ScanOption(cursor, errors, nameMarker, name, commandName); arguments.Add(option); }
private SyntaxToken ScanEndOfInput( ElementsCursor <SyntaxToken> cursor, List <SyntaxError> errors) { var token = cursor.Peek(); if (token.Kind == SyntaxKind.EndOfInputToken) { return(token); } var builder = new SyntaxTokenBuilder(); var span = token.FullSpan; _syntaxFactory.EndOfInputToken(builder, span.Source, span.Start, missing: true); errors.Add(_syntaxFactory.MissingEndOfInputError(builder.Span)); if (!span.IsEmpty) { int start = span.Start; int length = cursor.TerminalElement.FullSpan.End - start; builder.TrailingTrivia = _syntaxFactory.UndefinedTrivia(span.Source, start, length); errors.Add(_syntaxFactory.UnrecognizedInputError(builder.TrailingTrivia.Span)); } return(builder.Build()); }
private ValueSyntax ScanValue(ElementsCursor <SyntaxToken> cursor, List <SyntaxError> errors) { var token = cursor.Peek(); cursor.MoveNext(); if (token.Kind == SyntaxKind.QuotedLiteralToken || !HasMoreTokens(cursor)) { if (!HasSpaceAfterOrEnd(token, cursor.Peek(1))) { // Quoted literals do not merge with any other literal // even if they don't have spaces between them. var builder = new SyntaxTokenBuilder(token); builder.TrailingTrivia = _syntaxFactory.WhitespaceTriviaAfter(token, length: 0, missing: true); token = builder.Build(); errors.Add(_syntaxFactory.MissingWhitespaceError(token.TrailingTrivia.Span)); } if (token.Kind == SyntaxKind.QuotedLiteralToken && !HasClosingQuote(token)) { var span = token.Span; errors.Add(_syntaxFactory.MissingClosingQuoteError( new TextSpan(span.Source, span.End, 0))); } return(new ValueSyntax(token)); } return(ScanMultiTokenValue(cursor, errors, token)); }
private SyntaxToken GetTerminalElement(SyntaxToken[] tokens, string commandLine) { var terminalElement = tokens.LastOrDefault(); if (terminalElement == null || terminalElement.Kind != SyntaxKind.EndOfInputToken) { var builder = new SyntaxTokenBuilder(); _syntaxFactory.EndOfInputToken(builder, commandLine, terminalElement?.FullSpan.End ?? 0, missing: true); terminalElement = builder.Build(); } return(terminalElement); }
private CommandNameSyntax ScanCommandName( ElementsCursor <SyntaxToken> cursor, List <SyntaxError> errors, CancellationToken cancellation, out IReadOnlyList <string> commandName) { var nameParts = new List <SyntaxToken>(); var command = new List <string>(); while (HasMoreTokens(cursor) && !cancellation.IsCancellationRequested) { var token = cursor.Peek(); if (!IsIdentifier(token)) { break; } string subcommand = token.StringValue; if (!_semanticModel.HasSubCommand(command, subcommand)) { break; } if (!HasSpaceAfterOrEnd(token, cursor.Peek(1))) { var builder = new SyntaxTokenBuilder(token); builder.TrailingTrivia = _syntaxFactory.WhitespaceTriviaAfter(token, length: 0, missing: true); token = builder.Build(); errors.Add(_syntaxFactory.MissingWhitespaceError(token.TrailingTrivia.Span)); } command.Add(subcommand); nameParts.Add(token); cursor.MoveNext(); } cancellation.ThrowIfCancellationRequested(); commandName = command; if (nameParts.Count == 0) { return(null); } return(new CommandNameSyntax(nameParts)); }
public IEnumerable <SyntaxToken> Lex(string commandLine, CancellationToken cancellation = default) { if (commandLine == null) { throw new ArgumentNullException(nameof(commandLine)); } cancellation.ThrowIfCancellationRequested(); var chars = new CharsReadOnlyList(commandLine); var cursor = new ElementsCursor <char>(chars, EndOfInput); var builder = new SyntaxTokenBuilder(); do { builder.LeadingTrivia = LexSyntaxTrivia(commandLine, cursor); LexSyntaxToken(builder, commandLine, cursor); builder.TrailingTrivia = LexSyntaxTrivia(commandLine, cursor); cancellation.ThrowIfCancellationRequested(); yield return(builder.Build()); } while (builder.Kind != SyntaxKind.EndOfInputToken); }
private ValueSyntax ScanMultiTokenValue( ElementsCursor <SyntaxToken> cursor, List <SyntaxError> errors, SyntaxToken first) { var tokens = new List <SyntaxToken>(); var token = first; tokens.Add(token); while (HasMoreTokens(cursor)) { var next = cursor.Peek(); if (HasSpaceAfterOrEnd(token, next)) { break; } if (next.Kind == SyntaxKind.QuotedLiteralToken) { // Quoted literals do not merge with any other literal // even if they don't have spaces between them. var builder = new SyntaxTokenBuilder(token); builder.TrailingTrivia = _syntaxFactory.WhitespaceTriviaAfter(token, length: 0, missing: true); tokens[tokens.Count - 1] = builder.Build(); errors.Add(_syntaxFactory.MissingWhitespaceError(builder.TrailingTrivia.Span)); break; } token = next; tokens.Add(token); cursor.MoveNext(); } return(new ValueSyntax(tokens)); }
private OptionSyntax ScanOption(ElementsCursor <SyntaxToken> cursor, List <SyntaxError> errors, SyntaxToken nameMarker, SyntaxToken name, IReadOnlyList <string> commandName) { SyntaxToken valueMarker = null; ValueSyntax value = null; if (!HasMoreTokens(cursor)) { return(new OptionSyntax(nameMarker, name, valueMarker, value)); } var token = cursor.Peek(); if (IsOptionValueMarker(token)) { valueMarker = token; cursor.MoveNext(); token = cursor.Peek(); } else { if (!HasSpaceAfterOrEnd(name, token)) { var builder = new SyntaxTokenBuilder(name); builder.TrailingTrivia = _syntaxFactory.WhitespaceTriviaAfter(name, length: 0, missing: true); name = builder.Build(); errors.Add(_syntaxFactory.MissingWhitespaceError(name.TrailingTrivia.Span)); } _semanticModel.TryGetOptionType(commandName, name.StringValue, out Type valueType); if (IsFlag(valueType)) { // Flag can have a value only if a value marker is specified // because it have value 'true' by default. return(new OptionSyntax(nameMarker, name, valueMarker, value)); } } bool missingValue = valueMarker != null && (!HasMoreTokens(cursor) || (valueMarker.HasTrailingTrivia && IsOptionNameOrEndOfOptions(token, cursor.Peek(1)))); if (missingValue) { SyntaxToken valueToken = null; var builder = new SyntaxTokenBuilder(); var span = valueMarker.Span; _syntaxFactory.LiteralToken(builder, span.Source, span.End, 0, null, missing: true); if (valueMarker.HasTrailingTrivia) { // Place trailing trivia after missing option value builder.TrailingTrivia = valueMarker.TrailingTrivia; valueToken = builder.Build(); // and remove it from value marker. builder.InitializeWith(valueMarker); builder.TrailingTrivia = null; valueMarker = builder.Build(); } else { valueToken = builder.Build(); } errors.Add(_syntaxFactory.MissingOptionValueError(valueToken.Span)); value = new ValueSyntax(valueToken); return(new OptionSyntax(nameMarker, name, valueMarker, value)); } bool isValue = (valueMarker != null && !valueMarker.HasTrailingTrivia) || !IsOptionNameOrEndOfOptions(token, cursor.Peek(1)); if (isValue) { value = ScanValue(cursor, errors); } return(new OptionSyntax(nameMarker, name, valueMarker, value)); }