File size: 4,041 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using System;

namespace UnityEngine.InputSystem.Utilities
{
    // this parser uses Span<T> so it's only available from later unity versions
#if UNITY_2021_2_OR_NEWER
    internal struct PredictiveParser
    {
        public void ExpectSingleChar(ReadOnlySpan<char> str, char c)
        {
            if (str[m_Position] != c)
                throw new InvalidOperationException($"Expected a '{c}' character at position {m_Position} in : {str.ToString()}");

            ++m_Position;
        }

        public int ExpectInt(ReadOnlySpan<char> str)
        {
            int pos = m_Position;

            int sign = 1;
            if (str[pos] == '-')
            {
                sign = -1;
                ++pos;
            }

            int value = 0;
            for (;;)
            {
                var n = str[pos];
                if (n >= '0' && n <= '9')
                {
                    value *= 10;
                    value += n - '0';
                    ++pos;
                }
                else
                    break;
            }

            if (m_Position == pos)
                throw new InvalidOperationException($"Expected an int at position {m_Position} in {str.ToString()}");

            m_Position = pos;
            return value * sign;
        }

        public ReadOnlySpan<char> ExpectString(ReadOnlySpan<char> str)
        {
            var startPos = m_Position;
            if (str[startPos] != '\"')
                throw new InvalidOperationException($"Expected a '\"' character at position {m_Position} in {str.ToString()}");

            ++m_Position;

            for (;;)
            {
                var c = str[m_Position];
                c |= ' ';
                if (c >= 'a' && c <= 'z')
                {
                    ++m_Position;
                    continue;
                }

                break;
            }

            // if the first non-alpha character is not a quote, throw
            if (str[m_Position] != '\"')
                throw new InvalidOperationException($"Expected a closing '\"' character at position {m_Position} in string: {str.ToString()}");

            if (m_Position - startPos == 1)
                return ReadOnlySpan<char>.Empty;

            var output = str.Slice(startPos + 1, m_Position - startPos - 1);

            ++m_Position;
            return output;
        }

        public bool AcceptSingleChar(ReadOnlySpan<char> str, char c)
        {
            if (str[m_Position] != c)
                return false;

            m_Position++;
            return true;
        }

        public bool AcceptString(ReadOnlySpan<char> input, out ReadOnlySpan<char> output)
        {
            output = default;
            var startPos = m_Position;
            var endPos = startPos;
            if (input[endPos] != '\"')
                return false;

            ++endPos;

            for (;;)
            {
                var c = input[endPos];
                c |= ' ';
                if (c >= 'a' && c <= 'z')
                {
                    ++endPos;
                    continue;
                }

                break;
            }

            // if the first non-alpha character is not a quote, throw
            if (input[endPos] != '\"')
                return false;

            // empty string?
            if (m_Position - startPos == 1)
                output = ReadOnlySpan<char>.Empty;
            else
                output = input.Slice(startPos + 1, endPos - startPos - 1);

            m_Position = endPos + 1;
            return true;
        }

        public void AcceptInt(ReadOnlySpan<char> str)
        {
            // skip negative sign
            if (str[m_Position] == '-')
                ++m_Position;

            for (;;)
            {
                var n = str[m_Position];
                if (n >= '0' && n <= '9')
                    ++m_Position;
                else
                    break;
            }
        }

        private int m_Position;
    }
#endif
}