Exemple #1
0
        private JsonMultiValueSyntax(Union <_void, JsonListSyntax, JsonKeyValueSyntax> parent, GreenJsonMultiValueSyntax green)
        {
            Parent = parent;
            Green  = green;

            ValueNodes = new SafeLazyObjectCollection <JsonValueWithBackgroundSyntax>(
                green.ValueNodes.Count,
                index => new JsonValueWithBackgroundSyntax(this, index));

            backgroundAfter = new SafeLazyObject <JsonBackgroundListSyntax>(() => new JsonBackgroundListSyntax(this));
        }
 /// <summary>
 /// Initializes a new instance of <see cref="RootJsonSyntax"/>.
 /// </summary>
 /// <param name="syntax">
 /// The root <see cref="GreenJsonMultiValueSyntax"/> node from which to construct a <see cref="JsonMultiValueSyntax"/> abstract syntax tree.
 /// </param>
 /// <param name="errors">
 /// The enumeration containing all errors generated during a parse.
 /// </param>
 /// <exception cref="ArgumentNullException">
 /// <paramref name="syntax"/> and/or <paramref name="errors"/> are null.
 /// </exception>
 public RootJsonSyntax(GreenJsonMultiValueSyntax syntax, IEnumerable <JsonErrorInfo> errors)
 {
     if (syntax == null)
     {
         throw new ArgumentNullException(nameof(syntax));
     }
     if (errors == null)
     {
         throw new ArgumentNullException(nameof(errors));
     }
     Syntax = new JsonMultiValueSyntax(syntax);
     Errors = errors is List <JsonErrorInfo> errorList ? errorList : new List <JsonErrorInfo>(errors);
 }
Exemple #3
0
        public (GreenJsonValueSyntax, JsonSymbolType) ParseList()
        {
            var listBuilder = new List <GreenJsonMultiValueSyntax>();

            for (; ;)
            {
                GreenJsonMultiValueSyntax parsedValueNode = ParseMultiValue(JsonErrorCode.MultipleValues);

                // Always add each value, because it may contain background symbols.
                listBuilder.Add(parsedValueNode);

                // ParseMultiValue() guarantees that the next symbol is never a ValueStartSymbol.
                JsonSymbolType symbolType = CurrentToken.SymbolType;
                if (symbolType == JsonSymbolType.Comma)
                {
                    if (parsedValueNode.ValueNode.ContentNode is GreenJsonMissingValueSyntax)
                    {
                        // Two commas or '[,'.
                        Report(new JsonErrorInfo(
                                   JsonErrorCode.MissingValue,
                                   CurrentLength - CurrentToken.Length,
                                   CurrentToken.Length));
                    }
                }
                else if (symbolType == JsonSymbolType.BracketClose)
                {
                    return(new GreenJsonListSyntax(listBuilder, missingSquareBracketClose: false), ShiftToNextForegroundToken());
                }
                else
                {
                    // ':', '}', EOF; assume missing closing bracket ']'.
                    Report(new JsonErrorInfo(
                               symbolType == JsonSymbolType.Eof ? JsonErrorCode.UnexpectedEofInArray : JsonErrorCode.ControlSymbolInArray,
                               CurrentLength - CurrentToken.Length,
                               CurrentToken.Length));

                    return(new GreenJsonListSyntax(listBuilder, missingSquareBracketClose: true), symbolType);
                }
            }
        }
Exemple #4
0
        public (GreenJsonValueSyntax, JsonSymbolType) ParseMap()
        {
            var mapBuilder            = new List <GreenJsonKeyValueSyntax>();
            var keyValueSyntaxBuilder = new List <GreenJsonMultiValueSyntax>();

            // Maintain a separate set of keys to aid error reporting on duplicate keys.
            HashSet <string> foundKeys = new HashSet <string>();

            for (; ;)
            {
                // Save CurrentLength for error reporting before parsing the key.
                int keyStart = CurrentLength;
                GreenJsonMultiValueSyntax multiKeyNode  = ParseMultiValue(JsonErrorCode.MultiplePropertyKeys);
                GreenJsonValueSyntax      parsedKeyNode = multiKeyNode.ValueNode.ContentNode;

                // Analyze if this is an actual, unique property key.
                int  parsedKeyNodeStart = keyStart + multiKeyNode.ValueNode.BackgroundBefore.Length;
                bool gotKey;
                Maybe <GreenJsonStringLiteralSyntax> validKey = Maybe <GreenJsonStringLiteralSyntax> .Nothing;

                switch (parsedKeyNode)
                {
                case GreenJsonMissingValueSyntax _:
                    gotKey = false;
                    break;

                case GreenJsonStringLiteralSyntax stringLiteral:
                    gotKey = true;
                    string propertyKey = stringLiteral.Value;

                    // Expect unique keys.
                    if (!foundKeys.Contains(propertyKey))
                    {
                        validKey = stringLiteral;
                        foundKeys.Add(propertyKey);
                    }
                    else
                    {
                        Report(new JsonErrorInfo(
                                   JsonErrorCode.PropertyKeyAlreadyExists,
                                   parsedKeyNodeStart,
                                   parsedKeyNode.Length,
                                   // Take the substring, key may contain escape sequences.
                                   new JsonErrorInfoParameter <string>(Json.Substring(parsedKeyNodeStart + 1, parsedKeyNode.Length - 2))));
                    }
                    break;

                default:
                    gotKey = true;
                    Report(new JsonErrorInfo(
                               JsonErrorCode.InvalidPropertyKey,
                               parsedKeyNodeStart,
                               parsedKeyNode.Length));
                    break;
                }

                // Reuse keyValueSyntaxBuilder.
                keyValueSyntaxBuilder.Clear();
                keyValueSyntaxBuilder.Add(multiKeyNode);

                // Keep parsing multi-values until encountering a non ':'.
                JsonSymbolType symbolType = CurrentToken.SymbolType;
                bool           gotColon   = false;
                while (symbolType == JsonSymbolType.Colon)
                {
                    if (gotColon)
                    {
                        // Multiple ':' without a ','.
                        Report(new JsonErrorInfo(
                                   JsonErrorCode.MultiplePropertyKeySections,
                                   CurrentLength - CurrentToken.Length,
                                   CurrentToken.Length));
                    }
                    else
                    {
                        gotColon = true;
                    }

                    // ParseMultiValue() guarantees that the next symbol is never a ValueStartSymbol.
                    keyValueSyntaxBuilder.Add(ParseMultiValue(JsonErrorCode.MultipleValues));
                    symbolType = CurrentToken.SymbolType;
                }

                // One key-value section done.
                var jsonKeyValueSyntax = new GreenJsonKeyValueSyntax(validKey, keyValueSyntaxBuilder);

                mapBuilder.Add(jsonKeyValueSyntax);

                bool isComma      = symbolType == JsonSymbolType.Comma;
                bool isCurlyClose = symbolType == JsonSymbolType.CurlyClose;

                // '}' directly following a ',' should not report errors.
                // '..., : }' however misses both a key and a value.
                if (isComma || (isCurlyClose && (gotKey || gotColon)))
                {
                    // Report missing property key and/or value.
                    if (!gotKey)
                    {
                        Report(new JsonErrorInfo(
                                   JsonErrorCode.MissingPropertyKey,
                                   CurrentLength - CurrentToken.Length,
                                   CurrentToken.Length));
                    }

                    // Report missing value error from being reported if all value sections are empty.
                    // Example: { "key1":: 2, "key2": , }
                    // Skip the fist value section, it contains the key node.
                    if (jsonKeyValueSyntax.ValueSectionNodes.Skip(1).All(x => x.ValueNode.ContentNode is GreenJsonMissingValueSyntax))
                    {
                        Report(new JsonErrorInfo(
                                   JsonErrorCode.MissingValue,
                                   CurrentLength - CurrentToken.Length,
                                   CurrentToken.Length));
                    }
                }

                if (!isComma)
                {
                    if (isCurlyClose)
                    {
                        return(new GreenJsonMapSyntax(mapBuilder, missingCurlyClose: false), ShiftToNextForegroundToken());
                    }

                    // ']', EOF; assume missing closing bracket '}'.
                    Report(new JsonErrorInfo(
                               symbolType == JsonSymbolType.Eof ? JsonErrorCode.UnexpectedEofInObject : JsonErrorCode.ControlSymbolInObject,
                               CurrentLength - CurrentToken.Length,
                               CurrentToken.Length));

                    return(new GreenJsonMapSyntax(mapBuilder, missingCurlyClose: true), symbolType);
                }
            }
        }
Exemple #5
0
 // For root nodes.
 internal JsonMultiValueSyntax(GreenJsonMultiValueSyntax green)
     : this(_void._, green)
 {
     // Do not assign ParentIndex, its value is meaningless in this case.
 }