factor/basis/peg/peg.factor

646 lines
16 KiB
Factor
Raw Normal View History

2008-03-29 00:37:52 -04:00
! Copyright (C) 2007, 2008 Chris Double.
2007-11-19 22:36:38 -05:00
! See http://factorcode.org/license.txt for BSD license.
USING: kernel sequences strings fry namespaces make math assocs
shuffle debugger io vectors arrays math.parser math.order
vectors combinators classes sets unicode.categories
compiler.units parser words quotations effects memoize accessors
locals effects splitting combinators.short-circuit
combinators.short-circuit.smart generalizations ;
2007-11-19 22:36:38 -05:00
IN: peg
2008-03-28 06:20:43 -04:00
USE: prettyprint
2007-11-20 21:31:23 -05:00
TUPLE: parse-result remaining ast ;
2008-06-25 03:37:58 -04:00
TUPLE: parse-error position messages ;
2008-07-08 00:10:06 -04:00
TUPLE: parser peg compiled id ;
2008-03-30 00:48:01 -04:00
2008-07-10 01:17:36 -04:00
M: parser equal? { [ [ class ] bi@ = ] [ [ id>> ] bi@ = ] } 2&& ;
2008-03-30 00:48:01 -04:00
M: parser hashcode* id>> hashcode* ;
2008-07-08 00:10:06 -04:00
C: <parse-result> parse-result
C: <parse-error> parse-error
2008-07-03 01:38:28 -04:00
M: parse-error error.
"Peg parsing error at character position " write dup position>> number>string write
"." print "Expected " write messages>> [ " or " write ] [ write ] interleave nl ;
2008-06-25 03:37:58 -04:00
SYMBOL: error-stack
: (merge-errors) ( a b -- c )
{
{ [ over position>> not ] [ nip ] }
{ [ dup position>> not ] [ drop ] }
[ 2dup [ position>> ] bi@ <=> {
{ +lt+ [ nip ] }
{ +gt+ [ drop ] }
{ +eq+ [ messages>> over messages>> union [ position>> ] dip <parse-error> ] }
} case
]
} cond ;
: merge-errors ( -- )
error-stack get dup length 1 > [
dup pop over pop swap (merge-errors) swap push
] [
drop
] if ;
2007-11-26 18:22:33 -05:00
: add-error ( remaining message -- )
2008-06-25 03:37:58 -04:00
<parse-error> error-stack get push ;
SYMBOL: ignore
2007-11-19 22:36:38 -05:00
2008-07-08 20:07:17 -04:00
: packrat ( id -- cache )
#! The packrat cache is a mapping of parser-id->cache.
#! For each parser it maps to a cache holding a mapping
#! of position->result. The packrat cache therefore keeps
#! track of all parses that have occurred at each position
#! of the input string and the results obtained from that
#! parser.
\ packrat get [ drop H{ } clone ] cache ;
2008-03-28 06:20:43 -04:00
SYMBOL: pos
SYMBOL: input
SYMBOL: fail
SYMBOL: lrstack
2008-07-08 20:07:17 -04:00
: heads ( -- cache )
#! A mapping from position->peg-head. It maps a
#! position in the input string being parsed to
#! the head of the left recursion which is currently
#! being grown. It is 'f' at any position where
#! left recursion growth is not underway.
\ heads get ;
2008-03-28 06:20:43 -04:00
2008-04-08 20:52:49 -04:00
: failed? ( obj -- ? )
fail = ;
2008-07-08 00:10:06 -04:00
: peg-cache ( -- cache )
#! Holds a hashtable mapping a peg tuple to
#! the parser tuple for that peg. The parser tuple
#! holds a unique id and the compiled form of that peg.
\ peg-cache get-global [
H{ } clone dup \ peg-cache set-global
] unless* ;
: reset-pegs ( -- )
2008-07-08 00:10:06 -04:00
H{ } clone \ peg-cache set-global ;
reset-pegs
2008-07-08 20:07:17 -04:00
#! An entry in the table of memoized parse results
#! ast = an AST produced from the parse
#! or the symbol 'fail'
#! or a left-recursion object
#! pos = the position in the input string of this entry
2008-03-28 06:20:43 -04:00
TUPLE: memo-entry ans pos ;
2008-03-27 22:51:18 -04:00
TUPLE: left-recursion seed rule-id head next ;
TUPLE: peg-head rule-id involved-set eval-set ;
2008-07-08 20:07:17 -04:00
: rule-id ( word -- id )
2008-03-28 06:20:43 -04:00
#! A rule is the parser compiled down to a word. It has
2008-07-08 20:07:17 -04:00
#! a "peg-id" property containing the id of the original parser.
"peg-id" word-prop ;
2008-03-28 06:20:43 -04:00
: input-slice ( -- slice )
#! Return a slice of the input from the current parse position
input get pos get tail-slice ;
2008-03-27 22:51:18 -04:00
: input-from ( input -- n )
#! Return the index from the original string that the
#! input slice is based on.
2008-08-30 15:06:10 -04:00
dup slice? [ from>> ] [ drop 0 ] if ;
2008-03-27 22:51:18 -04:00
2008-04-08 20:52:49 -04:00
: process-rule-result ( p result -- result )
[
nip [ ast>> ] [ remaining>> ] bi input-from pos set
] [
pos set fail
] if* ;
2008-03-28 06:20:43 -04:00
: eval-rule ( rule -- ast )
#! Evaluate a rule, return an ast resulting from it.
#! Return fail if the rule failed. The rule has
2008-07-08 19:45:51 -04:00
#! stack effect ( -- parse-result )
2008-04-08 20:52:49 -04:00
pos get swap execute process-rule-result ; inline
2008-03-20 10:05:21 -04:00
: memo ( pos id -- memo-entry )
2008-03-28 06:20:43 -04:00
#! Return the result from the memo cache.
packrat at
2008-07-08 20:07:17 -04:00
! " memo result " write dup .
;
2008-03-27 00:45:59 -04:00
: set-memo ( memo-entry pos id -- )
2008-03-28 06:20:43 -04:00
#! Store an entry in the cache
packrat set-at ;
2008-04-08 20:52:49 -04:00
: update-m ( ast m -- )
swap >>ans pos get >>pos drop ;
: stop-growth? ( ast m -- ? )
[ failed? pos get ] dip
pos>> <= or ;
: setup-growth ( h p -- )
pos set dup involved-set>> clone >>eval-set drop ;
2008-08-22 19:09:38 -04:00
: (grow-lr) ( h p r: ( -- result ) m -- )
2008-04-10 22:46:11 -04:00
>r >r [ setup-growth ] 2keep r> r>
>r dup eval-rule r> swap
dup pick stop-growth? [
2008-08-22 19:09:38 -04:00
5 ndrop
2008-03-28 08:17:54 -04:00
] [
2008-04-10 22:46:11 -04:00
over update-m
(grow-lr)
2008-08-22 19:09:38 -04:00
] if ; inline recursive
2008-03-28 08:17:54 -04:00
2008-04-10 22:46:11 -04:00
: grow-lr ( h p r m -- ast )
2008-07-08 20:07:17 -04:00
>r >r [ heads set-at ] 2keep r> r>
2008-04-10 22:46:11 -04:00
pick over >r >r (grow-lr) r> r>
2008-07-08 20:07:17 -04:00
swap heads delete-at
2008-04-10 22:46:11 -04:00
dup pos>> pos set ans>>
2008-03-28 23:11:08 -04:00
; inline
2008-03-28 08:17:54 -04:00
:: (setup-lr) ( r l s -- )
s head>> l head>> eq? [
l head>> s (>>head)
l head>> [ s rule-id>> suffix ] change-involved-set drop
r l s next>> (setup-lr)
] unless ;
:: setup-lr ( r l -- )
l head>> [
r rule-id V{ } clone V{ } clone peg-head boa l (>>head)
] unless
r l lrstack get (setup-lr) ;
:: lr-answer ( r p m -- ast )
[let* |
h [ m ans>> head>> ]
|
h rule-id>> r rule-id eq? [
m ans>> seed>> m (>>ans)
2008-04-08 20:52:49 -04:00
m ans>> failed? [
fail
] [
2008-04-08 20:52:49 -04:00
h p r m grow-lr
] if
] [
m ans>> seed>>
] if
2008-03-28 23:11:08 -04:00
] ; inline
:: recall ( r p -- memo-entry )
[let* |
m [ p r rule-id memo ]
2008-07-08 20:07:17 -04:00
h [ p heads at ]
|
h [
m r rule-id h involved-set>> h rule-id>> suffix member? not and [
2008-07-08 20:07:17 -04:00
fail p memo-entry boa
] [
r rule-id h eval-set>> member? [
h [ r rule-id swap remove ] change-eval-set drop
r eval-rule
2008-04-08 20:52:49 -04:00
m update-m
m
] [
m
] if
] if
] [
m
] if
2008-03-28 23:11:08 -04:00
] ; inline
2008-03-28 06:20:43 -04:00
:: apply-non-memo-rule ( r p -- ast )
2008-03-27 22:51:18 -04:00
[let* |
lr [ fail r rule-id f lrstack get left-recursion boa ]
m [ lr lrstack set lr p memo-entry boa dup p r rule-id set-memo ]
2008-03-28 06:20:43 -04:00
ans [ r eval-rule ]
2008-03-27 22:51:18 -04:00
|
lrstack get next>> lrstack set
2008-03-28 07:49:39 -04:00
pos get m (>>pos)
lr head>> [
ans lr (>>seed)
r p m lr-answer
2008-03-28 08:17:54 -04:00
] [
ans m (>>ans)
2008-03-28 08:17:54 -04:00
ans
] if
2008-03-28 23:11:08 -04:00
] ; inline
2008-03-27 22:51:18 -04:00
2008-04-04 09:07:17 -04:00
: apply-memo-rule ( r m -- ast )
[ ans>> ] [ pos>> ] bi pos set
dup left-recursion? [
[ setup-lr ] keep seed>>
] [
2008-04-04 09:07:17 -04:00
nip
] if ;
2008-03-27 22:51:18 -04:00
2008-07-08 20:07:17 -04:00
USE: prettyprint
2008-04-04 08:56:37 -04:00
: apply-rule ( r p -- ast )
2008-07-08 20:07:17 -04:00
! 2dup [ rule-id ] dip 2array "apply-rule: " write .
2008-04-04 08:56:37 -04:00
2dup recall [
2008-07-08 20:07:17 -04:00
! " memoed" print
2008-04-04 08:56:37 -04:00
nip apply-memo-rule
] [
2008-07-08 20:07:17 -04:00
! " not memoed" print
2008-04-04 08:56:37 -04:00
apply-non-memo-rule
] if* ; inline
2008-03-27 22:51:18 -04:00
2008-03-28 06:20:43 -04:00
: with-packrat ( input quot -- result )
#! Run the quotation with a packrat cache active.
swap [
input set
0 pos set
f lrstack set
2008-06-25 03:37:58 -04:00
V{ } clone error-stack set
2008-07-08 20:07:17 -04:00
H{ } clone \ heads set
H{ } clone \ packrat set
2008-03-28 23:24:13 -04:00
] H{ } make-assoc swap bind ; inline
2008-03-27 22:51:18 -04:00
2008-07-08 00:10:06 -04:00
GENERIC: (compile) ( peg -- quot )
2008-03-27 00:45:59 -04:00
2008-07-08 00:56:12 -04:00
: process-parser-result ( result -- result )
dup failed? [
2008-04-08 20:52:49 -04:00
drop f
] [
input-slice swap <parse-result>
2008-07-08 00:56:12 -04:00
] if ;
: execute-parser ( word -- result )
pos get apply-rule process-parser-result ; inline
2008-03-26 00:38:30 -04:00
2008-04-08 20:52:49 -04:00
: parser-body ( parser -- quot )
#! Return the body of the word that is the compiled version
#! of the parser.
2008-07-08 20:07:17 -04:00
gensym 2dup swap peg>> (compile) 0 1 <effect> define-declared swap dupd id>> "peg-id" set-word-prop
2008-04-08 20:52:49 -04:00
[ execute-parser ] curry ;
2008-07-10 10:27:28 -04:00
: preset-parser-word ( parser -- parser word )
gensym [ >>compiled ] keep ;
: define-parser-word ( parser word -- )
swap parser-body (( -- result )) define-declared ;
: compile-parser ( parser -- word )
#! Look to see if the given parser has been compiled.
2008-03-20 10:05:21 -04:00
#! If not, compile it to a temporary word, cache it,
#! and return it. Otherwise return the existing one.
2008-03-27 21:10:33 -04:00
#! Circular parsers are supported by getting the word
#! name and storing it in the cache, before compiling,
#! so it is picked up when re-entered.
dup compiled>> [
nip
] [
2008-07-10 10:27:28 -04:00
preset-parser-word [ define-parser-word ] keep
] if* ;
2008-03-20 10:05:21 -04:00
2008-04-14 06:42:45 -04:00
SYMBOL: delayed
: fixup-delayed ( -- )
#! Work through all delayed parsers and recompile their
#! words to have the correct bodies.
delayed get [
2008-07-10 10:27:28 -04:00
call compile-parser 1quotation 0 1 <effect> define-declared
2008-04-14 06:42:45 -04:00
] assoc-each ;
: compile ( parser -- word )
2008-04-14 06:42:45 -04:00
[
H{ } clone delayed [
2008-07-10 10:27:28 -04:00
compile-parser fixup-delayed
2008-04-14 06:42:45 -04:00
] with-variable
] with-compilation-unit ;
2008-03-20 10:05:21 -04:00
2008-03-28 23:24:13 -04:00
: compiled-parse ( state word -- result )
2008-07-03 00:52:22 -04:00
swap [ execute [ error-stack get first throw ] unless* ] with-packrat ; inline
2008-03-28 23:24:13 -04:00
2008-07-03 22:20:19 -04:00
: (parse) ( input parser -- result )
2008-03-28 23:24:13 -04:00
dup word? [ compile ] unless compiled-parse ;
2008-07-03 22:20:19 -04:00
: parse ( input parser -- ast )
(parse) ast>> ;
2007-11-28 18:35:45 -05:00
<PRIVATE
SYMBOL: id
: next-id ( -- n )
#! Return the next unique id for a parser
id get-global [
dup 1+ id set-global
] [
1 id set-global 0
] if* ;
2008-07-08 00:10:06 -04:00
: wrap-peg ( peg -- parser )
#! Wrap a parser tuple around the peg object.
#! Look for an existing parser tuple for that
#! peg object.
peg-cache [
f next-id parser boa
] cache ;
2007-11-19 22:36:38 -05:00
TUPLE: token-parser symbol ;
: parse-token ( input string -- result )
#! Parse the string, returning a parse result
2008-08-23 00:00:35 -04:00
[ ?head-slice ] keep swap [
<parse-result> f f add-error
] [
2008-08-23 00:00:35 -04:00
>r drop pos get "token '" r> append "'" append 1vector add-error f
] if ;
2008-07-08 00:10:06 -04:00
M: token-parser (compile) ( peg -- quot )
2008-09-10 23:11:40 -04:00
symbol>> '[ input-slice _ parse-token ] ;
2008-03-28 06:20:43 -04:00
TUPLE: satisfy-parser quot ;
2008-04-05 00:15:43 -04:00
: parse-satisfy ( input quot -- result )
swap dup empty? [
2drop f
] [
unclip-slice rot dupd call [
<parse-result>
] [
2drop f
] if
] if ; inline
2008-07-08 00:10:06 -04:00
M: satisfy-parser (compile) ( peg -- quot )
2008-09-10 23:11:40 -04:00
quot>> '[ input-slice _ parse-satisfy ] ;
2007-11-26 21:08:16 -05:00
2007-11-19 22:36:38 -05:00
TUPLE: range-parser min max ;
2008-04-05 00:30:10 -04:00
: parse-range ( input min max -- result )
pick empty? [
3drop f
] [
pick first -rot between? [
unclip-slice <parse-result>
] [
drop f
2008-04-05 00:30:10 -04:00
] if
] if ;
2008-07-08 00:10:06 -04:00
M: range-parser (compile) ( peg -- quot )
2008-09-10 23:11:40 -04:00
[ min>> ] [ max>> ] bi '[ input-slice _ _ parse-range ] ;
2007-11-19 22:36:38 -05:00
TUPLE: seq-parser parsers ;
2008-04-05 00:51:42 -04:00
: ignore? ( ast -- bool )
ignore = ;
2008-04-05 00:25:04 -04:00
2008-04-05 00:51:42 -04:00
: calc-seq-result ( prev-result current-result -- next-result )
[
2008-04-05 00:51:42 -04:00
[ remaining>> swap (>>remaining) ] 2keep
ast>> dup ignore? [
drop
] [
2008-04-05 00:51:42 -04:00
swap [ ast>> push ] keep
] if
] [
drop f
] if* ;
: parse-seq-element ( result quot -- result )
over [
call calc-seq-result
] [
2drop f
] if ; inline
2007-11-19 22:36:38 -05:00
2008-07-08 00:10:06 -04:00
M: seq-parser (compile) ( peg -- quot )
[
2008-03-28 06:20:43 -04:00
[ input-slice V{ } clone <parse-result> ] %
[
2008-07-10 10:27:28 -04:00
parsers>> unclip compile-parser 1quotation [ parse-seq-element ] curry ,
[ compile-parser 1quotation [ merge-errors ] compose [ parse-seq-element ] curry , ] each
] { } make , \ && ,
] [ ] make ;
2007-11-19 22:36:38 -05:00
2007-11-19 23:58:11 -05:00
TUPLE: choice-parser parsers ;
2008-07-08 00:10:06 -04:00
M: choice-parser (compile) ( peg -- quot )
2008-03-28 06:20:43 -04:00
[
2008-07-10 07:09:29 -04:00
[
2008-07-10 10:27:28 -04:00
parsers>> [ compile-parser ] map
2008-07-10 07:09:29 -04:00
unclip 1quotation , [ 1quotation [ merge-errors ] compose , ] each
] { } make , \ || ,
] [ ] make ;
2007-11-19 23:58:11 -05:00
2007-11-20 21:01:44 -05:00
TUPLE: repeat0-parser p1 ;
2008-08-23 00:00:35 -04:00
: (repeat) ( quot: ( -- result ) result -- result )
2008-03-28 06:20:43 -04:00
over call [
2008-03-25 23:08:14 -04:00
[ remaining>> swap (>>remaining) ] 2keep
ast>> swap [ ast>> push ] keep
(repeat)
] [
2007-11-20 21:01:44 -05:00
nip
2008-08-23 00:00:35 -04:00
] if* ; inline recursive
2007-11-20 21:01:44 -05:00
2008-07-08 00:10:06 -04:00
M: repeat0-parser (compile) ( peg -- quot )
2008-07-10 10:27:28 -04:00
p1>> compile-parser 1quotation '[
2008-09-10 23:11:40 -04:00
input-slice V{ } clone <parse-result> _ swap (repeat)
] ;
2007-11-20 21:01:44 -05:00
TUPLE: repeat1-parser p1 ;
: repeat1-empty-check ( result -- result )
[
dup ast>> empty? [ drop f ] when
] [
f
] if* ;
2008-07-08 00:10:06 -04:00
M: repeat1-parser (compile) ( peg -- quot )
2008-07-10 10:27:28 -04:00
p1>> compile-parser 1quotation '[
2008-09-10 23:11:40 -04:00
input-slice V{ } clone <parse-result> _ swap (repeat) repeat1-empty-check
] ;
2007-11-20 21:01:44 -05:00
2007-11-20 21:50:47 -05:00
TUPLE: optional-parser p1 ;
2008-04-05 01:05:09 -04:00
: check-optional ( result -- result )
[ input-slice f <parse-result> ] unless* ;
2008-07-08 00:10:06 -04:00
M: optional-parser (compile) ( peg -- quot )
2008-07-10 10:27:28 -04:00
p1>> compile-parser 1quotation '[ @ check-optional ] ;
2007-11-20 21:50:47 -05:00
2008-03-30 23:34:59 -04:00
TUPLE: semantic-parser p1 quot ;
2008-04-05 01:19:11 -04:00
: check-semantic ( result quot -- result )
over [
over ast>> swap call [ drop f ] unless
] [
drop
] if ; inline
2008-03-30 23:34:59 -04:00
2008-07-08 00:10:06 -04:00
M: semantic-parser (compile) ( peg -- quot )
2008-07-10 10:27:28 -04:00
[ p1>> compile-parser 1quotation ] [ quot>> ] bi
2008-09-10 23:11:40 -04:00
'[ @ _ check-semantic ] ;
2008-03-30 23:34:59 -04:00
2007-11-20 22:06:02 -05:00
TUPLE: ensure-parser p1 ;
2008-04-05 01:30:11 -04:00
: check-ensure ( old-input result -- result )
[ ignore <parse-result> ] [ drop f ] if ;
2008-07-08 00:10:06 -04:00
M: ensure-parser (compile) ( peg -- quot )
2008-07-10 10:27:28 -04:00
p1>> compile-parser 1quotation '[ input-slice @ check-ensure ] ;
2007-11-20 22:06:02 -05:00
2007-11-20 22:11:49 -05:00
TUPLE: ensure-not-parser p1 ;
2008-04-05 01:30:11 -04:00
: check-ensure-not ( old-input result -- result )
[ drop f ] [ ignore <parse-result> ] if ;
2008-07-08 00:10:06 -04:00
M: ensure-not-parser (compile) ( peg -- quot )
2008-07-10 10:27:28 -04:00
p1>> compile-parser 1quotation '[ input-slice @ check-ensure-not ] ;
2007-11-20 22:11:49 -05:00
2007-11-20 22:21:23 -05:00
TUPLE: action-parser p1 quot ;
2008-04-05 01:33:50 -04:00
: check-action ( result quot -- result )
over [
over ast>> swap call >>ast
] [
drop
] if ; inline
2008-07-08 00:10:06 -04:00
M: action-parser (compile) ( peg -- quot )
2008-09-10 23:11:40 -04:00
[ p1>> compile-parser 1quotation ] [ quot>> ] bi '[ @ _ check-action ] ;
2007-11-20 22:21:23 -05:00
2007-11-26 21:36:26 -05:00
TUPLE: sp-parser p1 ;
2008-07-08 00:10:06 -04:00
M: sp-parser (compile) ( peg -- quot )
2008-07-10 10:27:28 -04:00
p1>> compile-parser 1quotation '[
2008-09-05 21:14:37 -04:00
input-slice [ blank? ] trim-left-slice input-from pos set @
2008-04-05 01:36:17 -04:00
] ;
2007-11-26 21:36:26 -05:00
2007-11-26 22:16:21 -05:00
TUPLE: delay-parser quot ;
2008-07-08 00:10:06 -04:00
M: delay-parser (compile) ( peg -- quot )
#! For efficiency we memoize the quotation.
#! This way it is run only once and the
#! parser constructed once at run time.
2008-04-14 06:42:45 -04:00
quot>> gensym [ delayed get set-at ] keep 1quotation ;
2007-11-26 22:16:21 -05:00
2008-03-29 00:42:21 -04:00
TUPLE: box-parser quot ;
2008-07-08 00:10:06 -04:00
M: box-parser (compile) ( peg -- quot )
2008-03-29 00:42:21 -04:00
#! Calls the quotation at compile time
#! to produce the parser to be compiled.
#! This differs from 'delay' which calls
2008-07-08 00:10:06 -04:00
#! it at run time.
2008-07-10 10:27:28 -04:00
quot>> call compile-parser 1quotation ;
2008-03-29 00:42:21 -04:00
2007-11-26 18:22:33 -05:00
PRIVATE>
: token ( string -- parser )
2008-07-08 00:10:06 -04:00
token-parser boa wrap-peg ;
2007-11-26 18:22:33 -05:00
: satisfy ( quot -- parser )
2008-07-08 00:10:06 -04:00
satisfy-parser boa wrap-peg ;
2007-11-26 21:08:16 -05:00
: range ( min max -- parser )
2008-07-08 00:10:06 -04:00
range-parser boa wrap-peg ;
2007-11-26 18:22:33 -05:00
: seq ( seq -- parser )
2008-07-08 00:10:06 -04:00
seq-parser boa wrap-peg ;
2007-11-26 18:22:33 -05:00
: 2seq ( parser1 parser2 -- parser )
2008-02-26 16:17:17 -05:00
2array seq ;
: 3seq ( parser1 parser2 parser3 -- parser )
2008-02-26 16:17:17 -05:00
3array seq ;
: 4seq ( parser1 parser2 parser3 parser4 -- parser )
4array seq ;
2008-03-27 18:30:46 -04:00
: seq* ( quot -- paser )
2008-02-13 16:39:37 -05:00
{ } make seq ; inline
: choice ( seq -- parser )
2008-07-08 00:10:06 -04:00
choice-parser boa wrap-peg ;
2007-11-26 18:22:33 -05:00
: 2choice ( parser1 parser2 -- parser )
2array choice ;
: 3choice ( parser1 parser2 parser3 -- parser )
3array choice ;
: 4choice ( parser1 parser2 parser3 parser4 -- parser )
4array choice ;
2008-03-27 18:30:46 -04:00
: choice* ( quot -- paser )
2008-02-13 16:39:37 -05:00
{ } make choice ; inline
: repeat0 ( parser -- parser )
2008-07-08 00:10:06 -04:00
repeat0-parser boa wrap-peg ;
2007-11-26 18:22:33 -05:00
: repeat1 ( parser -- parser )
2008-07-08 00:10:06 -04:00
repeat1-parser boa wrap-peg ;
2007-11-26 18:22:33 -05:00
: optional ( parser -- parser )
2008-07-08 00:10:06 -04:00
optional-parser boa wrap-peg ;
2008-03-30 23:34:59 -04:00
: semantic ( parser quot -- parser )
2008-07-08 00:10:06 -04:00
semantic-parser boa wrap-peg ;
2007-11-26 18:22:33 -05:00
: ensure ( parser -- parser )
2008-07-08 00:10:06 -04:00
ensure-parser boa wrap-peg ;
2007-11-26 18:22:33 -05:00
: ensure-not ( parser -- parser )
2008-07-08 00:10:06 -04:00
ensure-not-parser boa wrap-peg ;
2007-11-26 18:22:33 -05:00
: action ( parser quot -- parser )
2008-07-08 00:10:06 -04:00
action-parser boa wrap-peg ;
2007-11-26 21:36:26 -05:00
: sp ( parser -- parser )
2008-07-08 00:10:06 -04:00
sp-parser boa wrap-peg ;
2007-11-26 21:45:00 -05:00
: hide ( parser -- parser )
2007-11-26 21:45:00 -05:00
[ drop ignore ] action ;
2007-11-26 22:16:21 -05:00
: delay ( quot -- parser )
2008-07-08 00:10:06 -04:00
delay-parser boa wrap-peg ;
2008-03-03 17:57:30 -05:00
2008-03-29 00:42:21 -04:00
: box ( quot -- parser )
2008-03-30 07:53:33 -04:00
#! because a box has its quotation run at compile time
2008-07-08 00:10:06 -04:00
#! it must always have a new parser wrapper created,
2008-03-30 07:53:33 -04:00
#! not a cached one. This is because the same box,
#! compiled twice can have a different compiled word
#! due to running at compile time.
#! Why the [ ] action at the end? Box parsers don't get
#! memoized during parsing due to all box parsers being
#! unique. This breaks left recursion detection during the
#! parse. The action adds an indirection with a parser type
#! that gets memoized and fixes this. Need to rethink how
#! to fix boxes so this isn't needed...
2008-07-08 00:10:06 -04:00
box-parser boa f next-id parser boa [ ] action ;
2008-03-29 00:42:21 -04:00
2008-06-18 01:35:19 -04:00
ERROR: parse-failed input word ;
M: parse-failed error.
"The " write dup word>> pprint " word could not parse the following input:" print nl
input>> . ;
2008-03-03 17:57:30 -05:00
: PEG:
2008-06-18 01:35:19 -04:00
(:)
2008-06-18 02:18:39 -04:00
[let | def [ ] word [ ] |
2008-03-03 17:57:30 -05:00
[
2008-06-18 01:35:19 -04:00
[
2008-06-18 02:18:39 -04:00
[let | compiled-def [ def call compile ] |
2008-06-18 01:58:29 -04:00
[
dup compiled-def compiled-parse
[ ast>> ] [ word parse-failed ] ?if
]
word swap define
2008-06-18 01:35:19 -04:00
]
] with-compilation-unit
] over push-all
] ; parsing