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

Side by Side Diff: utils/peg/pegparser_test.dart

Issue 8448006: Move PEG parser test into testing framework. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: removed empty section Created 9 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | utils/tests/peg/peg.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
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 #import('pegparser.dart');
6
7 testParens() {
8 Grammar g = new Grammar();
9 Symbol a = g['A'];
10
11 a.def = ['(', MANY(a, min:0), ')', (a) => a];
12
13 check(g, a, "", null);
14 check(g, a, "()", '[]');
15 check(g, a, "(()())", '[[],[]]');
16 check(g, a, "(()((()))())", '[[],[[[]]],[]]');
17 }
18
19 testBlockComment() {
20
21 // Block comment in whitespace.
22
23 Grammar g = new Grammar();
24 Symbol blockComment = g['blockComment'];
25
26 blockComment.def =
27 ['/*',
28 MANY(OR([blockComment,
29 [NOT('*/'), CHAR()],
30 [END, ERROR('EOF in block comment')]
31 ]),
32 min: 0),
33 '*/'];
34 print(blockComment);
35
36 var a = MANY(TEXT('x'));
37
38 g.whitespace = OR([g.whitespace, blockComment]);
39
40 check(g, a, "x /**/ x", '[x,x]');
41 check(g, a, "x /*/**/*/ x", '[x,x]');
42 check(g, a, "x /*/***/ x", 'EOF in block comment');
43 check(g, a, "x /*/*/x**/**/ x", '[x,x]');
44
45 check(g, a, @"""
46 /* Comment */
47 /* Following comment with /* nested comment*/ */
48 x
49 /* x in comment */
50 x /* outside comment */
51 """,
52 '[x,x]');
53 }
54
55 testTEXT() {
56 Grammar g = new Grammar();
57
58 // TEXT grabs the parsed text,
59 check(g, TEXT(LEX(MANY(OR(['1','a'])))), ' 1a1 ', '1a1');
60
61 // Without the lexical context, TEXT will grab intervening whitespace.
62 check(g, TEXT(MANY(OR(['1','a']))), ' 1a1 ', '1a1');
63 check(g, TEXT(MANY(OR(['1','a']))), ' 1 a 1 ', '1 a 1');
64
65 // Custom processing of the TEXT substring.
66 var binaryNumber =
67 TEXT(LEX(MANY(OR(['0','1']))),
68 (str, start, end) {
69 var r = 0;
70 var zero = '0'.charCodeAt(0);
71 for (int i = start; i < end; i++)
72 r = r * 2 + (str.charCodeAt(i) - zero);
73 return r;
74 });
75
76 check(g, binaryNumber, ' 10101 ', 21);
77 check(g, binaryNumber, '1010111', 87);
78 check(g, binaryNumber, '1010 111', null);
79 }
80
81 testOR() {
82 // OR matches the first match.
83 Grammar g = new Grammar();
84 check(g, OR([['a', NOT(END), () => 1],
85 ['a', () => 2],
86 ['a', () => 3]]),
87 'a', 2);
88 }
89
90 testCODE() {
91 Grammar g = new Grammar();
92 var a = TEXT(LEX('thing', MANY(CHAR('bcd'))));
93
94 check(g, a, 'bbb', 'bbb');
95 check(g, a, 'ccc', 'ccc');
96 check(g, a, 'ddd', 'ddd');
97 check(g, a, 'bad', null); // a is outside range.
98 check(g, a, 'bed', null); // e is outside range.
99 }
100
101 testC() {
102 // Curried tree builders.
103 binary(operation) => (second) => (first) => [operation, first, second];
104 unary(operation) => () => (first) => [operation, first];
105 reform(a, fns) {
106 var r = a;
107 for (var fn in fns)
108 r = fn(r);
109 return r;
110 }
111
112 Grammar g = new Grammar();
113
114 Symbol expression = g['expression'];
115 Symbol postfix_e = g['postfix_e'];
116 Symbol unary_e = g['unary_e'];
117 Symbol cast_e = g['cast_e'];
118 Symbol mult_e = g['mult_e'];
119 Symbol add_e = g['add_e'];
120 Symbol shift_e = g['shift_e'];
121 Symbol relational_e = g['relational_e'];
122 Symbol equality_e = g['equality_e'];
123 Symbol cond_e = g['cond_e'];
124 Symbol assignment_e = g['assignment_e'];
125
126 // Lexical elements.
127 var idStartChar = CHAR(
128 @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
129 var idNextChar = CHAR(
130 @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$_");
131
132 var id = TEXT(LEX('identifier', [idStartChar, MANY(idNextChar, min: 0)]));
133
134 var lit = TEXT(LEX('literal', MANY(CHAR('0123456789'))));
135
136
137 var type_name = id;
138
139
140 // Expression grammar.
141 var primary_e = OR([id,
142 lit,
143 ['(', expression, ')', (e) => e]
144 ]);
145
146 var postfixes = OR([['(', MANY(assignment_e, ',', 0), ')', binary('apply')],
147 ['++', unary('postinc')],
148 ['--', unary('postdec')],
149 ['.', id, binary('field')],
150 ['->', id, binary('ptr')],
151 ]);
152
153 postfix_e.def = [primary_e, MANY(postfixes, min:0), reform];
154
155
156 var unary_op = OR([['&', () => 'address'],
157 ['*', () => 'indir'],
158 ['!', () => 'not'],
159 ['~', () => 'not'],
160 ['-', () => 'negate'],
161 ['+', () => 'uplus'],
162 ]);
163 var sizeof = LEX('sizeof', ['sizeof', NOT(idNextChar)]);
164
165 Symbol unary_e_plain = g['unary_e_plain'];
166 unary_e_plain.def =
167 OR([ ['++', unary_e, (e) => ['preinc', e]],
168 ['--', unary_e, (e) => ['predec', e]],
169 [unary_op, cast_e, (o, e) => [o, e]],
170 [sizeof, unary_e, (e) => ['sizeof-expr', e]],
171 [sizeof, '(', type_name , ')', (t) => ['sizeof-type', t]],
172 postfix_e
173 ]);
174
175 unary_e.def = MEMO(unary_e_plain);
176 //unary_e.def = unary_e_plain;
177
178 cast_e.def = OR([ ['(', type_name, ')', cast_e, (t, e) => ['cast', t, e]],
179 unary_e,
180 ]);
181
182 var mult_ops = OR([['*', cast_e, binary('mult')],
183 ['/', cast_e, binary('div')],
184 ['%', cast_e, binary('rem')],
185 ]);
186 mult_e.def = [cast_e, MANY(mult_ops, min:0), reform];
187
188 var add_ops = OR([['+', mult_e, binary('add')],
189 ['-', mult_e, binary('sub')],
190 ]);
191 add_e.def = [mult_e, MANY(add_ops, min:0), reform];
192
193 var shift_ops = OR([['>>', add_e, binary('shl')],
194 ['<<', add_e, binary('shr')],
195 ]);
196 shift_e.def = [add_e, MANY(shift_ops, min:0), reform];
197
198 var relational_ops = OR([['<=', shift_e, binary('le')],
199 ['>=', shift_e, binary('ge')],
200 ['<', shift_e, binary('lt')],
201 ['>', shift_e, binary('gt')],
202 ]);
203 relational_e.def = [shift_e, MANY(relational_ops, min:0), reform];
204
205
206 var equality_ops = OR([['==', shift_e, binary('eq')],
207 ['!=', shift_e, binary('ne')],
208 ]);
209 equality_e.def = [relational_e, MANY(equality_ops, min:0), reform];
210
211
212 var bit_and_op = LEX('&', ['&', NOT('&')]); // Don't see '&&' and '&', '&'
213 var bit_or_op = LEX('|', ['|', NOT('|')]);
214
215 var and_e = [equality_e, MANY([bit_and_op, equality_e, binary('bitand')], min: 0), reform];
216 var xor_e = [and_e, MANY(['^', and_e, binary('bitxor')], min:0), reform];
217 var or_e = [xor_e, MANY([bit_or_op, xor_e, binary('bitor')], min:0), reform];
218
219 var log_and_e = [or_e, MANY(['&&', or_e, binary('and')], min:0), reform];
220
221 var log_or_e = [log_and_e, MANY(['||', log_and_e, binary('or')], min:0), refor m];
222
223 //cond_e.def = OR([ [log_or_e, '?', expression, ':', cond_e,
224 // (p,a,b) => ['cond', p, a, b]],
225 // log_or_e]);
226 // Alternate version avoids reparsing log_or_e.
227 cond_e.def = [log_or_e, MAYBE(['?', expression, ':', cond_e]),
228 (p, r) => r == null || r == false ? p : ['cond', p, r[0], r[1]]] ;
229
230 var assign_op = OR([['*=', () => 'mulassign'],
231 ['=', () => 'assign']]);
232
233 // TODO: Figure out how not to re-parse a unary_e.
234 // Order matters - cond_e can't go first since cond_e will succeed on, e.g. 'a '.
235 assignment_e.def = OR([[unary_e, assign_op, assignment_e,
236 (u, op, a) => [op, u, a]],
237 cond_e]);
238
239 expression.def = [assignment_e,
240 MANY([',', assignment_e, binary('comma')], min:0),
241 reform];
242
243 show(g, expression, 'a');
244 check(g, expression, 'a', 'a');
245 check(g, expression, '(a)', 'a');
246 check(g, expression, ' ( ( a ) ) ', 'a');
247
248 check(g, expression, 'a(~1,2)', '[apply,a,[[not,1],2]]');
249 check(g, expression, 'a(1)(x,2)', '[apply,[apply,a,[1]],[x,2]]');
250 check(g, expression, 'a(1,2())', '[apply,a,[1,[apply,2,[]]]]');
251
252 check(g, expression, '++a++', '[preinc,[postinc,a]]');
253 check(g, expression, 'a++++b', null);
254 check(g, expression, 'a++ ++b', null);
255 check(g, expression, 'a+ +++b', '[add,a,[preinc,[uplus,b]]]');
256 check(g, expression, 'a+ + ++b', '[add,a,[uplus,[preinc,b]]]');
257 check(g, expression, 'a+ + + +b', '[add,a,[uplus,[uplus,[uplus,b]]]]');
258 check(g, expression, 'a+ ++ +b', '[add,a,[preinc,[uplus,b]]]');
259 check(g, expression, 'a++ + +b', '[add,[postinc,a],[uplus,b]]');
260 check(g, expression, 'a+++ +b', '[add,[postinc,a],[uplus,b]]');
261
262 check(g, expression, '((T)f)(x)', '[apply,[cast,T,f],[x]]');
263 check(g, expression, '(T)f(x)', '[cast,T,[apply,f,[x]]]');
264
265 check(g, expression, 'a++*++b', '[mult,[postinc,a],[preinc,b]]');
266
267 check(g, expression, 'a<<1>>++b', '[shl,[shr,a,1],[preinc,b]]');
268
269 check(g, expression, 'a<1&&b', '[and,[lt,a,1],b]');
270
271 check(g, expression, 'a<1 & &b', '[bitand,[lt,a,1],[address,b]]');
272 check(g, expression,
273 'a ? b ? c : d : e ? f : g',
274 '[cond,a,[cond,b,c,d],[cond,e,f,g]]');
275
276 check(g, expression, 'a,b,c', '[comma,[comma,a,b],c]');
277 check(g, expression, 'a=1,b,c', '[comma,[comma,[assign,a,1],b],c]');
278
279 check(g, expression,
280 '((((((((((((a))))))))))))=1,b,c', '[comma,[comma,[assign,a,1],b],c]');
281
282 check(g, expression, 'sizeof a', '[sizeof-expr,a]');
283 check(g, expression, 'sizeofa', 'sizeofa');
284 check(g, expression, 'sizeof (a)', '[sizeof-expr,a]');
285 }
286
287
288 show(grammar, rule, input) {
289 print('show: "$input"');
290 var ast;
291 try {
292 ast = grammar.parse(rule, input);
293 } catch (var exception) {
294 if (exception is ParseError)
295 ast = exception;
296 else
297 throw;
298 }
299 print('${printList(ast)}');
300 }
301
302 void check(grammar, rule, input, expected) {
303 // If [expected] is String then the result is coerced to string.
304 // If [expected] is !String, the result is compared directly.
305 print('check: "$input"');
306 var ast;
307 try {
308 ast = grammar.parse(rule, input);
309 } catch (var exception) {
310 ast = exception;
311 }
312
313 var formatted = ast;
314 if (expected is String)
315 formatted = printList(ast);
316
317 Expect.equals(expected, formatted, "parse: $input");
318 }
319
320 // Prints the list in [1,2,3] notation, including nested lists.
321 void printList(item) {
322 if (item is List) {
323 StringBuffer sb = new StringBuffer();
324 sb.add('[');
325 var sep = '';
326 for (var x in item) {
327 sb.add(sep);
328 sb.add(printList(x));
329 sep = ',';
330 }
331 sb.add(']');
332 return sb.toString();
333 }
334 if (item == null)
335 return 'null';
336 return item.toString();
337 }
338
339 main() {
340 testCODE();
341 testParens();
342 testOR();
343 testTEXT();
344 testBlockComment();
345 testC();
346 }
OLDNEW
« no previous file with comments | « no previous file | utils/tests/peg/peg.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698