csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 1 | using System;
|
| 2 | using System.Collections.Generic;
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 3 | using System.Diagnostics;
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 4 | using System.Globalization;
|
| 5 | using System.IO;
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 6 |
|
| 7 | namespace Google.ProtocolBuffers.Serialization
|
| 8 | {
|
| 9 | /// <summary>
|
| 10 | /// JSon Tokenizer used by JsonFormatReader
|
| 11 | /// </summary>
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 12 | internal abstract class JsonCursor
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 13 | {
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 14 | public enum JsType
|
| 15 | {
|
| 16 | String,
|
| 17 | Number,
|
| 18 | Object,
|
| 19 | Array,
|
| 20 | True,
|
| 21 | False,
|
| 22 | Null
|
| 23 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 24 |
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 25 | #region Buffering implementations
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 26 |
|
| 27 | private class JsonStreamCursor : JsonCursor
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 28 | {
|
| 29 | private readonly byte[] _buffer;
|
| 30 | private int _bufferPos;
|
| 31 | private readonly Stream _input;
|
| 32 |
|
| 33 | public JsonStreamCursor(Stream input)
|
| 34 | {
|
| 35 | _input = input;
|
| 36 | _next = _input.ReadByte();
|
| 37 | }
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 38 |
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 39 | public JsonStreamCursor(byte[] input)
|
| 40 | {
|
| 41 | _input = null;
|
| 42 | _buffer = input;
|
| 43 | _next = _buffer[_bufferPos];
|
| 44 | }
|
| 45 |
|
| 46 | protected override int Peek()
|
| 47 | {
|
| 48 | if (_input != null)
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 49 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 50 | return _next;
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 51 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 52 | else if (_bufferPos < _buffer.Length)
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 53 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 54 | return _buffer[_bufferPos];
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 55 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 56 | else
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 57 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 58 | return -1;
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 59 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 60 | }
|
| 61 |
|
| 62 | protected override int Read()
|
| 63 | {
|
| 64 | if (_input != null)
|
| 65 | {
|
| 66 | int result = _next;
|
| 67 | _next = _input.ReadByte();
|
| 68 | return result;
|
| 69 | }
|
| 70 | else if (_bufferPos < _buffer.Length)
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 71 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 72 | return _buffer[_bufferPos++];
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 73 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 74 | else
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 75 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 76 | return -1;
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 77 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 78 | }
|
| 79 | }
|
| 80 |
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 81 | private class JsonTextCursor : JsonCursor
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 82 | {
|
| 83 | private readonly char[] _buffer;
|
| 84 | private int _bufferPos;
|
| 85 | private readonly TextReader _input;
|
| 86 |
|
| 87 | public JsonTextCursor(char[] input)
|
| 88 | {
|
| 89 | _input = null;
|
| 90 | _buffer = input;
|
| 91 | _bufferPos = 0;
|
| 92 | _next = Peek();
|
| 93 | }
|
| 94 |
|
| 95 | public JsonTextCursor(TextReader input)
|
| 96 | {
|
| 97 | _input = input;
|
| 98 | _next = Peek();
|
| 99 | }
|
| 100 |
|
| 101 | protected override int Peek()
|
| 102 | {
|
| 103 | if (_input != null)
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 104 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 105 | return _input.Peek();
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 106 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 107 | else if (_bufferPos < _buffer.Length)
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 108 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 109 | return _buffer[_bufferPos];
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 110 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 111 | else
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 112 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 113 | return -1;
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 114 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 115 | }
|
| 116 |
|
| 117 | protected override int Read()
|
| 118 | {
|
| 119 | if (_input != null)
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 120 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 121 | return _input.Read();
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 122 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 123 | else if (_bufferPos < _buffer.Length)
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 124 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 125 | return _buffer[_bufferPos++];
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 126 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 127 | else
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 128 | {
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 129 | return -1;
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 130 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 131 | }
|
| 132 | }
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 133 |
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 134 | #endregion
|
| 135 |
|
| 136 | protected int _next;
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 137 | private int _lineNo, _linePos;
|
| 138 |
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 139 | public static JsonCursor CreateInstance(byte[] input)
|
| 140 | {
|
| 141 | return new JsonStreamCursor(input);
|
| 142 | }
|
| 143 |
|
| 144 | public static JsonCursor CreateInstance(Stream input)
|
| 145 | {
|
| 146 | return new JsonStreamCursor(input);
|
| 147 | }
|
| 148 |
|
| 149 | public static JsonCursor CreateInstance(string input)
|
| 150 | {
|
| 151 | return new JsonTextCursor(input.ToCharArray());
|
| 152 | }
|
| 153 |
|
| 154 | public static JsonCursor CreateInstance(TextReader input)
|
| 155 | {
|
| 156 | return new JsonTextCursor(input);
|
| 157 | }
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 158 |
|
| 159 | protected JsonCursor()
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 160 | {
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 161 | _lineNo = 1;
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 162 | _linePos = 0;
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 163 | }
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 164 |
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 165 | /// <summary>Returns the next character without actually 'reading' it</summary>
|
| 166 | protected abstract int Peek();
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 167 |
|
csharptest | 7fc785c | 2011-06-10 23:54:53 -0500 | [diff] [blame] | 168 | /// <summary>Reads the next character in the input</summary>
|
| 169 | protected abstract int Read();
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 170 |
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 171 | public Char NextChar
|
| 172 | {
|
| 173 | get
|
| 174 | {
|
| 175 | SkipWhitespace();
|
| 176 | return (char) _next;
|
| 177 | }
|
| 178 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 179 |
|
| 180 | #region Assert(...)
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 181 |
|
| 182 | [DebuggerNonUserCode]
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 183 | private string CharDisplay(int ch)
|
| 184 | {
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 185 | return ch == -1
|
| 186 | ? "EOF"
|
| 187 | : (ch > 32 && ch < 127)
|
| 188 | ? String.Format("'{0}'", (char) ch)
|
| 189 | : String.Format("'\\u{0:x4}'", ch);
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 190 | }
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 191 |
|
| 192 | [DebuggerNonUserCode]
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 193 | private void Assert(bool cond, char expected)
|
| 194 | {
|
| 195 | if (!cond)
|
| 196 | {
|
| 197 | throw new FormatException(
|
| 198 | String.Format(CultureInfo.InvariantCulture,
|
| 199 | "({0}:{1}) error: Unexpected token {2}, expected: {3}.",
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 200 | _lineNo, _linePos,
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 201 | CharDisplay(_next),
|
| 202 | CharDisplay(expected)
|
| 203 | ));
|
| 204 | }
|
| 205 | }
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 206 |
|
| 207 | [DebuggerNonUserCode]
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 208 | public void Assert(bool cond, string message)
|
| 209 | {
|
| 210 | if (!cond)
|
| 211 | {
|
| 212 | throw new FormatException(
|
| 213 | String.Format(CultureInfo.InvariantCulture,
|
| 214 | "({0},{1}) error: {2}", _lineNo, _linePos, message));
|
| 215 | }
|
| 216 | }
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 217 |
|
| 218 | [DebuggerNonUserCode]
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 219 | public void Assert(bool cond, string format, params object[] args)
|
| 220 | {
|
| 221 | if (!cond)
|
| 222 | {
|
| 223 | if (args != null && args.Length > 0)
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 224 | {
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 225 | format = String.Format(format, args);
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 226 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 227 | throw new FormatException(
|
| 228 | String.Format(CultureInfo.InvariantCulture,
|
| 229 | "({0},{1}) error: {2}", _lineNo, _linePos, format));
|
| 230 | }
|
| 231 | }
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 232 |
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 233 | #endregion
|
| 234 |
|
| 235 | private char ReadChar()
|
| 236 | {
|
| 237 | int ch = Read();
|
| 238 | Assert(ch != -1, "Unexpected end of file.");
|
| 239 | if (ch == '\n')
|
| 240 | {
|
| 241 | _lineNo++;
|
| 242 | _linePos = 0;
|
| 243 | }
|
| 244 | else if (ch != '\r')
|
| 245 | {
|
| 246 | _linePos++;
|
| 247 | }
|
| 248 | _next = Peek();
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 249 | return (char) ch;
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 250 | }
|
| 251 |
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 252 | public void Consume(char ch)
|
| 253 | {
|
| 254 | Assert(TryConsume(ch), ch);
|
| 255 | }
|
| 256 |
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 257 | public bool TryConsume(char ch)
|
| 258 | {
|
| 259 | SkipWhitespace();
|
| 260 | if (_next == ch)
|
| 261 | {
|
| 262 | ReadChar();
|
| 263 | return true;
|
| 264 | }
|
| 265 | return false;
|
| 266 | }
|
| 267 |
|
| 268 | public void Consume(string sequence)
|
| 269 | {
|
| 270 | SkipWhitespace();
|
| 271 |
|
| 272 | foreach (char ch in sequence)
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 273 | {
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 274 | Assert(ch == ReadChar(), "Expected token '{0}'.", sequence);
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 275 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 276 | }
|
| 277 |
|
| 278 | public void SkipWhitespace()
|
| 279 | {
|
| 280 | int chnext = _next;
|
| 281 | while (chnext != -1)
|
| 282 | {
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 283 | if (!Char.IsWhiteSpace((char) chnext))
|
| 284 | {
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 285 | break;
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 286 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 287 | ReadChar();
|
| 288 | chnext = _next;
|
| 289 | }
|
| 290 | }
|
| 291 |
|
| 292 | public string ReadString()
|
| 293 | {
|
| 294 | SkipWhitespace();
|
| 295 | Consume('"');
|
csharptest | ddb74eb | 2011-06-10 16:14:51 -0500 | [diff] [blame] | 296 | List<Char> sb = new List<char>(100);
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 297 | while (_next != '"')
|
| 298 | {
|
| 299 | if (_next == '\\')
|
| 300 | {
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 301 | Consume('\\'); //skip the escape
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 302 | char ch = ReadChar();
|
| 303 | switch (ch)
|
| 304 | {
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 305 | case 'b':
|
| 306 | sb.Add('\b');
|
| 307 | break;
|
| 308 | case 'f':
|
| 309 | sb.Add('\f');
|
| 310 | break;
|
| 311 | case 'n':
|
| 312 | sb.Add('\n');
|
| 313 | break;
|
| 314 | case 'r':
|
| 315 | sb.Add('\r');
|
| 316 | break;
|
| 317 | case 't':
|
| 318 | sb.Add('\t');
|
| 319 | break;
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 320 | case 'u':
|
| 321 | {
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 322 | string hex = new string(new char[] {ReadChar(), ReadChar(), ReadChar(), ReadChar()});
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 323 | int result;
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 324 | Assert(
|
| 325 | int.TryParse(hex, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture,
|
| 326 | out result),
|
| 327 | "Expected a 4-character hex specifier.");
|
| 328 | sb.Add((char) result);
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 329 | break;
|
| 330 | }
|
| 331 | default:
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 332 | sb.Add(ch);
|
| 333 | break;
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 334 | }
|
| 335 | }
|
| 336 | else
|
| 337 | {
|
| 338 | Assert(_next != '\n' && _next != '\r' && _next != '\f' && _next != -1, '"');
|
csharptest | ddb74eb | 2011-06-10 16:14:51 -0500 | [diff] [blame] | 339 | sb.Add(ReadChar());
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 340 | }
|
| 341 | }
|
| 342 | Consume('"');
|
csharptest | ddb74eb | 2011-06-10 16:14:51 -0500 | [diff] [blame] | 343 | return new String(sb.ToArray());
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 344 | }
|
| 345 |
|
| 346 | public string ReadNumber()
|
| 347 | {
|
| 348 | SkipWhitespace();
|
csharptest | ddb74eb | 2011-06-10 16:14:51 -0500 | [diff] [blame] | 349 | List<Char> sb = new List<char>(24);
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 350 | if (_next == '-')
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 351 | {
|
csharptest | ddb74eb | 2011-06-10 16:14:51 -0500 | [diff] [blame] | 352 | sb.Add(ReadChar());
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 353 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 354 | Assert(_next >= '0' && _next <= '9', "Expected a numeric type.");
|
| 355 | while ((_next >= '0' && _next <= '9') || _next == '.')
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 356 | {
|
csharptest | ddb74eb | 2011-06-10 16:14:51 -0500 | [diff] [blame] | 357 | sb.Add(ReadChar());
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 358 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 359 | if (_next == 'e' || _next == 'E')
|
| 360 | {
|
csharptest | ddb74eb | 2011-06-10 16:14:51 -0500 | [diff] [blame] | 361 | sb.Add(ReadChar());
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 362 | if (_next == '-' || _next == '+')
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 363 | {
|
csharptest | ddb74eb | 2011-06-10 16:14:51 -0500 | [diff] [blame] | 364 | sb.Add(ReadChar());
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 365 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 366 | Assert(_next >= '0' && _next <= '9', "Expected a numeric type.");
|
| 367 | while (_next >= '0' && _next <= '9')
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 368 | {
|
csharptest | ddb74eb | 2011-06-10 16:14:51 -0500 | [diff] [blame] | 369 | sb.Add(ReadChar());
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 370 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 371 | }
|
csharptest | ddb74eb | 2011-06-10 16:14:51 -0500 | [diff] [blame] | 372 | return new String(sb.ToArray());
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 373 | }
|
| 374 |
|
| 375 | public JsType ReadVariant(out object value)
|
| 376 | {
|
| 377 | SkipWhitespace();
|
| 378 | switch (_next)
|
| 379 | {
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 380 | case 'n':
|
| 381 | Consume("null");
|
| 382 | value = null;
|
| 383 | return JsType.Null;
|
| 384 | case 't':
|
| 385 | Consume("true");
|
| 386 | value = true;
|
| 387 | return JsType.True;
|
| 388 | case 'f':
|
| 389 | Consume("false");
|
| 390 | value = false;
|
| 391 | return JsType.False;
|
| 392 | case '"':
|
| 393 | value = ReadString();
|
| 394 | return JsType.String;
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 395 | case '{':
|
| 396 | {
|
| 397 | Consume('{');
|
| 398 | while (NextChar != '}')
|
| 399 | {
|
| 400 | ReadString();
|
| 401 | Consume(':');
|
| 402 | object tmp;
|
| 403 | ReadVariant(out tmp);
|
| 404 | if (!TryConsume(','))
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 405 | {
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 406 | break;
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 407 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 408 | }
|
| 409 | Consume('}');
|
| 410 | value = null;
|
| 411 | return JsType.Object;
|
| 412 | }
|
| 413 | case '[':
|
| 414 | {
|
| 415 | Consume('[');
|
| 416 | List<object> values = new List<object>();
|
| 417 | while (NextChar != ']')
|
| 418 | {
|
| 419 | object tmp;
|
| 420 | ReadVariant(out tmp);
|
| 421 | values.Add(tmp);
|
| 422 | if (!TryConsume(','))
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 423 | {
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 424 | break;
|
csharptest | 74c5e0c | 2011-07-14 13:06:22 -0500 | [diff] [blame] | 425 | }
|
csharptest | afe844b | 2011-06-10 16:03:22 -0500 | [diff] [blame] | 426 | }
|
| 427 | Consume(']');
|
| 428 | value = values.ToArray();
|
| 429 | return JsType.Array;
|
| 430 | }
|
| 431 | default:
|
| 432 | if ((_next >= '0' && _next <= '9') || _next == '-')
|
| 433 | {
|
| 434 | value = ReadNumber();
|
| 435 | return JsType.Number;
|
| 436 | }
|
| 437 | Assert(false, "Expected a value.");
|
| 438 | throw new FormatException();
|
| 439 | }
|
| 440 | }
|
| 441 | }
|
| 442 | } |