]> gitweb.factorcode.org Git - factor.git/blob - basis/peg/ebnf/ebnf-tests.factor
Fix comments to be ! not #!.
[factor.git] / basis / peg / ebnf / ebnf-tests.factor
1 ! Copyright (C) 2007 Chris Double.
2 ! See http://factorcode.org/license.txt for BSD license.
3 !
4 USING: kernel tools.test peg peg.ebnf peg.ebnf.private words
5 math math.parser sequences accessors peg.parsers parser
6 namespaces arrays strings eval unicode.data multiline ;
7 IN: peg.ebnf.tests
8
9 { T{ ebnf-non-terminal f "abc" } } [
10   "abc" non-terminal-parser parse
11 ] unit-test
12
13 { T{ ebnf-terminal f "55" } } [
14   "'55'" terminal-parser parse
15 ] unit-test
16
17 {
18   T{ ebnf-rule f
19      "digit"
20      T{ ebnf-choice f
21         V{ T{ ebnf-terminal f "1" } T{ ebnf-terminal f "2" } }
22      }
23   }
24 } [
25   "digit = '1' | '2'" rule-parser parse
26 ] unit-test
27
28 {
29   T{ ebnf-rule f
30      "digit"
31      T{ ebnf-sequence f
32         V{ T{ ebnf-terminal f "1" } T{ ebnf-terminal f "2" } }
33      }
34   }
35 } [
36   "digit = '1' '2'" rule-parser parse
37 ] unit-test
38
39 {
40   T{ ebnf-choice f
41      V{
42        T{ ebnf-sequence f
43           V{ T{ ebnf-non-terminal f "one" } T{ ebnf-non-terminal f "two" } }
44        }
45        T{ ebnf-non-terminal f "three" }
46      }
47   }
48 } [
49   "one two | three" choice-parser parse
50 ] unit-test
51
52 {
53   T{ ebnf-sequence f
54      V{
55        T{ ebnf-non-terminal f "one" }
56        T{ ebnf-whitespace f
57          T{ ebnf-choice f
58             V{ T{ ebnf-non-terminal f "two" } T{ ebnf-non-terminal f "three" } }
59          }
60        }
61      }
62   }
63 } [
64   "one {two | three}" choice-parser parse
65 ] unit-test
66
67 {
68   T{ ebnf-sequence f
69      V{
70        T{ ebnf-non-terminal f "one" }
71        T{ ebnf-repeat0 f
72           T{ ebnf-sequence f
73              V{
74                 T{ ebnf-choice f
75                    V{ T{ ebnf-non-terminal f "two" } T{ ebnf-non-terminal f "three" } }
76                 }
77                 T{ ebnf-non-terminal f "four" }
78              }
79           }
80         }
81      }
82   }
83 } [
84   "one ((two | three) four)*" choice-parser parse
85 ] unit-test
86
87 {
88   T{ ebnf-sequence f
89      V{
90        T{ ebnf-non-terminal f "one" }
91        T{ ebnf-ignore f
92           T{ ebnf-sequence f
93              V{
94                 T{ ebnf-choice f
95                    V{ T{ ebnf-non-terminal f "two" } T{ ebnf-non-terminal f "three" } }
96                 }
97                 T{ ebnf-non-terminal f "four" }
98              }
99           }
100         }
101      }
102   }
103 } [
104   "one ((two | three) four)~" choice-parser parse
105 ] unit-test
106
107 {
108   T{ ebnf-sequence f
109      V{
110          T{ ebnf-non-terminal f "one" }
111          T{ ebnf-optional f T{ ebnf-non-terminal f "two" } }
112          T{ ebnf-non-terminal f "three" }
113      }
114   }
115 } [
116   "one ( two )? three" choice-parser parse
117 ] unit-test
118
119 { "foo" } [
120   "\"foo\"" identifier-parser parse
121 ] unit-test
122
123 { "foo" } [
124   "'foo'" identifier-parser parse
125 ] unit-test
126
127 { "\"" } [
128   "\"\\\"\"" identifier-parser parse
129 ] unit-test
130
131 { "\\" } [
132   "\"\\\\\"" identifier-parser parse
133 ] unit-test
134
135 { "AΣ𝄞" } [
136   "'\\x41\\u{greek-capital-letter-sigma}\\u01D11E'" identifier-parser parse
137 ] unit-test
138
139 { "foo" } [
140   "foo" non-terminal-parser parse symbol>>
141 ] unit-test
142
143 { "foo" } [
144   "foo]" non-terminal-parser parse symbol>>
145 ] unit-test
146
147 { V{ "a" "b" } } [
148   "ab" [EBNF foo='a' 'b' EBNF]
149 ] unit-test
150
151 { V{ 1 "b" } } [
152   "ab" [EBNF foo=('a')[[ drop 1 ]] 'b' EBNF]
153 ] unit-test
154
155 { V{ 1 2 } } [
156   "ab" [EBNF foo=('a') [[ drop 1 ]] ('b') [[ drop 2 ]] EBNF]
157 ] unit-test
158
159 { CHAR: A } [
160   "A" [EBNF foo=[A-Z] EBNF]
161 ] unit-test
162
163 { CHAR: Z } [
164   "Z" [EBNF foo=[A-Z] EBNF]
165 ] unit-test
166
167 [
168   "0" [EBNF foo=[A-Z] EBNF]
169 ] must-fail
170
171 { CHAR: 0 } [
172   "0" [EBNF foo=[^A-Z] EBNF]
173 ] unit-test
174
175 [
176   "A" [EBNF foo=[^A-Z] EBNF]
177 ] must-fail
178
179 [
180   "Z" [EBNF foo=[^A-Z] EBNF]
181 ] must-fail
182
183 { V{ "1" "+" "foo" } } [
184   "1+1" [EBNF foo='1' '+' '1' [[ drop "foo" ]] EBNF]
185 ] unit-test
186
187 { "foo" } [
188   "1+1" [EBNF foo='1' '+' '1' => [[ drop "foo" ]] EBNF]
189 ] unit-test
190
191 { "foo" } [
192   "1+1" [EBNF foo='1' '+' '1' => [[ drop "foo" ]] | '1' '-' '1' => [[ drop "bar" ]] EBNF]
193 ] unit-test
194
195 { "bar" } [
196   "1-1" [EBNF foo='1' '+' '1' => [[ drop "foo" ]] | '1' '-' '1' => [[ drop "bar" ]] EBNF]
197 ] unit-test
198
199 { 6 } [
200   "4+2" [EBNF num=[0-9] => [[ digit> ]] foo=num:x '+' num:y => [[ x y + ]] EBNF]
201 ] unit-test
202
203 { 6 } [
204   "4+2" [EBNF foo=[0-9]:x '+' [0-9]:y => [[ x digit> y digit> + ]] EBNF]
205 ] unit-test
206
207 { 10 } [
208   { 1 2 3 4 } [EBNF num=. ?[ number? ]? list=list:x num:y => [[ x y + ]] | num EBNF]
209 ] unit-test
210
211 [
212   { "a" 2 3 4 } [EBNF num=. ?[ number? ]? list=list:x num:y => [[ x y + ]] | num EBNF]
213 ] must-fail
214
215 { 3 } [
216   { 1 2 "a" 4 } [EBNF num=. ?[ number? ]? list=list:x num:y => [[ x y + ]] | num EBNF]
217 ] unit-test
218
219 [
220   "ab" [EBNF -=" " | "\t" | "\n" foo="a" - "b" EBNF]
221 ] must-fail
222
223 { V{ "a" " " "b" } } [
224   "a b" [EBNF -=" " | "\t" | "\n" foo="a" - "b" EBNF]
225 ] unit-test
226
227 { V{ "a" "\t" "b" } } [
228   "a\tb" [EBNF -=" " | "\t" | "\n" foo="a" - "b" EBNF]
229 ] unit-test
230
231 { V{ "a" "\n" "b" } } [
232   "a\nb" [EBNF -=" " | "\t" | "\n" foo="a" - "b" EBNF]
233 ] unit-test
234
235 { V{ "a" f "b" } } [
236   "ab" [EBNF -=" " | "\t" | "\n" foo="a" (-)? "b" EBNF]
237 ] unit-test
238
239 { V{ "a" " " "b" } } [
240   "a b" [EBNF -=" " | "\t" | "\n" foo="a" (-)? "b" EBNF]
241 ] unit-test
242
243
244 { V{ "a" "\t" "b" } } [
245   "a\tb" [EBNF -=" " | "\t" | "\n" foo="a" (-)? "b" EBNF]
246 ] unit-test
247
248 { V{ "a" "\n" "b" } } [
249   "a\nb" [EBNF -=" " | "\t" | "\n" foo="a" (-)? "b" EBNF]
250 ] unit-test
251
252 { V{ "a" "b" } } [
253   "ab" [EBNF -=(" " | "\t" | "\n")? => [[ drop ignore ]] foo="a" - "b" EBNF]
254 ] unit-test
255
256 { V{ "a" "b" } } [
257   "a\tb" [EBNF -=(" " | "\t" | "\n")? => [[ drop ignore ]] foo="a" - "b" EBNF]
258 ] unit-test
259
260 { V{ "a" "b" } } [
261   "a\nb" [EBNF -=(" " | "\t" | "\n")? => [[ drop ignore ]] foo="a" - "b" EBNF]
262 ] unit-test
263
264 [
265   "axb" [EBNF -=(" " | "\t" | "\n")? => [[ drop ignore ]] foo="a" - "b" EBNF]
266 ] must-fail
267
268 { V{ V{ 49 } "+" V{ 49 } } } [
269   ! Test direct left recursion.
270   ! Using packrat, so first part of expr fails, causing 2nd choice to be used
271   "1+1" [EBNF num=([0-9])+ expr=expr "+" num | num EBNF]
272 ] unit-test
273
274 { V{ V{ V{ 49 } "+" V{ 49 } } "+" V{ 49 } } } [
275   ! Test direct left recursion.
276   ! Using packrat, so first part of expr fails, causing 2nd choice to be used
277   "1+1+1" [EBNF num=([0-9])+ expr=expr "+" num | num EBNF]
278 ] unit-test
279
280 { V{ V{ V{ 49 } "+" V{ 49 } } "+" V{ 49 } } } [
281   ! Test indirect left recursion.
282   ! Using packrat, so first part of expr fails, causing 2nd choice to be used
283   "1+1+1" [EBNF num=([0-9])+ x=expr expr=x "+" num | num EBNF]
284 ] unit-test
285
286 { t } [
287   "abcd='9' | ('8'):x => [[ x ]]" ebnf-parser (parse) remaining>> empty?
288 ] unit-test
289
290 EBNF: primary 
291 Primary = PrimaryNoNewArray
292 PrimaryNoNewArray =  ClassInstanceCreationExpression
293                    | MethodInvocation
294                    | FieldAccess
295                    | ArrayAccess
296                    | "this"
297 ClassInstanceCreationExpression =  "new" ClassOrInterfaceType "(" ")"
298                                  | Primary "." "new" Identifier "(" ")"
299 MethodInvocation =  Primary "." MethodName "(" ")"
300                   | MethodName "(" ")"
301 FieldAccess =  Primary "." Identifier
302              | "super" "." Identifier  
303 ArrayAccess =  Primary "[" Expression "]" 
304              | ExpressionName "[" Expression "]"
305 ClassOrInterfaceType = ClassName | InterfaceTypeName
306 ClassName = "C" | "D"
307 InterfaceTypeName = "I" | "J"
308 Identifier = "x" | "y" | ClassOrInterfaceType
309 MethodName = "m" | "n"
310 ExpressionName = Identifier
311 Expression = "i" | "j"
312 main = Primary
313 ;EBNF
314
315 { "this" } [
316   "this" primary
317 ] unit-test
318
319 { V{ "this" "." "x" } } [
320   "this.x" primary
321 ] unit-test
322
323 { V{ V{ "this" "." "x" } "." "y" } } [
324   "this.x.y" primary
325 ] unit-test
326
327 { V{ V{ "this" "." "x" } "." "m" "(" ")" } } [
328   "this.x.m()" primary
329 ] unit-test
330
331 { V{ V{ V{ "x" "[" "i" "]" } "[" "j" "]" } "." "y" } } [
332   "x[i][j].y" primary
333 ] unit-test
334
335 { V{ V{ "a" "b" } "c" } } [
336   "abc" [EBNF a="a" "b" foo=(a "c") EBNF]
337 ] unit-test
338
339 { V{ "a" "c" } } [
340   "abc" [EBNF a="a" "b"~ foo=(a "c") EBNF]
341 ] unit-test
342
343 { V{ V{ "a" V{ "b" "b" } } "c" } } [
344   "abbc" [EBNF a=("a" "b"*) foo=(a "c") EBNF]
345 ] unit-test
346
347 { V{ "a" "c" } } [
348   "abc" [EBNF a=("a" ("b")~) foo=(a "c") EBNF]
349 ] unit-test
350
351 { V{ "a" "c" } } [
352   "abc" [EBNF a=("a" "b"~) foo=(a "c") EBNF]
353 ] unit-test
354
355 { "c" } [
356   "abc" [EBNF a=("a" "b")~ foo=(a "c") EBNF]
357 ] unit-test
358
359 { V{ V{ "a" "b" } "c" } } [
360   "abc" [EBNF a="a" "b" foo={a "c"} EBNF]
361 ] unit-test
362
363 { V{ V{ "a" "b" } "c" } } [
364   "abc" [EBNF a="a" "b" foo=a "c" EBNF]
365 ] unit-test
366
367 [
368   "a bc" [EBNF a="a" "b" foo=(a "c") EBNF]
369 ] must-fail
370
371 [
372   "a bc" [EBNF a="a" "b" foo=a "c" EBNF]
373 ] must-fail
374
375 [
376   "a bc" [EBNF a="a" "b" foo={a "c"} EBNF]
377 ] must-fail
378
379 [
380   "ab c" [EBNF a="a" "b" foo=a "c" EBNF]
381 ] must-fail
382
383 { V{ V{ "a" "b" } "c" } } [
384   "ab c" [EBNF a="a" "b" foo={a "c"} EBNF]
385 ] unit-test
386
387 [
388   "ab c" [EBNF a="a" "b" foo=(a "c") EBNF]
389 ] must-fail
390
391 [
392   "a b c" [EBNF a="a" "b" foo=a "c" EBNF]
393 ] must-fail
394
395 [
396   "a b c" [EBNF a="a" "b" foo=(a "c") EBNF]
397 ] must-fail
398
399 [
400   "a b c" [EBNF a="a" "b" foo={a "c"} EBNF]
401 ] must-fail
402
403 { V{ V{ V{ "a" "b" } "c" } V{ V{ "a" "b" } "c" } } } [
404   "ab cab c" [EBNF a="a" "b" foo={a "c"}* EBNF]
405 ] unit-test
406
407 { V{ } } [
408   "ab cab c" [EBNF a="a" "b" foo=(a "c")* EBNF]
409 ] unit-test
410
411 { V{ V{ V{ "a" "b" } "c" } V{ V{ "a" "b" } "c" } } } [
412   "ab c ab c" [EBNF a="a" "b" foo={a "c"}* EBNF]
413 ] unit-test
414
415 { V{ V{ "a" "c" } V{ "a" "c" } } } [
416   "ab c ab c" [EBNF a="a" "b"~ foo={a "c"}* EBNF]
417 ] unit-test
418
419 { V{ } } [
420   "ab c ab c" [EBNF a="a" "b" foo=(a "c")* EBNF]
421 ] unit-test
422
423 { V{ } } [
424   "ab c ab c" [EBNF a="a" "b" foo=(a "c")* EBNF]
425 ] unit-test
426
427 { V{ "a" "a" "a" } } [
428   "aaa" [EBNF a=('a')* b=!('b') a:x => [[ x ]] EBNF]
429 ] unit-test
430
431 { t } [
432   "aaa" [EBNF a=('a')* b=!('b') a:x => [[ x ]] EBNF]
433   "aaa" [EBNF a=('a')* b=!('b') (a):x => [[ x ]] EBNF] =
434 ] unit-test
435
436 { V{ "a" "a" "a" } } [
437   "aaa" [EBNF a=('a')* b=a:x => [[ x ]] EBNF]
438 ] unit-test
439
440 { t } [
441   "aaa" [EBNF a=('a')* b=a:x => [[ x ]] EBNF]
442   "aaa" [EBNF a=('a')* b=(a):x => [[ x ]] EBNF] =
443 ] unit-test
444
445 { t } [
446   "number=(digit)+:n 'a'" ebnf-parser (parse) remaining>> length zero?
447 ] unit-test
448
449 { t } [
450   "number=(digit)+ 'a'" ebnf-parser (parse) remaining>> length zero?
451 ] unit-test
452
453 { t } [
454   "number=digit+ 'a'" ebnf-parser (parse) remaining>> length zero?
455 ] unit-test
456
457 { t } [
458   "number=digit+:n 'a'" ebnf-parser (parse) remaining>> length zero?
459 ] unit-test
460
461 { t } [
462   "foo=(name):n !(keyword) => [[ n ]]" rule-parser parse
463   "foo=name:n !(keyword) => [[ n ]]" rule-parser parse =
464 ] unit-test
465
466 { t } [
467   "foo=!(keyword) (name):n => [[ n ]]" rule-parser parse
468   "foo=!(keyword) name:n => [[ n ]]" rule-parser parse =
469 ] unit-test
470
471 <<
472 EBNF: parser1 
473 foo='a' 
474 ;EBNF
475 >>
476
477 EBNF: parser2
478 foo=<foreign parser1 foo> 'b'
479 ;EBNF
480
481 EBNF: parser3
482 foo=<foreign parser1> 'c'
483 ;EBNF
484
485 EBNF: parser4
486 foo=<foreign any-char> 'd'
487 ;EBNF
488
489 { "a" } [
490   "a" parser1
491 ] unit-test
492
493 { V{ "a" "b" } } [
494   "ab" parser2
495 ] unit-test
496
497 { V{ "a" "c" } } [
498   "ac" parser3
499 ] unit-test
500
501 { V{ CHAR: a "d" } } [
502   "ad" parser4
503 ] unit-test
504
505 { } [
506  "USING: kernel peg.ebnf ; \"a\\n\" [EBNF foo='a' '\n'  => [[ drop \"\n\" ]] EBNF] drop" eval( -- )
507 ] unit-test
508
509 [
510   "USING: peg.ebnf ; <EBNF foo='a' foo='b' EBNF>" eval( -- ) drop
511 ] must-fail
512
513 { t } [
514   ! Rule lookup occurs in a namespace. This causes an incorrect duplicate rule
515   ! if a var in a namespace is set. This unit test is to remind me to fix this.
516   [ "fail" "foo" set "foo='a'" ebnf-parser parse transform drop t ] with-scope
517 ] unit-test
518
519 #! Tokenizer tests
520 { V{ "a" CHAR: b } } [
521   "ab" [EBNF tokenizer=default foo="a" . EBNF]
522 ] unit-test
523
524 TUPLE: ast-number value ;
525
526 EBNF: a-tokenizer 
527 Letter            = [a-zA-Z]
528 Digit             = [0-9]
529 Digits            = Digit+
530 SingleLineComment = "//" (!("\n") .)* "\n" => [[ ignore ]]
531 MultiLineComment  = "/*" (!("*/") .)* "*/" => [[ ignore ]]
532 Space             = " " | "\t" | "\r" | "\n" | SingleLineComment | MultiLineComment
533 Spaces            = Space* => [[ ignore ]]
534 Number            = Digits:ws '.' Digits:fs => [[ ws "." fs 3array "" concat-as string>number ast-number boa ]]
535                     | Digits => [[ >string string>number ast-number boa ]]  
536 Special            =   "("   | ")"   | "{"   | "}"   | "["   | "]"   | ","   | ";"
537                      | "?"   | ":"   | "!==" | "~="  | "===" | "=="  | "="   | ">="
538                      | ">"   | "<="  | "<"   | "++"  | "+="  | "+"   | "--"  | "-="
539                      | "-"   | "*="  | "*"   | "/="  | "/"   | "%="  | "%"   | "&&="
540                      | "&&"  | "||=" | "||"  | "."   | "!"
541 Tok                = Spaces (Number | Special )
542 ;EBNF
543
544 { V{ CHAR: 1 T{ ast-number f 23 } ";" CHAR: x } } [
545   "123;x" [EBNF bar = .
546                 tokenizer = <foreign a-tokenizer Tok>  foo=.
547                 tokenizer=default baz=.
548                 main = bar foo foo baz
549           EBNF]
550 ] unit-test
551
552 { V{ CHAR: 5 "+" CHAR: 2 } } [
553   "5+2" [EBNF
554           space=(" " | "\n")
555           number=[0-9]
556           operator=("*" | "+")
557           spaces=space* => [[ ignore ]]
558           tokenizer=spaces (number | operator)
559           main= . . .
560         EBNF]
561 ] unit-test
562
563 { V{ CHAR: 5 "+" CHAR: 2 } } [
564   "5 + 2" [EBNF
565           space=(" " | "\n")
566           number=[0-9]
567           operator=("*" | "+")
568           spaces=space* => [[ ignore ]]
569           tokenizer=spaces (number | operator)
570           main= . . .
571         EBNF]
572 ] unit-test
573
574 { "++" } [
575   "++--" [EBNF tokenizer=("++" | "--") main="++" EBNF]
576 ] unit-test
577
578 { "\\" } [
579   "\\" [EBNF foo="\\" EBNF]
580 ] unit-test
581
582 [ "USE: peg.ebnf [EBNF EBNF]" eval( -- ) ] must-fail
583
584 [ "USE: peg.ebnf [EBNF
585     lol = a
586     lol = b
587   EBNF]" eval( -- )
588 ] [
589     error>> [ redefined-rule? ] [ name>> "lol" = ] bi and
590 ] must-fail-with
591
592 {
593     { "a" "a" }
594 } [
595     EBNF: foo   Bar = "a":a1 "a":a2 => [[ a1 a2 2array ]] ;EBNF
596     "aa" foo
597 ] unit-test
598
599 {
600     { "a" "a" }
601 } [
602     EBNF: foo2   Bar = "a":a-1 "a":a-2 => [[ a-1 a-2 2array ]] ;EBNF
603     "aa" foo2
604 ] unit-test