| File: EmbeddedLanguages\Json\JsonNodes.cs | Web Access |
| Project: src\roslyn\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.EmbeddedLanguages.Common; namespace Microsoft.CodeAnalysis.Features.EmbeddedLanguages.Json; using JsonNodeOrToken = EmbeddedSyntaxNodeOrToken<JsonKind, JsonNode>; using JsonSeparatedList = EmbeddedSeparatedSyntaxNodeList<JsonKind, JsonNode, JsonValueNode>; using JsonToken = EmbeddedSyntaxToken<JsonKind>; internal sealed class JsonCompilationUnit : JsonNode { public JsonCompilationUnit(ImmutableArray<JsonValueNode> sequence, JsonToken endOfFileToken) : base(JsonKind.CompilationUnit) { Debug.Assert(sequence != null); Debug.Assert(endOfFileToken.Kind == JsonKind.EndOfFile); Sequence = sequence; EndOfFileToken = endOfFileToken; } /// <summary> /// For error recovery purposes, we support a sequence of nodes at the top level (even /// though only a single node is actually allowed). /// </summary> public ImmutableArray<JsonValueNode> Sequence { get; } public JsonToken EndOfFileToken { get; } internal override int ChildCount => Sequence.Length + 1; internal override JsonNodeOrToken ChildAt(int index) { if (index == Sequence.Length) return EndOfFileToken; return Sequence[index]; } public override void Accept(IJsonNodeVisitor visitor) => visitor.Visit(this); } /// <summary> /// Root of all value nodes. /// </summary> internal abstract class JsonValueNode : JsonNode { protected JsonValueNode(JsonKind kind) : base(kind) { } } /// <summary> /// Represents a chunk of text that we did not understand as anything special. i.e. it wasn't a keyword, number, or /// literal. One common case of this is an unquoted property name (which json.net accepts). /// </summary> internal sealed class JsonTextNode : JsonValueNode { public JsonTextNode(JsonToken textToken) : base(JsonKind.Text) { Debug.Assert(textToken.Kind == JsonKind.TextToken); TextToken = textToken; } public JsonToken TextToken { get; } internal override int ChildCount => 1; internal override JsonNodeOrToken ChildAt(int index) => index switch { 0 => TextToken, _ => throw new InvalidOperationException(), }; public override void Accept(IJsonNodeVisitor visitor) => visitor.Visit(this); } internal sealed class JsonObjectNode : JsonValueNode { public JsonObjectNode( JsonToken openBraceToken, JsonSeparatedList sequence, JsonToken closeBraceToken) : base(JsonKind.Object) { Debug.Assert(openBraceToken.Kind == JsonKind.OpenBraceToken); Debug.Assert(closeBraceToken.Kind == JsonKind.CloseBraceToken); OpenBraceToken = openBraceToken; Sequence = sequence; CloseBraceToken = closeBraceToken; } public JsonToken OpenBraceToken { get; } public JsonSeparatedList Sequence { get; } public JsonToken CloseBraceToken { get; } internal override int ChildCount => 2 + Sequence.NodesAndTokens.Length; internal override JsonNodeOrToken ChildAt(int index) { if (index == 0) return OpenBraceToken; if (index == Sequence.NodesAndTokens.Length + 1) return CloseBraceToken; return Sequence.NodesAndTokens[index - 1]; } public override void Accept(IJsonNodeVisitor visitor) => visitor.Visit(this); } internal sealed class JsonArrayNode : JsonValueNode { public JsonArrayNode( JsonToken openBracketToken, ImmutableArray<JsonValueNode> sequence, JsonToken closeBracketToken) : base(JsonKind.Array) { Debug.Assert(openBracketToken.Kind == JsonKind.OpenBracketToken); Debug.Assert(sequence != null); Debug.Assert(closeBracketToken.Kind == JsonKind.CloseBracketToken); OpenBracketToken = openBracketToken; Sequence = sequence; CloseBracketToken = closeBracketToken; } public JsonToken OpenBracketToken { get; } public ImmutableArray<JsonValueNode> Sequence { get; } public JsonToken CloseBracketToken { get; } internal override int ChildCount => 2 + Sequence.Length; internal override JsonNodeOrToken ChildAt(int index) { if (index == 0) return OpenBracketToken; if (index == Sequence.Length + 1) return CloseBracketToken; return Sequence[index - 1]; } public override void Accept(IJsonNodeVisitor visitor) => visitor.Visit(this); } internal sealed class JsonNegativeLiteralNode : JsonValueNode { public JsonNegativeLiteralNode(JsonToken minusToken, JsonToken literalToken) : base(JsonKind.NegativeLiteral) { Debug.Assert(minusToken.Kind == JsonKind.MinusToken); MinusToken = minusToken; LiteralToken = literalToken; } public JsonToken MinusToken { get; } public JsonToken LiteralToken { get; } internal override int ChildCount => 2; internal override JsonNodeOrToken ChildAt(int index) => index switch { 0 => MinusToken, 1 => LiteralToken, _ => throw new InvalidOperationException(), }; public override void Accept(IJsonNodeVisitor visitor) => visitor.Visit(this); } internal sealed class JsonLiteralNode(JsonToken literalToken) : JsonValueNode(JsonKind.Literal) { public JsonToken LiteralToken { get; } = literalToken; internal override int ChildCount => 1; internal override JsonNodeOrToken ChildAt(int index) => index switch { 0 => LiteralToken, _ => throw new InvalidOperationException(), }; public override void Accept(IJsonNodeVisitor visitor) => visitor.Visit(this); } /// <summary> /// See the note in <see cref="JsonParser"/> for why commas are stored as values for convenience. /// </summary> internal sealed class JsonCommaValueNode : JsonValueNode { public JsonCommaValueNode(JsonToken commaToken) : base(JsonKind.CommaValue) { Debug.Assert(commaToken.Kind == JsonKind.CommaToken); CommaToken = commaToken; } public JsonToken CommaToken { get; } internal override int ChildCount => 1; internal override JsonNodeOrToken ChildAt(int index) => index switch { 0 => CommaToken, _ => throw new InvalidOperationException(), }; public override void Accept(IJsonNodeVisitor visitor) => visitor.Visit(this); } internal sealed class JsonPropertyNode : JsonValueNode { public JsonPropertyNode(JsonToken nameToken, JsonToken colonToken, JsonValueNode value) : base(JsonKind.Property) { // Note: the name is allowed by json.net to just be a text token, not a string. e.g. `goo: 0` as opposed to // `"goo": 0`. Strict json does not allow this. Debug.Assert(nameToken.Kind is JsonKind.StringToken or JsonKind.TextToken); Debug.Assert(colonToken.Kind == JsonKind.ColonToken); Debug.Assert(value != null); NameToken = nameToken; ColonToken = colonToken; Value = value; } public JsonToken NameToken { get; } public JsonToken ColonToken { get; } public JsonValueNode Value { get; } internal override int ChildCount => 3; internal override JsonNodeOrToken ChildAt(int index) => index switch { 0 => NameToken, 1 => ColonToken, 2 => Value, _ => throw new InvalidOperationException(), }; public override void Accept(IJsonNodeVisitor visitor) => visitor.Visit(this); } /// <summary> /// Json.net construction. It allows things like <c>new Date(1, 2, 3)</c>. This is not allowed in strict mode. /// </summary> internal sealed class JsonConstructorNode : JsonValueNode { public JsonConstructorNode( JsonToken newKeyword, JsonToken nameToken, JsonToken openParenToken, ImmutableArray<JsonValueNode> sequence, JsonToken closeParenToken) : base(JsonKind.Constructor) { Debug.Assert(newKeyword.Kind == JsonKind.NewKeyword); Debug.Assert(nameToken.Kind == JsonKind.TextToken); Debug.Assert(openParenToken.Kind == JsonKind.OpenParenToken); Debug.Assert(sequence != null); Debug.Assert(closeParenToken.Kind == JsonKind.CloseParenToken); NewKeyword = newKeyword; NameToken = nameToken; OpenParenToken = openParenToken; Sequence = sequence; CloseParenToken = closeParenToken; } public JsonToken NewKeyword { get; } public JsonToken NameToken { get; } public JsonToken OpenParenToken { get; } public ImmutableArray<JsonValueNode> Sequence { get; } public JsonToken CloseParenToken { get; } internal override int ChildCount => Sequence.Length + 4; internal override JsonNodeOrToken ChildAt(int index) { if (index == 0) return NewKeyword; if (index == 1) return NameToken; if (index == 2) return OpenParenToken; if (index == Sequence.Length + 3) return CloseParenToken; return Sequence[index - 3]; } public override void Accept(IJsonNodeVisitor visitor) => visitor.Visit(this); }