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