/// <summary> /// Parses a <see cref="StackFrameNameNode"/> which could either be a <see cref="StackFrameSimpleNameNode"/> or <see cref="StackFrameQualifiedNameNode" />. /// /// Nodes will be parsed for arity but not generic type arguments. /// /// <code> /// All of the following are valid nodes, where "$$" marks the parsing starting point, and "[|" + "|]" mark the endpoints of the parsed node excluding trivia /// * [|$$MyNamespace.MyClass.MyMethod|](string s) /// * MyClass.MyMethod([|$$string|] s) /// * MyClass.MyMethod([|$$string[]|] s) /// * [|$$MyClass`1.MyMethod|](string s) /// * [|$$MyClass.MyMethod|][T](T t) /// </code> /// /// </summary> private StackFrameNameNode?TryParseRequiredNameNode(bool scanAtTrivia) { var currentIdentifer = _lexer.TryScanIdentifier(scanAtTrivia: scanAtTrivia, scanLeadingWhitespace: true, scanTrailingWhitespace: false); if (!currentIdentifer.HasValue) { return(null); } var(success, genericIdentifier) = TryScanGenericTypeIdentifier(currentIdentifer.Value); if (!success) { return(null); } RoslynDebug.AssertNotNull(genericIdentifier); StackFrameNameNode nameNode = genericIdentifier; while (true) { (success, var memberAccess) = TryParseQualifiedName(nameNode); if (!success) { return(null); } if (memberAccess is null) { Debug.Assert(nameNode is StackFrameQualifiedNameNode or StackFrameSimpleNameNode); return(nameNode); } nameNode = memberAccess; } }
public StackFrameQualifiedNameNode(StackFrameNameNode left, StackFrameToken dotToken, StackFrameSimpleNameNode right) : base(StackFrameKind.MemberAccess) { Debug.Assert(dotToken.Kind == StackFrameKind.DotToken); Left = left; DotToken = dotToken; Right = right; }
/// <summary> /// Given an existing left hand side node or token, parse a qualified name if possible. Returns /// null with success if a dot token is not available /// </summary> private Result <StackFrameQualifiedNameNode> TryParseQualifiedName(StackFrameNameNode lhs) { if (!_lexer.ScanCurrentCharAsTokenIfMatch(StackFrameKind.DotToken, out var dotToken)) { return(Result <StackFrameQualifiedNameNode> .Empty); } var identifier = _lexer.TryScanIdentifier(); if (!identifier.HasValue) { return(Result <StackFrameQualifiedNameNode> .Abort); } var(success, rhs) = TryScanGenericTypeIdentifier(identifier.Value); if (!success) { return(Result <StackFrameQualifiedNameNode> .Abort); } RoslynDebug.AssertNotNull(rhs); return(new StackFrameQualifiedNameNode(lhs, dotToken, rhs)); }
/// <summary> /// Given an existing left hand side node or token, parse a qualified name if possible. Returns /// null with success if a dot token is not available /// </summary> private Result <StackFrameQualifiedNameNode> TryParseQualifiedName(StackFrameNameNode lhs) { if (!_lexer.ScanCurrentCharAsTokenIfMatch(StackFrameKind.DotToken, out var dotToken)) { return(Result <StackFrameQualifiedNameNode> .Empty); } // Check if this is a generated identifier (var success, StackFrameSimpleNameNode? rhs) = TryScanGeneratedName(); if (!success) { return(Result <StackFrameQualifiedNameNode> .Abort); } if (rhs is not null) { return(new StackFrameQualifiedNameNode(lhs, dotToken, rhs)); } // The identifier is not a generated name, parse as a normal identifier and check for generics var identifier = _lexer.TryScanIdentifier(); if (!identifier.HasValue) { return(Result <StackFrameQualifiedNameNode> .Abort); } (success, rhs) = TryScanGenericTypeIdentifier(identifier.Value); if (!success) { return(Result <StackFrameQualifiedNameNode> .Abort); } RoslynDebug.AssertNotNull(rhs); return(new StackFrameQualifiedNameNode(lhs, dotToken, rhs)); }