private static TypeSpec Parse()

in Sources/Visualization/Microsoft.Psi.Visualization.Windows/Views/Visuals2D/DiagnosticsVisualization/TypeSpec.cs [143:220]


        private static TypeSpec Parse(Token[] tokens)
        {
            StringBuilder name = new StringBuilder();
            StringBuilder modifier = new StringBuilder();
            for (var i = 0; i < tokens.Length; i++)
            {
                var t = tokens[i];
                switch (t.Kind)
                {
                    case TokenKind.Name:
                        name.Clear();
                        name.Append(t.Value);
                        break;
                    case TokenKind.Open:
                        modifier.Append('['); // before ` braces represent arrays
                        break;
                    case TokenKind.Close:
                        modifier.Append(']'); // before ` braces represent arrays
                        break;
                    case TokenKind.Separator:
                        switch (t.Value)
                        {
                            case ",":
                                return new TypeSpec(name.ToString(), modifier.ToString()); // e.g. [Foo.Bar[], ... -> Bar []
                            case "`":
                                // generic type specification
                                var spec = new TypeSpec(name.ToString(), modifier.ToString());
                                if (i + 3 >= tokens.Length || tokens[i + 2].Kind != TokenKind.Open || tokens[i + 3].Kind != TokenKind.Open)
                                {
                                    return spec; // some types appear to be generic, but are _not_ followed by type params
                                }

                                // parse type params in the form [[...<param0>...],[...<param1>...],...] by matching braces and recursing
                                int match = 0;
                                for (var j = i + 3; j < tokens.Length; j++)
                                {
                                    switch (tokens[j].Kind)
                                    {
                                        case TokenKind.Open:
                                            match++;
                                            break;
                                        case TokenKind.Close:
                                            match--;
                                            break;
                                    }

                                    // sub [...<param>...] part
                                    if (match == 0 && i + 4 < tokens.Length)
                                    {
                                        var len = j - i - 5;
                                        var childTokens = new Token[len];
                                        Array.Copy(tokens, i + 4, childTokens, 0, len);
                                        spec.TypeParams.Add(Parse(childTokens)); // recurse
                                        if (j + 1 < tokens.Length && tokens[j + 1].Kind == TokenKind.Close)
                                        {
                                            return spec; // final
                                        }
                                        else
                                        {
                                            j++;
                                            i = j;
                                            if (j + 1 >= tokens.Length || tokens[j].Kind != TokenKind.Separator || tokens[j].Value != "," || tokens[j + 1].Kind != TokenKind.Open)
                                            {
                                                throw new ArgumentException("Malformed generic syntax. Expected \"Foo`123[[...],[...\"");
                                            }
                                        }
                                    }
                                }

                                break;
                        }

                        break;
                }
            }

            return new TypeSpec(name.ToString(), modifier.ToString()); // undelimited single type
        }