1 ! Copyright (C) 2007 Chris Double.
2 ! See http://factorcode.org/license.txt for BSD license.
4 USING: kernel tools.test peg peg.ebnf words math math.parser
5 sequences accessors peg.parsers parser namespaces arrays
9 { T{ ebnf-non-terminal f "abc" } } [
10 "abc" 'non-terminal' parse
13 { T{ ebnf-terminal f "55" } } [
14 "'55'" 'terminal' parse
21 V{ T{ ebnf-terminal f "1" } T{ ebnf-terminal f "2" } }
25 "digit = '1' | '2'" 'rule' parse
32 V{ T{ ebnf-terminal f "1" } T{ ebnf-terminal f "2" } }
36 "digit = '1' '2'" 'rule' parse
43 V{ T{ ebnf-non-terminal f "one" } T{ ebnf-non-terminal f "two" } }
45 T{ ebnf-non-terminal f "three" }
49 "one two | three" 'choice' parse
55 T{ ebnf-non-terminal f "one" }
58 V{ T{ ebnf-non-terminal f "two" } T{ ebnf-non-terminal f "three" } }
64 "one {two | three}" 'choice' parse
70 T{ ebnf-non-terminal f "one" }
75 V{ T{ ebnf-non-terminal f "two" } T{ ebnf-non-terminal f "three" } }
77 T{ ebnf-non-terminal f "four" }
84 "one ((two | three) four)*" 'choice' parse
90 T{ ebnf-non-terminal f "one" }
91 T{ ebnf-optional f T{ ebnf-non-terminal f "two" } }
92 T{ ebnf-non-terminal f "three" }
96 "one ( two )? three" 'choice' parse
100 "\"foo\"" 'identifier' parse
104 "'foo'" 'identifier' parse
108 "foo" 'non-terminal' parse symbol>>
112 "foo]" 'non-terminal' parse symbol>>
116 "ab" [EBNF foo='a' 'b' EBNF]
120 "ab" [EBNF foo=('a')[[ drop 1 ]] 'b' EBNF]
124 "ab" [EBNF foo=('a') [[ drop 1 ]] ('b') [[ drop 2 ]] EBNF]
128 "A" [EBNF foo=[A-Z] EBNF]
132 "Z" [EBNF foo=[A-Z] EBNF]
136 "0" [EBNF foo=[A-Z] EBNF]
140 "0" [EBNF foo=[^A-Z] EBNF]
144 "A" [EBNF foo=[^A-Z] EBNF]
148 "Z" [EBNF foo=[^A-Z] EBNF]
151 { V{ "1" "+" "foo" } } [
152 "1+1" [EBNF foo='1' '+' '1' [[ drop "foo" ]] EBNF]
156 "1+1" [EBNF foo='1' '+' '1' => [[ drop "foo" ]] EBNF]
160 "1+1" [EBNF foo='1' '+' '1' => [[ drop "foo" ]] | '1' '-' '1' => [[ drop "bar" ]] EBNF]
164 "1-1" [EBNF foo='1' '+' '1' => [[ drop "foo" ]] | '1' '-' '1' => [[ drop "bar" ]] EBNF]
168 "4+2" [EBNF num=[0-9] => [[ digit> ]] foo=num:x '+' num:y => [[ x y + ]] EBNF]
172 "4+2" [EBNF foo=[0-9]:x '+' [0-9]:y => [[ x digit> y digit> + ]] EBNF]
176 { 1 2 3 4 } [EBNF num=. ?[ number? ]? list=list:x num:y => [[ x y + ]] | num EBNF]
180 { "a" 2 3 4 } [EBNF num=. ?[ number? ]? list=list:x num:y => [[ x y + ]] | num EBNF]
184 { 1 2 "a" 4 } [EBNF num=. ?[ number? ]? list=list:x num:y => [[ x y + ]] | num EBNF]
188 "ab" [EBNF -=" " | "\t" | "\n" foo="a" - "b" EBNF]
191 { V{ "a" " " "b" } } [
192 "a b" [EBNF -=" " | "\t" | "\n" foo="a" - "b" EBNF]
195 { V{ "a" "\t" "b" } } [
196 "a\tb" [EBNF -=" " | "\t" | "\n" foo="a" - "b" EBNF]
199 { V{ "a" "\n" "b" } } [
200 "a\nb" [EBNF -=" " | "\t" | "\n" foo="a" - "b" EBNF]
204 "ab" [EBNF -=" " | "\t" | "\n" foo="a" (-)? "b" EBNF]
207 { V{ "a" " " "b" } } [
208 "a b" [EBNF -=" " | "\t" | "\n" foo="a" (-)? "b" EBNF]
212 { V{ "a" "\t" "b" } } [
213 "a\tb" [EBNF -=" " | "\t" | "\n" foo="a" (-)? "b" EBNF]
216 { V{ "a" "\n" "b" } } [
217 "a\nb" [EBNF -=" " | "\t" | "\n" foo="a" (-)? "b" EBNF]
221 "ab" [EBNF -=(" " | "\t" | "\n")? => [[ drop ignore ]] foo="a" - "b" EBNF]
225 "a\tb" [EBNF -=(" " | "\t" | "\n")? => [[ drop ignore ]] foo="a" - "b" EBNF]
229 "a\nb" [EBNF -=(" " | "\t" | "\n")? => [[ drop ignore ]] foo="a" - "b" EBNF]
233 "axb" [EBNF -=(" " | "\t" | "\n")? => [[ drop ignore ]] foo="a" - "b" EBNF]
236 { V{ V{ 49 } "+" V{ 49 } } } [
237 #! Test direct left recursion.
238 #! Using packrat, so first part of expr fails, causing 2nd choice to be used
239 "1+1" [EBNF num=([0-9])+ expr=expr "+" num | num EBNF]
242 { V{ V{ V{ 49 } "+" V{ 49 } } "+" V{ 49 } } } [
243 #! Test direct left recursion.
244 #! Using packrat, so first part of expr fails, causing 2nd choice to be used
245 "1+1+1" [EBNF num=([0-9])+ expr=expr "+" num | num EBNF]
248 { V{ V{ V{ 49 } "+" V{ 49 } } "+" V{ 49 } } } [
249 #! Test indirect left recursion.
250 #! Using packrat, so first part of expr fails, causing 2nd choice to be used
251 "1+1+1" [EBNF num=([0-9])+ x=expr expr=x "+" num | num EBNF]
255 "abcd='9' | ('8'):x => [[ x ]]" 'ebnf' (parse) remaining>> empty?
259 Primary = PrimaryNoNewArray
260 PrimaryNoNewArray = ClassInstanceCreationExpression
265 ClassInstanceCreationExpression = "new" ClassOrInterfaceType "(" ")"
266 | Primary "." "new" Identifier "(" ")"
267 MethodInvocation = Primary "." MethodName "(" ")"
269 FieldAccess = Primary "." Identifier
270 | "super" "." Identifier
271 ArrayAccess = Primary "[" Expression "]"
272 | ExpressionName "[" Expression "]"
273 ClassOrInterfaceType = ClassName | InterfaceTypeName
274 ClassName = "C" | "D"
275 InterfaceTypeName = "I" | "J"
276 Identifier = "x" | "y" | ClassOrInterfaceType
277 MethodName = "m" | "n"
278 ExpressionName = Identifier
279 Expression = "i" | "j"
287 { V{ "this" "." "x" } } [
291 { V{ V{ "this" "." "x" } "." "y" } } [
295 { V{ V{ "this" "." "x" } "." "m" "(" ")" } } [
299 { V{ V{ V{ "x" "[" "i" "]" } "[" "j" "]" } "." "y" } } [
303 'ebnf' compile must-infer
305 { V{ V{ "a" "b" } "c" } } [
306 "abc" [EBNF a="a" "b" foo=(a "c") EBNF]
309 { V{ V{ "a" "b" } "c" } } [
310 "abc" [EBNF a="a" "b" foo={a "c"} EBNF]
313 { V{ V{ "a" "b" } "c" } } [
314 "abc" [EBNF a="a" "b" foo=a "c" EBNF]
318 "a bc" [EBNF a="a" "b" foo=(a "c") EBNF]
322 "a bc" [EBNF a="a" "b" foo=a "c" EBNF]
326 "a bc" [EBNF a="a" "b" foo={a "c"} EBNF]
330 "ab c" [EBNF a="a" "b" foo=a "c" EBNF]
333 { V{ V{ "a" "b" } "c" } } [
334 "ab c" [EBNF a="a" "b" foo={a "c"} EBNF]
338 "ab c" [EBNF a="a" "b" foo=(a "c") EBNF]
342 "a b c" [EBNF a="a" "b" foo=a "c" EBNF]
346 "a b c" [EBNF a="a" "b" foo=(a "c") EBNF]
350 "a b c" [EBNF a="a" "b" foo={a "c"} EBNF]
353 { V{ V{ V{ "a" "b" } "c" } V{ V{ "a" "b" } "c" } } } [
354 "ab cab c" [EBNF a="a" "b" foo={a "c"}* EBNF]
358 "ab cab c" [EBNF a="a" "b" foo=(a "c")* EBNF]
361 { V{ V{ V{ "a" "b" } "c" } V{ V{ "a" "b" } "c" } } } [
362 "ab c ab c" [EBNF a="a" "b" foo={a "c"}* EBNF]
366 "ab c ab c" [EBNF a="a" "b" foo=(a "c")* EBNF]
369 { V{ "a" "a" "a" } } [
370 "aaa" [EBNF a=('a')* b=!('b') a:x => [[ x ]] EBNF]
374 "aaa" [EBNF a=('a')* b=!('b') a:x => [[ x ]] EBNF]
375 "aaa" [EBNF a=('a')* b=!('b') (a):x => [[ x ]] EBNF] =
378 { V{ "a" "a" "a" } } [
379 "aaa" [EBNF a=('a')* b=a:x => [[ x ]] EBNF]
383 "aaa" [EBNF a=('a')* b=a:x => [[ x ]] EBNF]
384 "aaa" [EBNF a=('a')* b=(a):x => [[ x ]] EBNF] =
388 "number=(digit)+:n 'a'" 'ebnf' (parse) remaining>> length zero?
392 "number=(digit)+ 'a'" 'ebnf' (parse) remaining>> length zero?
396 "number=digit+ 'a'" 'ebnf' (parse) remaining>> length zero?
400 "number=digit+:n 'a'" 'ebnf' (parse) remaining>> length zero?
404 "foo=(name):n !(keyword) => [[ n ]]" 'rule' parse
405 "foo=name:n !(keyword) => [[ n ]]" 'rule' parse =
409 "foo=!(keyword) (name):n => [[ n ]]" 'rule' parse
410 "foo=!(keyword) name:n => [[ n ]]" 'rule' parse =
420 foo=<foreign parser1 foo> 'b'
424 foo=<foreign parser1> 'c'
428 foo=<foreign any-char> 'd'
443 { V{ CHAR: a "d" } } [
448 "USING: kernel peg.ebnf ; \"a\\n\" [EBNF foo='a' '\n' => [[ drop \"\n\" ]] EBNF]" eval drop t
452 "USING: peg.ebnf ; <EBNF foo='a' foo='b' EBNF>" eval drop
456 #! Rule lookup occurs in a namespace. This causes an incorrect duplicate rule
457 #! if a var in a namespace is set. This unit test is to remind me to fix this.
458 [ "fail" "foo" set "foo='a'" 'ebnf' parse transform drop t ] with-scope
462 { V{ "a" CHAR: b } } [
463 "ab" [EBNF tokenizer=default foo="a" . EBNF]
466 TUPLE: ast-number value ;
472 SingleLineComment = "//" (!("\n") .)* "\n" => [[ ignore ]]
473 MultiLineComment = "/*" (!("*/") .)* "*/" => [[ ignore ]]
474 Space = " " | "\t" | "\r" | "\n" | SingleLineComment | MultiLineComment
475 Spaces = Space* => [[ ignore ]]
476 Number = Digits:ws '.' Digits:fs => [[ ws "." fs 3array concat >string string>number ast-number boa ]]
477 | Digits => [[ >string string>number ast-number boa ]]
478 Special = "(" | ")" | "{" | "}" | "[" | "]" | "," | ";"
479 | "?" | ":" | "!==" | "~=" | "===" | "==" | "=" | ">="
480 | ">" | "<=" | "<" | "++" | "+=" | "+" | "--" | "-="
481 | "-" | "*=" | "*" | "/=" | "/" | "%=" | "%" | "&&="
482 | "&&" | "||=" | "||" | "." | "!"
483 Tok = Spaces (Number | Special )
486 { V{ CHAR: 1 T{ ast-number f 23 } ";" CHAR: x } } [
487 "123;x" [EBNF bar = .
488 tokenizer = <foreign a-tokenizer Tok> foo=.
489 tokenizer=default baz=.
490 main = bar foo foo baz
494 { V{ CHAR: 5 "+" CHAR: 2 } } [
499 spaces=space* => [[ ignore ]]
500 tokenizer=spaces (number | operator)
505 { V{ CHAR: 5 "+" CHAR: 2 } } [
510 spaces=space* => [[ ignore ]]
511 tokenizer=spaces (number | operator)
517 "++--" [EBNF tokenizer=("++" | "--") main="++" EBNF]
521 "\\" [EBNF foo="\\" EBNF]