OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
Johnni Winther
2015/12/11 11:27:29
Why make a parser in JS? Who will use this?
floitsch
2015/12/14 18:56:40
See https://github.com/floitschG/messages and http
Siggi Cherem (dart-lang)
2015/12/14 22:12:07
I wonder whether people will forget that they are
| |
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 file. | |
4 | |
5 function parseMessages(str) { | |
6 var result = {}; | |
7 var i; | |
8 | |
9 function cc() { return str.charCodeAt(i); } | |
10 | |
11 var SPACE = 32; | |
12 var NL = 10; | |
13 var SLASH = 47; | |
14 var SQUOTE = 39; | |
15 var DQUOTE = 34; | |
16 var LBRACE = 123; // { | |
17 var RBRACE = 125; // } | |
18 var SEMICOLON = 59; | |
19 var COMMA = 44; | |
20 var LBRACKET = 91; | |
21 var RBRACKET = 93; | |
22 var BACK_SLASH = 92; | |
23 var $r = 114; | |
24 | |
25 // Avoid infinite loops with bad data. | |
26 var lastNonWhite = -1; | |
27 var encounteredSameNonWhite = 0; | |
28 | |
29 // Moves to the next non-white position (skipping over eol-comments). | |
30 function moveToNextNonWhite() { | |
31 for (; i < str.length; i++) { | |
32 var charCode = cc(); | |
33 if (charCode == NL || charCode == SPACE) { | |
34 // Do nothing. | |
35 } else if (charCode == SLASH && str.charCodeAt(i + 1) == SLASH) { | |
36 // Consume until eol. | |
37 while (cc() != NL) i++; | |
38 } else { | |
39 break; | |
40 } | |
41 } | |
42 if (lastNonWhite == i) { | |
43 if (encounteredSameNonWhite++ == 10) | |
44 throw "bad input " + i; | |
45 } else { | |
46 encounteredSameNonWhite = 0; | |
47 lastNonWhite = i; | |
48 } | |
49 } | |
50 | |
51 // Automatically concatenates adjacent string literals. | |
52 function parseString() { | |
53 var result; | |
54 // str[i] == '"', str[i] == "'", or str[i] == "r". | |
55 var allowEscapes = true; | |
56 var startChar = cc(); | |
57 if (startChar == $r) { | |
58 i++; | |
59 startChar = cc(); | |
60 allowEscapes = false; | |
61 } | |
62 i++; | |
63 if (cc() == startChar && str.charCodeAt(i + 1) != startChar) { | |
64 // Empty string. | |
65 result = ''; | |
66 i ++; | |
67 } else { | |
68 var isMultiline = false; | |
69 if (cc() == startChar) { | |
70 isMultiline = true; | |
71 i += 2; | |
72 // Multilines ignore the first new line. | |
Johnni Winther
2015/12/11 11:27:29
Shouldn't you ignore whitespaces until the first n
floitsch
2015/12/14 18:56:40
We don't need to follow the exact specification (i
| |
73 if (cc() == NL) i++; | |
Johnni Winther
2015/12/11 11:27:29
Remember our source files are converted to platfor
floitsch
2015/12/14 18:56:40
I'm now treating "CR" as whitespace. Should make i
| |
74 } | |
75 var startPos = i; | |
76 for (; i < str.length; i++) { | |
Johnni Winther
2015/12/11 11:27:29
A file ending with an unterminated string will jus
floitsch
2015/12/14 18:56:40
Done.
| |
77 var charCode = cc(); | |
78 if (allowEscapes && charCode == BACK_SLASH) { | |
79 // Ignore next character. | |
80 i++; | |
81 continue; | |
82 } | |
83 if (charCode == startChar && | |
84 (!isMultiline || | |
85 (str.charCodeAt(i + 1) == startChar && | |
86 str.charCodeAt(i + 2) == startChar))) { | |
87 result = str.substring(startPos, i); | |
88 i += isMultiline ? 3 : 1; | |
89 break; | |
90 } | |
91 } | |
92 } | |
93 moveToNextNonWhite(); | |
94 // Another string ?. | |
95 charCode = cc(); | |
96 if (charCode == SQUOTE || charCode == DQUOTE || charCode == $r) { | |
97 result += parseString(); | |
98 } | |
99 return result; | |
100 } | |
101 | |
102 | |
103 function parseValue() { | |
104 var charCode = cc(); | |
105 if (charCode == SQUOTE || charCode == DQUOTE || | |
106 (charCode == $r && | |
107 (str.charCodeAt(i + 1) == SQUOTE || | |
108 str.charCodeAt(i + 1) == DQUOTE))) { | |
109 return parseString(); | |
110 } else if (charCode == LBRACE) { | |
111 return parseMap(); | |
112 } else if (charCode == LBRACKET) { | |
113 return parseList(); | |
114 } else { | |
115 // Assume it's something we don't support (like DONT_KNOW_HOW_TO_FIX). | |
116 // Ignore and move to the end of the map. | |
117 while (true) { | |
118 var charCode = cc(); | |
119 if (charCode == RBRACE) break; | |
120 if (charCode == RBRACKET) break; | |
121 if (charCode == COMMA) break; | |
122 i++ | |
123 } | |
124 return null; | |
125 } | |
126 } | |
127 | |
128 function parseList() { | |
129 var result = []; | |
130 // str[i] == '['. | |
131 i++; | |
132 moveToNextNonWhite(); | |
133 while (cc() != RBRACKET) { | |
134 result.push(parseValue()); | |
135 moveToNextNonWhite(); | |
136 if (cc() == COMMA) { | |
137 i++; | |
138 moveToNextNonWhite(); | |
139 } | |
140 } | |
141 i++; | |
142 return result; | |
143 } | |
144 | |
145 // Parse { 'id': ... } | |
146 function parseMap() { | |
147 var result = {}; | |
148 // str[i] == '{'. | |
149 i++; | |
150 moveToNextNonWhite(); | |
151 while (cc() != RBRACE) { // "}" | |
152 var key = parseString(); | |
153 moveToNextNonWhite(); | |
154 i++; // The ":". | |
Johnni Winther
2015/12/11 11:27:29
Assert this?
floitsch
2015/12/14 18:56:40
Done.
| |
155 moveToNextNonWhite(); | |
156 result[key] = parseValue(); | |
157 moveToNextNonWhite(); | |
158 if (cc() == COMMA) { | |
159 i++; | |
160 moveToNextNonWhite(); | |
161 } | |
162 } | |
163 i++; | |
164 return result; | |
165 } | |
166 | |
167 // Skip header. | |
168 var start = "\nfinal MESSAGES = {"; | |
169 var messagesPos = str.indexOf(start); | |
170 for (i = messagesPos + start.length; i < str.length; moveToNextNonWhite()) { | |
171 var charCode = cc(); | |
172 if (charCode == SQUOTE || charCode == DQUOTE) { // '"' or "'" | |
173 var name = parseString(); | |
174 moveToNextNonWhite(); | |
175 i++; // The ":". | |
176 moveToNextNonWhite(); | |
177 var data = parseMap(); | |
178 result[name] = data; | |
179 moveToNextNonWhite(); | |
180 i++; // The trailing "," or the trailing "}". | |
181 } else if (charCode == RBRACE || charCode == SEMICOLON) { // "}" or ";". | |
182 break; | |
183 } | |
184 } | |
185 return result; | |
186 } | |
187 | |
188 var messagesUri = | |
189 'https://raw.githubusercontent.com/dart-lang/sdk/' + | |
190 'master/pkg/dart_messages/lib/shared_messages.dart'; | |
191 | |
192 function loadMessages(callback, onError, uri) { | |
193 if (!onError) onError = function(e) { throw e; }; | |
194 if (!uri) uri = messagesUri; | |
195 | |
196 var request = new XMLHttpRequest(); | |
197 request.addEventListener("load", function() { | |
198 try { | |
199 callback(parseMessages(this.responseText)); | |
200 } catch (e) { | |
201 onError(e); | |
202 } | |
203 }); | |
204 request.open("GET", uri); | |
205 request.send(); | |
206 } | |
OLD | NEW |