] must-fail
{ 3 } [
- { 1 2 "a" 4 } EBNF[=[ num=. ?[ number? ]? list=list:x num:y => [[ x y + ]] | num ]=]
+ { 1 2 "a" 4 } PARTIAL-EBNF[=[ num=. ?[ number? ]? list=list:x num:y => [[ x y + ]] | num ]=]
] unit-test
[
] unit-test
{ V{ } } [
- "ab cab c" EBNF[=[ a="a" "b" foo=(a "c")* ]=]
+ "ab cab c" PARTIAL-EBNF[=[ a="a" "b" foo=(a "c")* ]=]
] unit-test
{ V{ V{ V{ "a" "b" } "c" } V{ V{ "a" "b" } "c" } } } [
] unit-test
{ V{ } } [
- "ab c ab c" EBNF[=[ a="a" "b" foo=(a "c")* ]=]
+ "ab c ab c" PARTIAL-EBNF[=[ a="a" "b" foo=(a "c")* ]=]
] unit-test
{ V{ } } [
- "ab c ab c" EBNF[=[ a="a" "b" foo=(a "c")* ]=]
+ "ab c ab c" PARTIAL-EBNF[=[ a="a" "b" foo=(a "c")* ]=]
] unit-test
{ V{ "a" "a" "a" } } [
] unit-test
{ "++" } [
- "++--" EBNF[=[ tokenizer=("++" | "--") main="++" ]=]
+ "++--" PARTIAL-EBNF[=[ tokenizer=("++" | "--") main="++" ]=]
] unit-test
{ "\\" } [
EBNF: parse-til-right-bracket [=[
foo = [^\]]+
]=]
- "abc]" parse-til-right-bracket >string
+ PARTIAL-EBNF: parse-til-right-bracket* parse-til-right-bracket
+ "abc]" parse-til-right-bracket* >string
] unit-test
! Doesn't match anything, don't run it.
EBNF: parse-empty-range [=[
foo = []+
]=]
+] unit-test
+
+[
+ [==[
+ EBNF: parse-empty-squote [=[
+ foo = ''
+ ]=]
+ ]==] parse-string
+] must-fail
+
+[
+ [==[
+ EBNF: parse-empty-squote [=[
+ foo = ""
+ ]=]
+ ]==] parse-string
+] must-fail
+
+! Bugfix, ensure that ~ rules are ignored with local labels
+{ { "a" "c" } } [
+ "abc" EBNF[=[ rule="a":a "b"~ "c":c => [[ a c 2array ]] ]=]
+] unit-test
+
+{ { "a" "c" } } [
+ "abc" EBNF[=[ rule="a":a "b"*~ "c":c => [[ a c 2array ]] ]=]
+] unit-test
+
+{ { "a" "c" } } [
+ "abc" EBNF[=[ rule="a":a "b"+~ "c":c => [[ a c 2array ]] ]=]
] unit-test
\ No newline at end of file
TUPLE: ebnf-ensure-not group ;
TUPLE: ebnf-choice options ;
TUPLE: ebnf-sequence elements ;
-TUPLE: ebnf-ignore group ;
TUPLE: ebnf-repeat0 group ;
TUPLE: ebnf-repeat1 group ;
+TUPLE: ebnf-ignore group ;
+TUPLE: ebnf-ignore-repeat0 group ;
+TUPLE: ebnf-ignore-repeat1 group ;
TUPLE: ebnf-optional group ;
TUPLE: ebnf-whitespace group ;
TUPLE: ebnf-tokenizer elements ;
C: <ebnf-ensure-not> ebnf-ensure-not
C: <ebnf-choice> ebnf-choice
C: <ebnf-sequence> ebnf-sequence
-C: <ebnf-ignore> ebnf-ignore
C: <ebnf-repeat0> ebnf-repeat0
C: <ebnf-repeat1> ebnf-repeat1
+C: <ebnf-ignore> ebnf-ignore
+C: <ebnf-ignore-repeat0> ebnf-ignore-repeat0
+C: <ebnf-ignore-repeat1> ebnf-ignore-repeat1
C: <ebnf-optional> ebnf-optional
C: <ebnf-whitespace> ebnf-whitespace
C: <ebnf-tokenizer> ebnf-tokenizer
C: <ebnf-semantic> ebnf-semantic
C: <ebnf> ebnf
+MIXIN: ebnf-ignored
+
+INSTANCE: ebnf-ignore ebnf-ignored
+INSTANCE: ebnf-ignore-repeat0 ebnf-ignored
+INSTANCE: ebnf-ignore-repeat1 ebnf-ignored
+
: filter-hidden ( seq -- seq )
! Remove elements that produce no AST from sequence
- [ ebnf-ensure-not? ] reject [ ebnf-ensure? ] reject ;
+ [ ebnf-ensure-not? ] reject [ ebnf-ensure? ] reject
+ [ ebnf-ignored? ] reject ;
: syntax ( string -- parser )
! Parses the string, ignoring white space, and
! A parser to match the symbol for any character match.
[ CHAR: . = ] satisfy [ drop <ebnf-any-character> ] action ;
-: range-parser-parser ( -- parser )
+: range-parser ( -- parser )
! Match the syntax for declaring character ranges
[
[ "[" syntax , "[" token ensure-not , ] seq* hide ,
non-terminal-parser ,
terminal-parser ,
foreign-parser ,
- range-parser-parser ,
+ range-parser ,
any-character-parser ,
] choice*
[ dup , "~" token hide , ] seq* [ first <ebnf-ignore> ] action ,
+ [ dup , "*~" token hide , ] seq* [ first <ebnf-ignore-repeat0> ] action ,
+ [ dup , "+~" token hide , ] seq* [ first <ebnf-ignore-repeat1> ] action ,
[ dup , "*" token hide , ] seq* [ first <ebnf-repeat0> ] action ,
[ dup , "+" token hide , ] seq* [ first <ebnf-repeat1> ] action ,
[ dup , "?[" token ensure-not , "?" token hide , ] seq* [ first <ebnf-optional> ] action ,
"?" token sp ensure-not ,
] seq* hide grouped ;
-: ignore-parser ( -- parser )
- [ <ebnf-ignore> ] "~" syntax grouped ;
-
: repeat0-parser ( -- parser )
[ <ebnf-repeat0> ] "*" syntax grouped ;
: repeat1-parser ( -- parser )
[ <ebnf-repeat1> ] "+" syntax grouped ;
+: ignore-parser ( -- parser )
+ [ <ebnf-ignore> ] "~" syntax grouped ;
+
+: ignore-repeat0-parser ( -- parser )
+ [ <ebnf-ignore-repeat0> ] "*~" syntax grouped ;
+
+: ignore-repeat1-parser ( -- parser )
+ [ <ebnf-ignore-repeat1> ] "+~" syntax grouped ;
+
: optional-parser ( -- parser )
[ <ebnf-optional> ] "?" syntax grouped ;
element-parser sp ,
group-parser sp ,
ignore-parser sp ,
+ ignore-repeat0-parser sp ,
+ ignore-repeat1-parser sp ,
repeat0-parser sp ,
repeat1-parser sp ,
optional-parser sp ,
M: ebnf-ignore (transform)
transform-group [ drop ignore ] action ;
+M: ebnf-ignore-repeat0 (transform)
+ transform-group repeat0 hide ;
+
+M: ebnf-ignore-repeat1 (transform)
+ transform-group repeat1 hide ;
+
M: ebnf-repeat0 (transform)
transform-group repeat0 ;
: parse-ebnf ( string -- hashtable )
ebnf-parser (parse) check-parse-result ast>> transform ;
-: ebnf>quot ( string -- hashtable quot )
+: ebnf>quot ( string -- hashtable quot: ( string -- results ) )
parse-ebnf dup dup parser [ main of compile ] with-variable
- [ compiled-parse ] curry [ with-scope ast>> ] curry ;
+ '[ [ _ compiled-parse ] with-scope ] ;
PRIVATE>
reset-tokenizer
scan-new-word dup scan-object
ebnf>quot swapd
- ( input -- ast ) define-declared "ebnf-parser" set-word-prop
- reset-tokenizer ;
+ [ "ebnf-quot" set-word-prop ] 2keep
+ [ check-parse-result ast>> ] compose
+ ( input -- ast ) define-declared
+ "ebnf-parser" set-word-prop ;
+
+SYNTAX: PARTIAL-EBNF:
+ scan-new-word
+ scan-word "ebnf-quot" word-prop
+ [ ast>> ] compose
+ ( input -- ast ) define-declared ;
: define-inline-ebnf ( ast string -- quot )
reset-tokenizer
- ebnf>quot nip
+ ebnf>quot [ check-parse-result ast>> ] compose nip
+ suffix! \ call suffix! reset-tokenizer ;
+
+: define-partial-inline-ebnf ( ast string -- quot )
+ reset-tokenizer
+ ebnf>quot [ ast>> ] compose nip
suffix! \ call suffix! reset-tokenizer ;
SYNTAX: EBNF[[ "]]" parse-multiline-string define-inline-ebnf ;
SYNTAX: EBNF[===[ "]===]" parse-multiline-string define-inline-ebnf ;
SYNTAX: EBNF[====[ "]====]" parse-multiline-string define-inline-ebnf ;
+SYNTAX: PARTIAL-EBNF[[ "]]" parse-multiline-string define-partial-inline-ebnf ;
+SYNTAX: PARTIAL-EBNF[=[ "]=]" parse-multiline-string define-partial-inline-ebnf ;
+SYNTAX: PARTIAL-EBNF[==[ "]==]" parse-multiline-string define-partial-inline-ebnf ;
+SYNTAX: PARTIAL-EBNF[===[ "]===]" parse-multiline-string define-partial-inline-ebnf ;
+SYNTAX: PARTIAL-EBNF[====[ "]====]" parse-multiline-string define-partial-inline-ebnf ;
+
SYNTAX: EBNF-PARSER:
reset-tokenizer
scan-new-word