Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(431)

Side by Side Diff: samples/buildbot/json.dart

Issue 967883004: Replace string uses with code units in Json parser. (Closed) Base URL: git@github.com:dart-lang/fletch.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | samples/buildbot/model.dart » ('j') | samples/buildbot/tests/json_test.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE.md file. 3 // BSD-style license that can be found in the LICENSE.md file.
4 4
5 import 'dart:io'; 5 import 'dart:io';
6 import 'dart:typed_data'; 6 import 'dart:typed_data';
7 7
8 import 'package:http/http.dart'; 8 import 'package:http/http.dart';
9 9
10 int _min(int m, int n) => (m < n) ? m : n; 10 int _min(int m, int n) => (m < n) ? m : n;
11 11
12 dynamic getJson(String host, String resource) { 12 dynamic getJson(String host, String resource) {
13 var socket = new Socket.connect(host, 80); 13 var socket = new Socket.connect(host, 80);
14 HttpConnection connection = new HttpConnection(socket); 14 HttpConnection connection = new HttpConnection(socket);
15 HttpRequest request = new HttpRequest(resource); 15 HttpRequest request = new HttpRequest(resource);
16 request.headers["Host"] = host; 16 request.headers["Host"] = host;
17 HttpResponse response = connection.send(request); 17 HttpResponse response = connection.send(request);
18 return new JsonParser(new String.fromCharCodes(response.body)).parse(); 18 return new JsonParser(new String.fromCharCodes(response.body)).parse();
19 } 19 }
20 20
21 class JsonParser { 21 class JsonParser {
22 int _index = 0; 22 int _offset = 0;
23 String _json; 23 String _json;
24 String _whitespaceUnits = ' \t\n';
25 String _delimiterUnits = ' \t\n,[]{}';
26 24
27 JsonParser(this._json); 25 JsonParser(this._json);
28 26
29 dynamic parse() { 27 dynamic parse() {
30 _whitespace(); 28 _whitespace();
31 var result = _parseValue(); 29 var result = _parseValue();
32 _whitespace(); 30 _whitespace();
33 if (_hasCurrent) { 31 if (_hasCurrent) {
34 throw "Parse failed to consume: ${_json.substring(_index)}"; 32 throw "Parse failed to consume: ${_json.substring(_offset)}";
35 } 33 }
36 return result; 34 return result;
37 } 35 }
38 36
39 int get _currentUnit => _json.codeUnitAt(_index); 37 bool get _hasCurrent => _offset < _json.length;
40 String get _current => _json[_index]; 38 int get _current => _json.codeUnitAt(_offset);
41 bool get _hasCurrent => _index < _json.length; 39 String get _currentChar => _json[_offset];
40 void _consume() { ++_offset; }
42 41
43 bool _containsCurrent(String units) { 42 void _whitespace() {
44 int length = units.length; 43 while (_hasCurrent && _isWhitespace(_current)) _consume();
45 int unit = _currentUnit; 44 }
46 for (int i = 0; i < length; ++i) { 45
47 if (unit == units.codeUnitAt(i)) return true; 46 bool _optional(int char) {
47 if (_current == char) {
48 _consume();
49 return true;
48 } 50 }
49 return false; 51 return false;
50 } 52 }
51 53
52 void _whitespace() { 54 void _expect(int char) {
53 while (_hasCurrent && _containsCurrent(_whitespaceUnits)) ++_index; 55 if (!_optional(char)) {
54 } 56 String string = new String.fromCharCodes([char]);
55 57 throw "Expected $string at index $_offset, found $_currentChar";
56 void _parseToken(String token) {
57 if (!_tryParseToken(token)) {
58 throw "Expected $token at index $_index, found $_current";
59 } 58 }
60 } 59 }
61 60
62 bool _tryParseToken(String token) { 61 bool _tryParseToken(String token) {
63 int length = token.length; 62 int length = token.length;
64 int start = _index; 63 int start = _offset;
65 int end = start + length; 64 int end = start + length;
66 if (end > _json.length) return false; 65 if (end > _json.length) return false;
67 for (int i = 0; i < length; ++i) { 66 for (int i = 0; i < length; ++i) {
68 if (token.codeUnitAt(i) != _json.codeUnitAt(start + i)) { 67 if (token.codeUnitAt(i) != _json.codeUnitAt(start + i)) {
69 return false; 68 return false;
70 } 69 }
71 } 70 }
72 _index += length; 71 _offset += length;
73 return true; 72 return true;
74 } 73 }
75 74
76 bool get _isDelimiter => _containsCurrent(_delimiterUnits);
77
78 String _readToken() { 75 String _readToken() {
79 int start = _index; 76 int start = _offset;
80 while (_hasCurrent && !_isDelimiter) ++_index; 77 while (_hasCurrent && !_isSeparator(_current)) _consume();
81 return _json.substring(start, _index); 78 return _json.substring(start, _offset);
82 } 79 }
83 80
84 dynamic _parseValue() { 81 dynamic _parseValue() {
85 _whitespace(); 82 _whitespace();
86 if (_tryParseToken('{')) return _parseMap(); 83 if (_optional(_CHAR_BRACE_OPEN)) return _parseMap();
87 if (_tryParseToken('[')) return _parseList(); 84 if (_optional(_CHAR_SQUARE_OPEN)) return _parseList();
88 if (_tryParseToken('"')) return _parseString(); 85 if (_optional(_CHAR_DOUBLE_QUOTE)) return _parseString();
89 if (_tryParseToken('true')) return true; 86 if (_tryParseToken(_TOKEN_TRUE)) return true;
90 if (_tryParseToken('false')) return false; 87 if (_tryParseToken(_TOKEN_FALSE)) return false;
91 if (_tryParseToken('null')) return null; 88 if (_tryParseToken(_TOKEN_NULL)) return null;
92 89
93 int tryIndex = _index; 90 int start = _offset;
94 String token = _readToken(); 91 String token = _readToken();
95 bool error = false; 92 bool error = false;
96 // TODO(zerny) floating point numbers. 93 // TODO(zerny) floating point numbers.
97 int tryInt = int.parse(token, onError: (_) { error = true; return 0; }); 94 int tryInt = int.parse(token, onError: (_) { error = true; return 0; });
98 if (!error) return tryInt; 95 if (!error) return tryInt;
99 96
100 String context = _json.substring(tryIndex, _min(tryIndex + 10, _json.length) ); 97 String context = _json.substring(start, _min(start + 10, _json.length));
101 throw "Parse failed at index: $_index (context: '$context...')"; 98 throw "Parse failed at index: $_offset (context: '$context...')";
102 } 99 }
103 100
104 Map _parseMap() { 101 Map _parseMap() {
105 Map map = new Map(); 102 Map map = new Map();
106 _whitespace(); 103 _whitespace();
107 while (!_tryParseToken('}')) { 104 while (!_optional(_CHAR_BRACE_CLOSE)) {
108 var key = _parseValue(); 105 var key = _parseValue();
109 _whitespace(); 106 _whitespace();
110 _parseToken(':'); 107 _expect(_CHAR_COLON);
111 var value = _parseValue(); 108 var value = _parseValue();
112 map[key] = value; 109 map[key] = value;
113 _whitespace(); 110 _whitespace();
114 _tryParseToken(','); 111 _optional(_CHAR_COMMA);
115 _whitespace(); 112 _whitespace();
116 } 113 }
117 return map; 114 return map;
118 } 115 }
119 116
120 List _parseList() { 117 List _parseList() {
121 List list = new List(); 118 List list = new List();
122 _whitespace(); 119 _whitespace();
123 while (!_tryParseToken(']')) { 120 while (!_optional(_CHAR_SQUARE_CLOSE)) {
124 list.add(_parseValue()); 121 list.add(_parseValue());
125 _whitespace(); 122 _whitespace();
126 _tryParseToken(','); 123 _optional(_CHAR_COMMA);
Anders Johnsen 2015/03/05 07:35:31 Would this allow [1 2 3 4] ? (ditto above)
zerny-google 2015/03/05 08:12:31 Yes. Fortunately it does parse well-formed json :-
127 _whitespace(); 124 _whitespace();
128 } 125 }
129 return list; 126 return list;
130 } 127 }
131 128
132 String _parseString() { 129 String _parseString() {
133 int start = _index; 130 int start = _offset;
134 while (_hasCurrent && _current != '"') ++_index; 131 while (_hasCurrent && _current != _CHAR_DOUBLE_QUOTE) {
135 return _json.substring(start, _index++); 132 if (_current == _CHAR_BACKSLASH) _consume();
133 _consume();
134 }
135 _expect(_CHAR_DOUBLE_QUOTE);
136 return _json.substring(start, _offset - 1);
136 } 137 }
138
139 static bool _isWhitespace(int char) =>
140 char == _CHAR_TAB ||
141 char == _CHAR_LINE_FEED ||
142 char == _CHAR_SPACE;
143
144 static bool _isSeparator(int char) =>
145 _isWhitespace(char) ||
146 char == _CHAR_PAREN_OPEN ||
147 char == _CHAR_PAREN_CLOSE ||
148 char == _CHAR_COMMA ||
149 char == _CHAR_COLON ||
150 char == _CHAR_SQUARE_OPEN ||
151 char == _CHAR_SQUARE_CLOSE ||
152 char == _CHAR_BRACE_OPEN ||
153 char == _CHAR_BRACE_CLOSE;
154
155 static const String _TOKEN_TRUE = 'true';
156 static const String _TOKEN_FALSE = 'false';
157 static const String _TOKEN_NULL = 'null';
158
159 static const int _CHAR_TAB = 9;
160 static const int _CHAR_LINE_FEED = 10;
161 static const int _CHAR_SPACE = 32;
162 static const int _CHAR_DOUBLE_QUOTE = 34;
163 static const int _CHAR_PAREN_OPEN = 40;
164 static const int _CHAR_PAREN_CLOSE = 41;
165 static const int _CHAR_COMMA = 44;
166 static const int _CHAR_COLON = 58;
167 static const int _CHAR_SQUARE_OPEN = 91;
168 static const int _CHAR_BACKSLASH = 92;
169 static const int _CHAR_SQUARE_CLOSE = 93;
170 static const int _CHAR_BRACE_OPEN = 123;
171 static const int _CHAR_BRACE_CLOSE = 125;
137 } 172 }
OLDNEW
« no previous file with comments | « no previous file | samples/buildbot/model.dart » ('j') | samples/buildbot/tests/json_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698