/// <summary> /// Type arguments for stacks are only valid on method declarations, and can have either '[' or '<' as the /// starting character depending on output source. /// /// ex: MyNamespace.MyClass.MyMethod[T](T t) /// ex: MyNamespace.MyClass.MyMethod<T<(T t) /// /// Assumes the identifier "MyMethod" has already been parsed, and the type arguments will need to be parsed. /// </summary> private Result <StackFrameTypeArgumentList> TryParseTypeArguments() { if (!_lexer.ScanCurrentCharAsTokenIfMatch( kind => kind is StackFrameKind.OpenBracketToken or StackFrameKind.LessThanToken, out var openToken)) { return(Result <StackFrameTypeArgumentList> .Empty); } var closeBracketKind = openToken.Kind is StackFrameKind.OpenBracketToken ? StackFrameKind.CloseBracketToken : StackFrameKind.GreaterThanToken; using var _ = ArrayBuilder <StackFrameNodeOrToken> .GetInstance(out var builder); var currentIdentifier = _lexer.TryScanIdentifier(scanAtTrivia: false, scanLeadingWhitespace: true, scanTrailingWhitespace: true); StackFrameToken closeToken = default; while (currentIdentifier.HasValue && currentIdentifier.Value.Kind == StackFrameKind.IdentifierToken) { builder.Add(new StackFrameIdentifierNameNode(currentIdentifier.Value)); if (_lexer.ScanCurrentCharAsTokenIfMatch(closeBracketKind, out closeToken)) { break; } if (!_lexer.ScanCurrentCharAsTokenIfMatch(StackFrameKind.CommaToken, out var commaToken)) { return(Result <StackFrameTypeArgumentList> .Abort); } builder.Add(commaToken); currentIdentifier = _lexer.TryScanIdentifier(); } if (builder.Count == 0) { return(Result <StackFrameTypeArgumentList> .Abort); } if (closeToken.IsMissing) { return(Result <StackFrameTypeArgumentList> .Abort); } var separatedList = new EmbeddedSeparatedSyntaxNodeList <StackFrameKind, StackFrameNode, StackFrameIdentifierNameNode>(builder.ToImmutable()); return(new StackFrameTypeArgumentList(openToken, separatedList, closeToken)); }
/// <summary> /// MyNamespace.MyClass.MyMethod[|(string s1, string s2, int i1)|] /// Takes parameter declarations from method text and parses them into a <see cref="StackFrameParameterList"/>. /// </summary> /// <remarks> /// This method assumes that the caller requires method parameters, and returns null for all failure cases. The caller /// should escalate to abort parsing on null values. /// </remarks> private StackFrameParameterList?TryParseRequiredMethodParameters() { if (!_lexer.ScanCurrentCharAsTokenIfMatch(StackFrameKind.OpenParenToken, scanTrailingWhitespace: true, out var openParen)) { return(null); } if (_lexer.ScanCurrentCharAsTokenIfMatch(StackFrameKind.CloseParenToken, out var closeParen)) { return(new(openParen, EmbeddedSeparatedSyntaxNodeList <StackFrameKind, StackFrameNode, StackFrameParameterDeclarationNode> .Empty, closeParen)); } using var _ = ArrayBuilder <StackFrameNodeOrToken> .GetInstance(out var builder); while (true) { var(success, parameterNode) = ParseParameterNode(); if (!success) { return(null); } RoslynDebug.AssertNotNull(parameterNode); builder.Add(parameterNode); if (!_lexer.ScanCurrentCharAsTokenIfMatch(StackFrameKind.CommaToken, out var commaToken)) { break; } builder.Add(commaToken); } if (!_lexer.ScanCurrentCharAsTokenIfMatch(StackFrameKind.CloseParenToken, out closeParen)) { return(null); } var parameters = new EmbeddedSeparatedSyntaxNodeList <StackFrameKind, StackFrameNode, StackFrameParameterDeclarationNode>(builder.ToImmutable()); return(new(openParen, parameters, closeParen)); }