示例#1
0
        Signal ReadString(ref Readable <char> @in, out Tokenized @out)
        {
            int start = @in.Offset;

            for (; [email protected]; @in.Move())
            {
                switch (@in.Peek)
                {
                //below should do another move(), but checking to see if empty...
                case '\\':          //BUT! what about "\\", eh??? need to lookahead to know what to do
                    @in.Move();     //which we can't do, as we might be at end of buffer
                    break;          //if we're at end, then, what? it's like we want to look enter a special mode when we get here

                //or - maybe we have to emit a StringPart and start again
                case '"':
                    int length = @in.Offset - start;
                    @in.Move();
                    Pop();
                    return(Emit(out @out, start, length, Token.String));
                }
            }

            //x.Emit(Token.StringPart, 0, i);  //but only if i > 1...!
            return(Underrun(out @out));
        }
示例#2
0
        Signal ReadNumber(ref Readable <char> @in, out Tokenized @out)
        {
            int start = @in.Offset;

            @in.Move();

            for (; [email protected]; @in.Move())
            {
                if (!IsNumeric(@in.Peek))
                {
                    Pop();
                    int len = @in.Offset - start;
                    return(Emit(out @out, start, len, Token.Number));
                }
            }

            return(Underrun(out @out));
        }
示例#3
0
        void SkipWhitespace(ref Readable <char> @in)
        {
            int i    = 0;
            var data = @in.Data;

            for (; i < data.Length; i++)
            {
                if (!IsWhitespace(data[i]))
                {
                    break;
                }
            }

            @in.Move(i);
        }
示例#4
0
        public Signal Next(ref Readable <char> @in, out Tokenized @out)
        {
start:

            if (@in.IsEmpty)  //should just try reading, surely...
            {
                return(Underrun(out @out));
            }

            char current = @in.Peek;

            if (_mode != Mode.String && IsWhitespace(current))
            {
                SkipWhitespace(ref @in);
                goto start;
            }

            //stupid edge case
            //of line feed without the carriage return
            //requires look-ahead

            switch (_mode)
            {
            case Mode.Line:
                if (current == 0)          //shouldn't we just, you know, return the signal here...
                {
                    @in.Move();
                    return(End(out @out));
                }
                else
                {
                    Push(Mode.LineEnd);
                    Switch(Mode.Value);
                    goto start;
                }

            case Mode.LineEnd:
                if (current == 0)
                {
                    @in.Move();
                    return(End(out @out));
                }

                throw new NotImplementedException("Handle line break?");

            case Mode.Value:
                switch (current)
                {
                case '"':
                    @in.Move();
                    Switch(Mode.String);
                    goto start;

                case '{':
                    @in.Move();
                    Switch(Mode.Object1);
                    return(Emit(out @out, 1, 0, Token.Object));

                case '[':
                    @in.Move();
                    Switch(Mode.Array1);
                    return(Emit(out @out, 1, 0, Token.Array));

                case char c when IsNumeric(c):
                    return(ReadNumber(ref @in, out @out));
                }
                break;

            case Mode.Object1:
                switch (current)
                {
                case '}':
                    @in.Move();
                    Pop();
                    return(Emit(out @out, 1, 0, Token.ObjectEnd));

                case '"':
                    @in.Move();
                    Push(Mode.Object2);
                    Switch(Mode.String);
                    goto start;
                }
                break;

            case Mode.Object2:
                switch (current)
                {
                case ':':
                    @in.Move();
                    Push(Mode.Object3);
                    Switch(Mode.Value);
                    goto start;
                }
                break;

            case Mode.Object3:
                switch (current)
                {
                case ',':
                    @in.Move();
                    Switch(Mode.Object1);
                    goto start;

                case '}':
                    @in.Move();
                    Pop();
                    return(Emit(out @out, 1, 0, Token.ObjectEnd));
                }
                break;

            case Mode.Array1:
                switch (current)
                {
                case ']':
                    @in.Move();
                    Pop();
                    return(Emit(out @out, 1, 0, Token.ArrayEnd));

                default:
                    Push(Mode.Array2);
                    Switch(Mode.Value);
                    goto start;
                }

            case Mode.Array2:
                switch (current)
                {
                case ']':
                    @in.Move();
                    Pop();
                    return(Emit(out @out, 1, 0, Token.ArrayEnd));

                case ',':
                    @in.Move();
                    Switch(Mode.Array1);
                    goto start;
                }
                break;

            case Mode.String:
                return(ReadString(ref @in, out @out));
            }

            return(BadInput(out @out));
        }