Esempio n. 1
0
        /// <summary>
        /// Returns a <see cref="SyntaxError"/> for an unexpected token.
        /// </summary>
        /// <param name="token">The unexpected token.</param>
        /// <returns>A <see cref="SyntaxError"/> for <paramref name="token"/>.</returns>
        Exception UnexpectedToken(Json5Token token)
        {
            if (token.Type == Json5TokenType.Eof)
            {
                return(new Json5UnexpectedEndOfInputException(token.Line, token.Column));
            }

            return(new Json5UnexpectedInputException(token.Input, token.Line, token.Column));
        }
Esempio n. 2
0
        /// <summary>
        /// Parses and returns a <see cref="Json5Value"/>.
        /// </summary>
        /// <returns>A <see cref="Json5Value"/>.</returns>
        public Json5Value Parse()
        {
            if (this.parsed)
            {
                throw new InvalidOperationException("A Json5Parser may only be used once.");
            }

            this.state            = State.Value;
            this.root             = null;
            this.stack            = new Stack <Json5Container>();
            this.currentContainer = null;
            this.parsed           = true;

            string key = null;

start:
            Json5Token token = this.lexer.Read();

            switch (this.state)
            {
            case State.Value:
                switch (token.Type)
                {
                case Json5TokenType.String:
                    this.Add(new Json5String(token.String), key);
                    goto start;

                case Json5TokenType.Number:
                    this.Add(new Json5Number(token.Number), key);
                    goto start;

                case Json5TokenType.Punctuator:
                    switch (token.Character)
                    {
                    case '[':
                        this.Add(new Json5Array(), key);
                        goto start;

                    case '{':
                        this.Add(new Json5Object(), key);
                        goto start;
                    }

                    throw UnexpectedToken(token);

                case Json5TokenType.Identifier:
                    // Since these are literal tokens, check token.Input
                    // instead of token.String. Whereas `true` and `\x74rue`
                    // are both valid identifiers that represent the same
                    // thing, only `true` is a boolean literal.
                    switch (token.Input)
                    {
                    case "true":
                        this.Add(new Json5Boolean(true), key);
                        goto start;

                    case "false":
                        this.Add(new Json5Boolean(false), key);
                        goto start;

                    case "null":
                        this.Add(Json5Value.Null, key);
                        goto start;

                    case "Infinity":
                        this.Add(new Json5Number(double.PositiveInfinity), key);
                        goto start;

                    case "NaN":
                        this.Add(new Json5Number(double.NaN), key);
                        goto start;
                    }

                    break;
                }

                break;

            case State.BeforeArrayElement:
                if (token.Type == Json5TokenType.Punctuator && token.Character == ']')
                {
                    this.Pop();
                    goto start;
                }

                this.state = State.Value;
                goto case State.Value;

            case State.AfterArrayElement:
                if (token.Type == Json5TokenType.Punctuator)
                {
                    switch (token.Character)
                    {
                    case ',':
                        this.state = State.BeforeArrayElement;
                        goto start;

                    case ']':
                        this.Pop();
                        goto start;
                    }
                }

                break;

            case State.BeforeObjectKey:
                switch (token.Type)
                {
                case Json5TokenType.Punctuator:
                    if (token.Character == '}')
                    {
                        this.Pop();
                        goto start;
                    }

                    break;

                case Json5TokenType.Identifier:
                case Json5TokenType.String:
                    // All identifiers are valid as keys
                    // even if they are literals like
                    // `true`, `null`, or `Infinity`.
                    key        = token.String;
                    this.state = State.AfterObjectKey;
                    goto start;
                }

                break;

            case State.AfterObjectKey:
                if (token.Type != Json5TokenType.Punctuator || token.Character != ':')
                {
                    break;
                }

                this.state = State.Value;
                goto start;

            case State.AfterObjectValue:
                if (token.Type == Json5TokenType.Punctuator)
                {
                    switch (token.Character)
                    {
                    case ',':
                        this.state = State.BeforeObjectKey;
                        goto start;

                    case '}':
                        this.Pop();
                        goto start;
                    }
                }

                break;

            case State.End:
                if (token.Type == Json5TokenType.Eof)
                {
                    return(this.root);
                }

                break;
            }

            throw UnexpectedToken(token);
            //throw new Exception("Invalid tree state.");
        }