pygments.rb 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +6 -1
- data/lexers +0 -0
- data/lib/pygments/version.rb +1 -1
- data/vendor/pygments-main/AUTHORS +15 -0
- data/vendor/pygments-main/CHANGES +28 -1
- data/vendor/pygments-main/LICENSE +1 -1
- data/vendor/pygments-main/external/lasso-builtins-generator-9.lasso +121 -0
- data/vendor/pygments-main/pygments/cmdline.py +1 -1
- data/vendor/pygments-main/pygments/filters/__init__.py +0 -1
- data/vendor/pygments-main/pygments/formatters/_mapping.py +2 -2
- data/vendor/pygments-main/pygments/formatters/img.py +1 -1
- data/vendor/pygments-main/pygments/formatters/latex.py +8 -8
- data/vendor/pygments-main/pygments/formatters/other.py +0 -2
- data/vendor/pygments-main/pygments/lexers/_lassobuiltins.py +5413 -0
- data/vendor/pygments-main/pygments/lexers/_mapping.py +36 -11
- data/vendor/pygments-main/pygments/lexers/_openedgebuiltins.py +551 -0
- data/vendor/pygments-main/pygments/lexers/_postgres_builtins.py +0 -1
- data/vendor/pygments-main/pygments/lexers/_robotframeworklexer.py +546 -0
- data/vendor/pygments-main/pygments/lexers/_sourcemodbuiltins.py +1072 -0
- data/vendor/pygments-main/pygments/lexers/_stan_builtins.py +174 -0
- data/vendor/pygments-main/pygments/lexers/_vimbuiltins.py +13 -3
- data/vendor/pygments-main/pygments/lexers/agile.py +145 -33
- data/vendor/pygments-main/pygments/lexers/asm.py +2 -2
- data/vendor/pygments-main/pygments/lexers/compiled.py +328 -36
- data/vendor/pygments-main/pygments/lexers/dalvik.py +104 -0
- data/vendor/pygments-main/pygments/lexers/dotnet.py +8 -14
- data/vendor/pygments-main/pygments/lexers/functional.py +773 -8
- data/vendor/pygments-main/pygments/lexers/jvm.py +184 -36
- data/vendor/pygments-main/pygments/lexers/math.py +349 -23
- data/vendor/pygments-main/pygments/lexers/other.py +315 -492
- data/vendor/pygments-main/pygments/lexers/parsers.py +83 -1
- data/vendor/pygments-main/pygments/lexers/shell.py +4 -1
- data/vendor/pygments-main/pygments/lexers/templates.py +112 -2
- data/vendor/pygments-main/pygments/lexers/text.py +52 -3
- data/vendor/pygments-main/pygments/lexers/web.py +382 -36
- data/vendor/pygments-main/pygments/unistring.py +35 -25
- data/vendor/pygments-main/pygments/util.py +45 -0
- data/vendor/pygments-main/tests/examplefiles/Config.in.cache +1973 -0
- data/vendor/pygments-main/tests/examplefiles/example.Rd +78 -0
- data/vendor/pygments-main/tests/examplefiles/example.bug +54 -0
- data/vendor/pygments-main/tests/examplefiles/example.ceylon +33 -0
- data/vendor/pygments-main/tests/examplefiles/example.jag +48 -0
- data/vendor/pygments-main/tests/examplefiles/example.monkey +152 -0
- data/vendor/pygments-main/tests/examplefiles/example.msc +43 -0
- data/vendor/pygments-main/tests/examplefiles/example.reg +19 -0
- data/vendor/pygments-main/tests/examplefiles/example.rkt +95 -0
- data/vendor/pygments-main/tests/examplefiles/example.rpf +4 -0
- data/vendor/pygments-main/tests/examplefiles/example.stan +97 -0
- data/vendor/pygments-main/tests/examplefiles/example.xtend +34 -0
- data/vendor/pygments-main/tests/examplefiles/example2.msc +79 -0
- data/vendor/pygments-main/tests/examplefiles/garcia-wachs.kk +123 -0
- data/vendor/pygments-main/tests/examplefiles/hello.smali +40 -0
- data/vendor/pygments-main/tests/examplefiles/hello.sp +9 -0
- data/vendor/pygments-main/tests/examplefiles/http_request_example +2 -1
- data/vendor/pygments-main/tests/examplefiles/http_response_example +4 -2
- data/vendor/pygments-main/tests/examplefiles/inet_pton6.dg +71 -0
- data/vendor/pygments-main/tests/examplefiles/json.lasso +301 -0
- data/vendor/pygments-main/tests/examplefiles/json.lasso9 +213 -0
- data/vendor/pygments-main/tests/examplefiles/livescript-demo.ls +41 -0
- data/vendor/pygments-main/tests/examplefiles/matlab_sample +5 -2
- data/vendor/pygments-main/tests/examplefiles/metagrammar.treetop +455 -0
- data/vendor/pygments-main/tests/examplefiles/pytb_test3.pytb +4 -0
- data/vendor/pygments-main/tests/examplefiles/robotframework.txt +39 -0
- data/vendor/pygments-main/tests/examplefiles/rust_example.rs +743 -0
- data/vendor/pygments-main/tests/examplefiles/test.R +149 -115
- data/vendor/pygments-main/tests/examplefiles/test.cu +36 -0
- data/vendor/pygments-main/tests/test_basic_api.py +1 -1
- data/vendor/pygments-main/tests/test_util.py +18 -0
- metadata +34 -3
- data/vendor/pygments-main/REVISION +0 -1
@@ -0,0 +1,39 @@
|
|
1
|
+
*** Settings ***
|
2
|
+
Documentation Simple example demonstrating syntax highlighting.
|
3
|
+
Library ExampleLibrary
|
4
|
+
Test Setup Keyword argument argument with ${VARIABLE}
|
5
|
+
|
6
|
+
*** Variables ***
|
7
|
+
${VARIABLE} Variable value
|
8
|
+
@{LIST} List variable here
|
9
|
+
|
10
|
+
*** Test Cases ***
|
11
|
+
Keyword-driven example
|
12
|
+
Initialize System
|
13
|
+
Do Something
|
14
|
+
Result Should Be 42
|
15
|
+
[Teardown] Cleanup System
|
16
|
+
|
17
|
+
Data-driven example
|
18
|
+
[Template] Keyword
|
19
|
+
argument1 argument2
|
20
|
+
argument ${VARIABLE}
|
21
|
+
@{LIST}
|
22
|
+
|
23
|
+
Gherkin
|
24
|
+
Given system is initialized
|
25
|
+
When something is done
|
26
|
+
Then result should be "42"
|
27
|
+
|
28
|
+
| Pipes |
|
29
|
+
| | [Documentation] | Also pipe separated format is supported. |
|
30
|
+
| | Log | As this example demonstrates. |
|
31
|
+
|
32
|
+
*** Keywords ***
|
33
|
+
Result Should Be
|
34
|
+
[Arguments] ${expected}
|
35
|
+
${actual} = Get Value
|
36
|
+
Should be Equal ${actual} ${expected}
|
37
|
+
|
38
|
+
Then result should be "${expected}"
|
39
|
+
Result Should Be ${expected}
|
@@ -0,0 +1,743 @@
|
|
1
|
+
|
2
|
+
#[doc = "json serialization"];
|
3
|
+
|
4
|
+
import result::{result, ok, err};
|
5
|
+
import io;
|
6
|
+
import io::{reader_util, writer_util};
|
7
|
+
import map;
|
8
|
+
import map::hashmap;
|
9
|
+
|
10
|
+
export json;
|
11
|
+
export error;
|
12
|
+
export to_writer;
|
13
|
+
export to_str;
|
14
|
+
export from_reader;
|
15
|
+
export from_str;
|
16
|
+
export eq;
|
17
|
+
|
18
|
+
export num;
|
19
|
+
export string;
|
20
|
+
export boolean;
|
21
|
+
export list;
|
22
|
+
export dict;
|
23
|
+
export null;
|
24
|
+
|
25
|
+
#[doc = "Represents a json value"]
|
26
|
+
enum json {
|
27
|
+
num(float),
|
28
|
+
string(str),
|
29
|
+
boolean(bool),
|
30
|
+
list([json]),
|
31
|
+
dict(map::hashmap<str,json>),
|
32
|
+
null,
|
33
|
+
}
|
34
|
+
|
35
|
+
type error = {
|
36
|
+
line: uint,
|
37
|
+
col: uint,
|
38
|
+
msg: str,
|
39
|
+
};
|
40
|
+
|
41
|
+
#[doc = "Serializes a json value into a io::writer"]
|
42
|
+
fn to_writer(wr: io::writer, j: json) {
|
43
|
+
alt j {
|
44
|
+
num(n) { wr.write_str(float::to_str(n, 6u)); }
|
45
|
+
string(s) {
|
46
|
+
wr.write_char('"');
|
47
|
+
let mut escaped = "";
|
48
|
+
str::chars_iter(s) { |c|
|
49
|
+
alt c {
|
50
|
+
'"' { escaped += "\\\""; }
|
51
|
+
'\\' { escaped += "\\\\"; }
|
52
|
+
'\x08' { escaped += "\\b"; }
|
53
|
+
'\x0c' { escaped += "\\f"; }
|
54
|
+
'\n' { escaped += "\\n"; }
|
55
|
+
'\r' { escaped += "\\r"; }
|
56
|
+
'\t' { escaped += "\\t"; }
|
57
|
+
_ { escaped += str::from_char(c); }
|
58
|
+
}
|
59
|
+
};
|
60
|
+
wr.write_str(escaped);
|
61
|
+
wr.write_char('"');
|
62
|
+
}
|
63
|
+
boolean(b) {
|
64
|
+
wr.write_str(if b { "true" } else { "false" });
|
65
|
+
}
|
66
|
+
list(v) {
|
67
|
+
wr.write_char('[');
|
68
|
+
let mut first = true;
|
69
|
+
vec::iter(v) { |item|
|
70
|
+
if !first {
|
71
|
+
wr.write_str(", ");
|
72
|
+
}
|
73
|
+
first = false;
|
74
|
+
to_writer(wr, item);
|
75
|
+
};
|
76
|
+
wr.write_char(']');
|
77
|
+
}
|
78
|
+
dict(d) {
|
79
|
+
if d.size() == 0u {
|
80
|
+
wr.write_str("{}");
|
81
|
+
ret;
|
82
|
+
}
|
83
|
+
|
84
|
+
wr.write_str("{ ");
|
85
|
+
let mut first = true;
|
86
|
+
d.items { |key, value|
|
87
|
+
if !first {
|
88
|
+
wr.write_str(", ");
|
89
|
+
}
|
90
|
+
first = false;
|
91
|
+
to_writer(wr, string(key));
|
92
|
+
wr.write_str(": ");
|
93
|
+
to_writer(wr, value);
|
94
|
+
};
|
95
|
+
wr.write_str(" }");
|
96
|
+
}
|
97
|
+
null {
|
98
|
+
wr.write_str("null");
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
#[doc = "Serializes a json value into a string"]
|
104
|
+
fn to_str(j: json) -> str {
|
105
|
+
io::with_str_writer { |wr| to_writer(wr, j) }
|
106
|
+
}
|
107
|
+
|
108
|
+
type parser = {
|
109
|
+
rdr: io::reader,
|
110
|
+
mut ch: char,
|
111
|
+
mut line: uint,
|
112
|
+
mut col: uint,
|
113
|
+
};
|
114
|
+
|
115
|
+
impl parser for parser {
|
116
|
+
fn eof() -> bool { self.ch == -1 as char }
|
117
|
+
|
118
|
+
fn bump() {
|
119
|
+
self.ch = self.rdr.read_char();
|
120
|
+
|
121
|
+
if self.ch == '\n' {
|
122
|
+
self.line += 1u;
|
123
|
+
self.col = 1u;
|
124
|
+
} else {
|
125
|
+
self.col += 1u;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
fn next_char() -> char {
|
130
|
+
self.bump();
|
131
|
+
self.ch
|
132
|
+
}
|
133
|
+
|
134
|
+
fn error<T>(msg: str) -> result<T, error> {
|
135
|
+
err({ line: self.line, col: self.col, msg: msg })
|
136
|
+
}
|
137
|
+
|
138
|
+
fn parse() -> result<json, error> {
|
139
|
+
alt self.parse_value() {
|
140
|
+
ok(value) {
|
141
|
+
// Skip trailing whitespaces.
|
142
|
+
self.parse_whitespace();
|
143
|
+
// Make sure there is no trailing characters.
|
144
|
+
if self.eof() {
|
145
|
+
ok(value)
|
146
|
+
} else {
|
147
|
+
self.error("trailing characters")
|
148
|
+
}
|
149
|
+
}
|
150
|
+
e { e }
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
fn parse_value() -> result<json, error> {
|
155
|
+
self.parse_whitespace();
|
156
|
+
|
157
|
+
if self.eof() { ret self.error("EOF while parsing value"); }
|
158
|
+
|
159
|
+
alt self.ch {
|
160
|
+
'n' { self.parse_ident("ull", null) }
|
161
|
+
't' { self.parse_ident("rue", boolean(true)) }
|
162
|
+
'f' { self.parse_ident("alse", boolean(false)) }
|
163
|
+
'0' to '9' | '-' { self.parse_number() }
|
164
|
+
'"' {
|
165
|
+
alt self.parse_str() {
|
166
|
+
ok(s) { ok(string(s)) }
|
167
|
+
err(e) { err(e) }
|
168
|
+
}
|
169
|
+
}
|
170
|
+
'[' { self.parse_list() }
|
171
|
+
'{' { self.parse_object() }
|
172
|
+
_ { self.error("invalid syntax") }
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
fn parse_whitespace() {
|
177
|
+
while char::is_whitespace(self.ch) { self.bump(); }
|
178
|
+
}
|
179
|
+
|
180
|
+
fn parse_ident(ident: str, value: json) -> result<json, error> {
|
181
|
+
if str::all(ident, { |c| c == self.next_char() }) {
|
182
|
+
self.bump();
|
183
|
+
ok(value)
|
184
|
+
} else {
|
185
|
+
self.error("invalid syntax")
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
fn parse_number() -> result<json, error> {
|
190
|
+
let mut neg = 1f;
|
191
|
+
|
192
|
+
if self.ch == '-' {
|
193
|
+
self.bump();
|
194
|
+
neg = -1f;
|
195
|
+
}
|
196
|
+
|
197
|
+
let mut res = alt self.parse_integer() {
|
198
|
+
ok(res) { res }
|
199
|
+
err(e) { ret err(e); }
|
200
|
+
};
|
201
|
+
|
202
|
+
if self.ch == '.' {
|
203
|
+
alt self.parse_decimal(res) {
|
204
|
+
ok(r) { res = r; }
|
205
|
+
err(e) { ret err(e); }
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
if self.ch == 'e' || self.ch == 'E' {
|
210
|
+
alt self.parse_exponent(res) {
|
211
|
+
ok(r) { res = r; }
|
212
|
+
err(e) { ret err(e); }
|
213
|
+
}
|
214
|
+
}
|
215
|
+
|
216
|
+
ok(num(neg * res))
|
217
|
+
}
|
218
|
+
|
219
|
+
fn parse_integer() -> result<float, error> {
|
220
|
+
let mut res = 0f;
|
221
|
+
|
222
|
+
alt self.ch {
|
223
|
+
'0' {
|
224
|
+
self.bump();
|
225
|
+
|
226
|
+
// There can be only one leading '0'.
|
227
|
+
alt self.ch {
|
228
|
+
'0' to '9' { ret self.error("invalid number"); }
|
229
|
+
_ {}
|
230
|
+
}
|
231
|
+
}
|
232
|
+
'1' to '9' {
|
233
|
+
while !self.eof() {
|
234
|
+
alt self.ch {
|
235
|
+
'0' to '9' {
|
236
|
+
res *= 10f;
|
237
|
+
res += ((self.ch as int) - ('0' as int)) as float;
|
238
|
+
|
239
|
+
self.bump();
|
240
|
+
}
|
241
|
+
_ { break; }
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
_ { ret self.error("invalid number"); }
|
246
|
+
}
|
247
|
+
|
248
|
+
ok(res)
|
249
|
+
}
|
250
|
+
|
251
|
+
fn parse_decimal(res: float) -> result<float, error> {
|
252
|
+
self.bump();
|
253
|
+
|
254
|
+
// Make sure a digit follows the decimal place.
|
255
|
+
alt self.ch {
|
256
|
+
'0' to '9' {}
|
257
|
+
_ { ret self.error("invalid number"); }
|
258
|
+
}
|
259
|
+
|
260
|
+
let mut res = res;
|
261
|
+
let mut dec = 1f;
|
262
|
+
while !self.eof() {
|
263
|
+
alt self.ch {
|
264
|
+
'0' to '9' {
|
265
|
+
dec /= 10f;
|
266
|
+
res += (((self.ch as int) - ('0' as int)) as float) * dec;
|
267
|
+
|
268
|
+
self.bump();
|
269
|
+
}
|
270
|
+
_ { break; }
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
ok(res)
|
275
|
+
}
|
276
|
+
|
277
|
+
fn parse_exponent(res: float) -> result<float, error> {
|
278
|
+
self.bump();
|
279
|
+
|
280
|
+
let mut res = res;
|
281
|
+
let mut exp = 0u;
|
282
|
+
let mut neg_exp = false;
|
283
|
+
|
284
|
+
alt self.ch {
|
285
|
+
'+' { self.bump(); }
|
286
|
+
'-' { self.bump(); neg_exp = true; }
|
287
|
+
_ {}
|
288
|
+
}
|
289
|
+
|
290
|
+
// Make sure a digit follows the exponent place.
|
291
|
+
alt self.ch {
|
292
|
+
'0' to '9' {}
|
293
|
+
_ { ret self.error("invalid number"); }
|
294
|
+
}
|
295
|
+
|
296
|
+
while !self.eof() {
|
297
|
+
alt self.ch {
|
298
|
+
'0' to '9' {
|
299
|
+
exp *= 10u;
|
300
|
+
exp += (self.ch as uint) - ('0' as uint);
|
301
|
+
|
302
|
+
self.bump();
|
303
|
+
}
|
304
|
+
_ { break; }
|
305
|
+
}
|
306
|
+
}
|
307
|
+
|
308
|
+
let exp = float::pow_with_uint(10u, exp);
|
309
|
+
if neg_exp {
|
310
|
+
res /= exp;
|
311
|
+
} else {
|
312
|
+
res *= exp;
|
313
|
+
}
|
314
|
+
|
315
|
+
ok(res)
|
316
|
+
}
|
317
|
+
|
318
|
+
fn parse_str() -> result<str, error> {
|
319
|
+
let mut escape = false;
|
320
|
+
let mut res = "";
|
321
|
+
|
322
|
+
while !self.eof() {
|
323
|
+
self.bump();
|
324
|
+
|
325
|
+
if (escape) {
|
326
|
+
alt self.ch {
|
327
|
+
'"' { str::push_char(res, '"'); }
|
328
|
+
'\\' { str::push_char(res, '\\'); }
|
329
|
+
'/' { str::push_char(res, '/'); }
|
330
|
+
'b' { str::push_char(res, '\x08'); }
|
331
|
+
'f' { str::push_char(res, '\x0c'); }
|
332
|
+
'n' { str::push_char(res, '\n'); }
|
333
|
+
'r' { str::push_char(res, '\r'); }
|
334
|
+
't' { str::push_char(res, '\t'); }
|
335
|
+
'u' {
|
336
|
+
// Parse \u1234.
|
337
|
+
let mut i = 0u;
|
338
|
+
let mut n = 0u;
|
339
|
+
while i < 4u {
|
340
|
+
alt self.next_char() {
|
341
|
+
'0' to '9' {
|
342
|
+
n = n * 10u +
|
343
|
+
(self.ch as uint) - ('0' as uint);
|
344
|
+
}
|
345
|
+
_ { ret self.error("invalid \\u escape"); }
|
346
|
+
}
|
347
|
+
i += 1u;
|
348
|
+
}
|
349
|
+
|
350
|
+
// Error out if we didn't parse 4 digits.
|
351
|
+
if i != 4u {
|
352
|
+
ret self.error("invalid \\u escape");
|
353
|
+
}
|
354
|
+
|
355
|
+
str::push_char(res, n as char);
|
356
|
+
}
|
357
|
+
_ { ret self.error("invalid escape"); }
|
358
|
+
}
|
359
|
+
escape = false;
|
360
|
+
} else if self.ch == '\\' {
|
361
|
+
escape = true;
|
362
|
+
} else {
|
363
|
+
if self.ch == '"' {
|
364
|
+
self.bump();
|
365
|
+
ret ok(res);
|
366
|
+
}
|
367
|
+
str::push_char(res, self.ch);
|
368
|
+
}
|
369
|
+
}
|
370
|
+
|
371
|
+
self.error("EOF while parsing string")
|
372
|
+
}
|
373
|
+
|
374
|
+
fn parse_list() -> result<json, error> {
|
375
|
+
self.bump();
|
376
|
+
self.parse_whitespace();
|
377
|
+
|
378
|
+
let mut values = [];
|
379
|
+
|
380
|
+
if self.ch == ']' {
|
381
|
+
self.bump();
|
382
|
+
ret ok(list(values));
|
383
|
+
}
|
384
|
+
|
385
|
+
loop {
|
386
|
+
alt self.parse_value() {
|
387
|
+
ok(v) { vec::push(values, v); }
|
388
|
+
e { ret e; }
|
389
|
+
}
|
390
|
+
|
391
|
+
self.parse_whitespace();
|
392
|
+
if self.eof() {
|
393
|
+
ret self.error("EOF while parsing list");
|
394
|
+
}
|
395
|
+
|
396
|
+
alt self.ch {
|
397
|
+
',' { self.bump(); }
|
398
|
+
']' { self.bump(); ret ok(list(values)); }
|
399
|
+
_ { ret self.error("expecting ',' or ']'"); }
|
400
|
+
}
|
401
|
+
};
|
402
|
+
}
|
403
|
+
|
404
|
+
fn parse_object() -> result<json, error> {
|
405
|
+
self.bump();
|
406
|
+
self.parse_whitespace();
|
407
|
+
|
408
|
+
let values = map::str_hash();
|
409
|
+
|
410
|
+
if self.ch == '}' {
|
411
|
+
self.bump();
|
412
|
+
ret ok(dict(values));
|
413
|
+
}
|
414
|
+
|
415
|
+
while !self.eof() {
|
416
|
+
self.parse_whitespace();
|
417
|
+
|
418
|
+
if self.ch != '"' {
|
419
|
+
ret self.error("key must be a string");
|
420
|
+
}
|
421
|
+
|
422
|
+
let key = alt self.parse_str() {
|
423
|
+
ok(key) { key }
|
424
|
+
err(e) { ret err(e); }
|
425
|
+
};
|
426
|
+
|
427
|
+
self.parse_whitespace();
|
428
|
+
|
429
|
+
if self.ch != ':' {
|
430
|
+
if self.eof() { break; }
|
431
|
+
ret self.error("expecting ':'");
|
432
|
+
}
|
433
|
+
self.bump();
|
434
|
+
|
435
|
+
alt self.parse_value() {
|
436
|
+
ok(value) { values.insert(key, value); }
|
437
|
+
e { ret e; }
|
438
|
+
}
|
439
|
+
self.parse_whitespace();
|
440
|
+
|
441
|
+
alt self.ch {
|
442
|
+
',' { self.bump(); }
|
443
|
+
'}' { self.bump(); ret ok(dict(values)); }
|
444
|
+
_ {
|
445
|
+
if self.eof() { break; }
|
446
|
+
ret self.error("expecting ',' or '}'");
|
447
|
+
}
|
448
|
+
}
|
449
|
+
}
|
450
|
+
|
451
|
+
ret self.error("EOF while parsing object");
|
452
|
+
}
|
453
|
+
}
|
454
|
+
|
455
|
+
#[doc = "Deserializes a json value from an io::reader"]
|
456
|
+
fn from_reader(rdr: io::reader) -> result<json, error> {
|
457
|
+
let parser = {
|
458
|
+
rdr: rdr,
|
459
|
+
mut ch: rdr.read_char(),
|
460
|
+
mut line: 1u,
|
461
|
+
mut col: 1u,
|
462
|
+
};
|
463
|
+
|
464
|
+
parser.parse()
|
465
|
+
}
|
466
|
+
|
467
|
+
#[doc = "Deserializes a json value from a string"]
|
468
|
+
fn from_str(s: str) -> result<json, error> {
|
469
|
+
io::with_str_reader(s, from_reader)
|
470
|
+
}
|
471
|
+
|
472
|
+
#[doc = "Test if two json values are equal"]
|
473
|
+
fn eq(value0: json, value1: json) -> bool {
|
474
|
+
alt (value0, value1) {
|
475
|
+
(num(f0), num(f1)) { f0 == f1 }
|
476
|
+
(string(s0), string(s1)) { s0 == s1 }
|
477
|
+
(boolean(b0), boolean(b1)) { b0 == b1 }
|
478
|
+
(list(l0), list(l1)) { vec::all2(l0, l1, eq) }
|
479
|
+
(dict(d0), dict(d1)) {
|
480
|
+
if d0.size() == d1.size() {
|
481
|
+
let mut equal = true;
|
482
|
+
d0.items { |k, v0|
|
483
|
+
alt d1.find(k) {
|
484
|
+
some(v1) {
|
485
|
+
if !eq(v0, v1) { equal = false; } }
|
486
|
+
none { equal = false; }
|
487
|
+
}
|
488
|
+
};
|
489
|
+
equal
|
490
|
+
} else {
|
491
|
+
false
|
492
|
+
}
|
493
|
+
}
|
494
|
+
(null, null) { true }
|
495
|
+
_ { false }
|
496
|
+
}
|
497
|
+
}
|
498
|
+
|
499
|
+
#[cfg(test)]
|
500
|
+
mod tests {
|
501
|
+
fn mk_dict(items: [(str, json)]) -> json {
|
502
|
+
let d = map::str_hash();
|
503
|
+
|
504
|
+
vec::iter(items) { |item|
|
505
|
+
let (key, value) = item;
|
506
|
+
d.insert(key, value);
|
507
|
+
};
|
508
|
+
|
509
|
+
dict(d)
|
510
|
+
}
|
511
|
+
|
512
|
+
#[test]
|
513
|
+
fn test_write_null() {
|
514
|
+
assert to_str(null) == "null";
|
515
|
+
}
|
516
|
+
|
517
|
+
#[test]
|
518
|
+
fn test_write_num() {
|
519
|
+
assert to_str(num(3f)) == "3";
|
520
|
+
assert to_str(num(3.1f)) == "3.1";
|
521
|
+
assert to_str(num(-1.5f)) == "-1.5";
|
522
|
+
assert to_str(num(0.5f)) == "0.5";
|
523
|
+
}
|
524
|
+
|
525
|
+
#[test]
|
526
|
+
fn test_write_str() {
|
527
|
+
assert to_str(string("")) == "\"\"";
|
528
|
+
assert to_str(string("foo")) == "\"foo\"";
|
529
|
+
}
|
530
|
+
|
531
|
+
#[test]
|
532
|
+
fn test_write_bool() {
|
533
|
+
assert to_str(boolean(true)) == "true";
|
534
|
+
assert to_str(boolean(false)) == "false";
|
535
|
+
}
|
536
|
+
|
537
|
+
#[test]
|
538
|
+
fn test_write_list() {
|
539
|
+
assert to_str(list([])) == "[]";
|
540
|
+
assert to_str(list([boolean(true)])) == "[true]";
|
541
|
+
assert to_str(list([
|
542
|
+
boolean(false),
|
543
|
+
null,
|
544
|
+
list([string("foo\nbar"), num(3.5f)])
|
545
|
+
])) == "[false, null, [\"foo\\nbar\", 3.5]]";
|
546
|
+
}
|
547
|
+
|
548
|
+
#[test]
|
549
|
+
fn test_write_dict() {
|
550
|
+
assert to_str(mk_dict([])) == "{}";
|
551
|
+
assert to_str(mk_dict([("a", boolean(true))])) == "{ \"a\": true }";
|
552
|
+
assert to_str(mk_dict([
|
553
|
+
("a", boolean(true)),
|
554
|
+
("b", list([
|
555
|
+
mk_dict([("c", string("\x0c\r"))]),
|
556
|
+
mk_dict([("d", string(""))])
|
557
|
+
]))
|
558
|
+
])) ==
|
559
|
+
"{ " +
|
560
|
+
"\"a\": true, " +
|
561
|
+
"\"b\": [" +
|
562
|
+
"{ \"c\": \"\\f\\r\" }, " +
|
563
|
+
"{ \"d\": \"\" }" +
|
564
|
+
"]" +
|
565
|
+
" }";
|
566
|
+
}
|
567
|
+
|
568
|
+
#[test]
|
569
|
+
fn test_trailing_characters() {
|
570
|
+
assert from_str("nulla") ==
|
571
|
+
err({line: 1u, col: 5u, msg: "trailing characters"});
|
572
|
+
assert from_str("truea") ==
|
573
|
+
err({line: 1u, col: 5u, msg: "trailing characters"});
|
574
|
+
assert from_str("falsea") ==
|
575
|
+
err({line: 1u, col: 6u, msg: "trailing characters"});
|
576
|
+
assert from_str("1a") ==
|
577
|
+
err({line: 1u, col: 2u, msg: "trailing characters"});
|
578
|
+
assert from_str("[]a") ==
|
579
|
+
err({line: 1u, col: 3u, msg: "trailing characters"});
|
580
|
+
assert from_str("{}a") ==
|
581
|
+
err({line: 1u, col: 3u, msg: "trailing characters"});
|
582
|
+
}
|
583
|
+
|
584
|
+
#[test]
|
585
|
+
fn test_read_identifiers() {
|
586
|
+
assert from_str("n") ==
|
587
|
+
err({line: 1u, col: 2u, msg: "invalid syntax"});
|
588
|
+
assert from_str("nul") ==
|
589
|
+
err({line: 1u, col: 4u, msg: "invalid syntax"});
|
590
|
+
|
591
|
+
assert from_str("t") ==
|
592
|
+
err({line: 1u, col: 2u, msg: "invalid syntax"});
|
593
|
+
assert from_str("truz") ==
|
594
|
+
err({line: 1u, col: 4u, msg: "invalid syntax"});
|
595
|
+
|
596
|
+
assert from_str("f") ==
|
597
|
+
err({line: 1u, col: 2u, msg: "invalid syntax"});
|
598
|
+
assert from_str("faz") ==
|
599
|
+
err({line: 1u, col: 3u, msg: "invalid syntax"});
|
600
|
+
|
601
|
+
assert from_str("null") == ok(null);
|
602
|
+
assert from_str("true") == ok(boolean(true));
|
603
|
+
assert from_str("false") == ok(boolean(false));
|
604
|
+
assert from_str(" null ") == ok(null);
|
605
|
+
assert from_str(" true ") == ok(boolean(true));
|
606
|
+
assert from_str(" false ") == ok(boolean(false));
|
607
|
+
}
|
608
|
+
|
609
|
+
#[test]
|
610
|
+
fn test_read_num() {
|
611
|
+
assert from_str("+") ==
|
612
|
+
err({line: 1u, col: 1u, msg: "invalid syntax"});
|
613
|
+
assert from_str(".") ==
|
614
|
+
err({line: 1u, col: 1u, msg: "invalid syntax"});
|
615
|
+
|
616
|
+
assert from_str("-") ==
|
617
|
+
err({line: 1u, col: 2u, msg: "invalid number"});
|
618
|
+
assert from_str("00") ==
|
619
|
+
err({line: 1u, col: 2u, msg: "invalid number"});
|
620
|
+
assert from_str("1.") ==
|
621
|
+
err({line: 1u, col: 3u, msg: "invalid number"});
|
622
|
+
assert from_str("1e") ==
|
623
|
+
err({line: 1u, col: 3u, msg: "invalid number"});
|
624
|
+
assert from_str("1e+") ==
|
625
|
+
err({line: 1u, col: 4u, msg: "invalid number"});
|
626
|
+
|
627
|
+
assert from_str("3") == ok(num(3f));
|
628
|
+
assert from_str("3.1") == ok(num(3.1f));
|
629
|
+
assert from_str("-1.2") == ok(num(-1.2f));
|
630
|
+
assert from_str("0.4") == ok(num(0.4f));
|
631
|
+
assert from_str("0.4e5") == ok(num(0.4e5f));
|
632
|
+
assert from_str("0.4e+15") == ok(num(0.4e15f));
|
633
|
+
assert from_str("0.4e-01") == ok(num(0.4e-01f));
|
634
|
+
assert from_str(" 3 ") == ok(num(3f));
|
635
|
+
}
|
636
|
+
|
637
|
+
#[test]
|
638
|
+
fn test_read_str() {
|
639
|
+
assert from_str("\"") ==
|
640
|
+
err({line: 1u, col: 2u, msg: "EOF while parsing string"});
|
641
|
+
assert from_str("\"lol") ==
|
642
|
+
err({line: 1u, col: 5u, msg: "EOF while parsing string"});
|
643
|
+
|
644
|
+
assert from_str("\"\"") == ok(string(""));
|
645
|
+
assert from_str("\"foo\"") == ok(string("foo"));
|
646
|
+
assert from_str("\"\\\"\"") == ok(string("\""));
|
647
|
+
assert from_str("\"\\b\"") == ok(string("\x08"));
|
648
|
+
assert from_str("\"\\n\"") == ok(string("\n"));
|
649
|
+
assert from_str("\"\\r\"") == ok(string("\r"));
|
650
|
+
assert from_str("\"\\t\"") == ok(string("\t"));
|
651
|
+
assert from_str(" \"foo\" ") == ok(string("foo"));
|
652
|
+
}
|
653
|
+
|
654
|
+
#[test]
|
655
|
+
fn test_read_list() {
|
656
|
+
assert from_str("[") ==
|
657
|
+
err({line: 1u, col: 2u, msg: "EOF while parsing value"});
|
658
|
+
assert from_str("[1") ==
|
659
|
+
err({line: 1u, col: 3u, msg: "EOF while parsing list"});
|
660
|
+
assert from_str("[1,") ==
|
661
|
+
err({line: 1u, col: 4u, msg: "EOF while parsing value"});
|
662
|
+
assert from_str("[1,]") ==
|
663
|
+
err({line: 1u, col: 4u, msg: "invalid syntax"});
|
664
|
+
assert from_str("[6 7]") ==
|
665
|
+
err({line: 1u, col: 4u, msg: "expecting ',' or ']'"});
|
666
|
+
|
667
|
+
assert from_str("[]") == ok(list([]));
|
668
|
+
assert from_str("[ ]") == ok(list([]));
|
669
|
+
assert from_str("[true]") == ok(list([boolean(true)]));
|
670
|
+
assert from_str("[ false ]") == ok(list([boolean(false)]));
|
671
|
+
assert from_str("[null]") == ok(list([null]));
|
672
|
+
assert from_str("[3, 1]") == ok(list([num(3f), num(1f)]));
|
673
|
+
assert from_str("\n[3, 2]\n") == ok(list([num(3f), num(2f)]));
|
674
|
+
assert from_str("[2, [4, 1]]") ==
|
675
|
+
ok(list([num(2f), list([num(4f), num(1f)])]));
|
676
|
+
}
|
677
|
+
|
678
|
+
#[test]
|
679
|
+
fn test_read_dict() {
|
680
|
+
assert from_str("{") ==
|
681
|
+
err({line: 1u, col: 2u, msg: "EOF while parsing object"});
|
682
|
+
assert from_str("{ ") ==
|
683
|
+
err({line: 1u, col: 3u, msg: "EOF while parsing object"});
|
684
|
+
assert from_str("{1") ==
|
685
|
+
err({line: 1u, col: 2u, msg: "key must be a string"});
|
686
|
+
assert from_str("{ \"a\"") ==
|
687
|
+
err({line: 1u, col: 6u, msg: "EOF while parsing object"});
|
688
|
+
assert from_str("{\"a\"") ==
|
689
|
+
err({line: 1u, col: 5u, msg: "EOF while parsing object"});
|
690
|
+
assert from_str("{\"a\" ") ==
|
691
|
+
err({line: 1u, col: 6u, msg: "EOF while parsing object"});
|
692
|
+
|
693
|
+
assert from_str("{\"a\" 1") ==
|
694
|
+
err({line: 1u, col: 6u, msg: "expecting ':'"});
|
695
|
+
assert from_str("{\"a\":") ==
|
696
|
+
err({line: 1u, col: 6u, msg: "EOF while parsing value"});
|
697
|
+
assert from_str("{\"a\":1") ==
|
698
|
+
err({line: 1u, col: 7u, msg: "EOF while parsing object"});
|
699
|
+
assert from_str("{\"a\":1 1") ==
|
700
|
+
err({line: 1u, col: 8u, msg: "expecting ',' or '}'"});
|
701
|
+
assert from_str("{\"a\":1,") ==
|
702
|
+
err({line: 1u, col: 8u, msg: "EOF while parsing object"});
|
703
|
+
|
704
|
+
assert eq(result::get(from_str("{}")), mk_dict([]));
|
705
|
+
assert eq(result::get(from_str("{\"a\": 3}")),
|
706
|
+
mk_dict([("a", num(3.0f))]));
|
707
|
+
|
708
|
+
assert eq(result::get(from_str("{ \"a\": null, \"b\" : true }")),
|
709
|
+
mk_dict([("a", null), ("b", boolean(true))]));
|
710
|
+
assert eq(result::get(from_str("\n{ \"a\": null, \"b\" : true }\n")),
|
711
|
+
mk_dict([("a", null), ("b", boolean(true))]));
|
712
|
+
assert eq(result::get(from_str("{\"a\" : 1.0 ,\"b\": [ true ]}")),
|
713
|
+
mk_dict([
|
714
|
+
("a", num(1.0)),
|
715
|
+
("b", list([boolean(true)]))
|
716
|
+
]));
|
717
|
+
assert eq(result::get(from_str(
|
718
|
+
"{" +
|
719
|
+
"\"a\": 1.0, " +
|
720
|
+
"\"b\": [" +
|
721
|
+
"true," +
|
722
|
+
"\"foo\\nbar\", " +
|
723
|
+
"{ \"c\": {\"d\": null} } " +
|
724
|
+
"]" +
|
725
|
+
"}")),
|
726
|
+
mk_dict([
|
727
|
+
("a", num(1.0f)),
|
728
|
+
("b", list([
|
729
|
+
boolean(true),
|
730
|
+
string("foo\nbar"),
|
731
|
+
mk_dict([
|
732
|
+
("c", mk_dict([("d", null)]))
|
733
|
+
])
|
734
|
+
]))
|
735
|
+
]));
|
736
|
+
}
|
737
|
+
|
738
|
+
#[test]
|
739
|
+
fn test_multiline_errors() {
|
740
|
+
assert from_str("{\n \"foo\":\n \"bar\"") ==
|
741
|
+
err({line: 3u, col: 8u, msg: "EOF while parsing object"});
|
742
|
+
}
|
743
|
+
}
|