Merge commit 'doublec/master'
						commit
						31102fc37c
					
				| 
						 | 
				
			
			@ -9,27 +9,91 @@ IN: temporary
 | 
			
		|||
] unit-test
 | 
			
		||||
 | 
			
		||||
{ T{ ebnf-terminal f "55" } } [
 | 
			
		||||
  "\"55\"" 'terminal' parse parse-result-ast 
 | 
			
		||||
  "'55'" 'terminal' parse parse-result-ast 
 | 
			
		||||
] unit-test
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
  T{ ebnf-rule f 
 | 
			
		||||
     "digit"
 | 
			
		||||
     V{ 
 | 
			
		||||
       T{ ebnf-choice f
 | 
			
		||||
          V{ T{ ebnf-terminal f "1" } T{ ebnf-terminal f "2" } }
 | 
			
		||||
       }
 | 
			
		||||
       f
 | 
			
		||||
     }
 | 
			
		||||
  } 
 | 
			
		||||
} [
 | 
			
		||||
  "digit = '1' | '2'" 'rule' parse parse-result-ast
 | 
			
		||||
] unit-test
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
  T{ ebnf-rule f 
 | 
			
		||||
     "digit" 
 | 
			
		||||
     T{ ebnf-choice f
 | 
			
		||||
        V{ T{ ebnf-terminal f "1" } T{ ebnf-terminal f "2" } }
 | 
			
		||||
     V{
 | 
			
		||||
       T{ ebnf-sequence f
 | 
			
		||||
          V{ T{ ebnf-terminal f "1" } T{ ebnf-terminal f "2" } }
 | 
			
		||||
       }
 | 
			
		||||
       f
 | 
			
		||||
     }
 | 
			
		||||
  } 
 | 
			
		||||
  }   
 | 
			
		||||
} [
 | 
			
		||||
  "digit = \"1\" | \"2\"" 'rule' parse parse-result-ast
 | 
			
		||||
  "digit = '1' '2'" 'rule' parse parse-result-ast
 | 
			
		||||
] unit-test
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
  T{ ebnf-rule f 
 | 
			
		||||
     "digit" 
 | 
			
		||||
     T{ ebnf-sequence f
 | 
			
		||||
        V{ T{ ebnf-terminal f "1" } T{ ebnf-terminal f "2" } }
 | 
			
		||||
  T{ ebnf-choice f
 | 
			
		||||
     V{ 
 | 
			
		||||
       T{ ebnf-sequence f
 | 
			
		||||
          V{ T{ ebnf-non-terminal f "one" } T{ ebnf-non-terminal f "two" } }
 | 
			
		||||
       }
 | 
			
		||||
       T{ ebnf-non-terminal f "three" }
 | 
			
		||||
     }
 | 
			
		||||
  } 
 | 
			
		||||
} [
 | 
			
		||||
  "digit = \"1\" \"2\"" 'rule' parse parse-result-ast
 | 
			
		||||
] unit-test
 | 
			
		||||
  "one two | three" 'choice' parse parse-result-ast
 | 
			
		||||
] unit-test
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
  T{ ebnf-sequence f
 | 
			
		||||
     V{ 
 | 
			
		||||
       T{ ebnf-non-terminal f "one" }
 | 
			
		||||
       T{ ebnf-choice f
 | 
			
		||||
          V{ T{ ebnf-non-terminal f "two" } T{ ebnf-non-terminal f "three" } }
 | 
			
		||||
       }
 | 
			
		||||
     }
 | 
			
		||||
  } 
 | 
			
		||||
} [
 | 
			
		||||
  "one (two | three)" 'choice' parse parse-result-ast
 | 
			
		||||
] unit-test
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
  T{ ebnf-sequence f
 | 
			
		||||
     V{ 
 | 
			
		||||
       T{ ebnf-non-terminal f "one" }
 | 
			
		||||
       T{ ebnf-repeat0 f
 | 
			
		||||
          T{ ebnf-sequence f
 | 
			
		||||
             V{
 | 
			
		||||
                T{ ebnf-choice f
 | 
			
		||||
                   V{ T{ ebnf-non-terminal f "two" } T{ ebnf-non-terminal f "three" } }
 | 
			
		||||
                }
 | 
			
		||||
                T{ ebnf-non-terminal f "four" }
 | 
			
		||||
             }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
     }
 | 
			
		||||
  } 
 | 
			
		||||
} [
 | 
			
		||||
  "one {(two | three) four}" 'choice' parse parse-result-ast
 | 
			
		||||
] unit-test
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
  T{ ebnf-sequence f
 | 
			
		||||
     V{ 
 | 
			
		||||
         T{ ebnf-non-terminal f "one" } 
 | 
			
		||||
         T{ ebnf-optional f T{ ebnf-non-terminal f "two" } }
 | 
			
		||||
         T{ ebnf-non-terminal f "three" }
 | 
			
		||||
     }
 | 
			
		||||
  } 
 | 
			
		||||
} [
 | 
			
		||||
  "one [ two ] three" 'choice' parse parse-result-ast
 | 
			
		||||
] unit-test
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
! Copyright (C) 2007 Chris Double.
 | 
			
		||||
! See http://factorcode.org/license.txt for BSD license.
 | 
			
		||||
USING: kernel parser words arrays strings math.parser sequences namespaces peg ;
 | 
			
		||||
USING: kernel parser words arrays strings math.parser sequences 
 | 
			
		||||
       quotations vectors namespaces math assocs continuations peg ;
 | 
			
		||||
IN: peg.ebnf
 | 
			
		||||
 | 
			
		||||
TUPLE: ebnf-non-terminal symbol ;
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +9,9 @@ TUPLE: ebnf-terminal symbol ;
 | 
			
		|||
TUPLE: ebnf-choice options ;
 | 
			
		||||
TUPLE: ebnf-sequence elements ;
 | 
			
		||||
TUPLE: ebnf-repeat0 group ;
 | 
			
		||||
TUPLE: ebnf-optional elements ;
 | 
			
		||||
TUPLE: ebnf-rule symbol elements ;
 | 
			
		||||
TUPLE: ebnf-action word ;
 | 
			
		||||
TUPLE: ebnf rules ;
 | 
			
		||||
 | 
			
		||||
C: <ebnf-non-terminal> ebnf-non-terminal
 | 
			
		||||
| 
						 | 
				
			
			@ -16,58 +19,82 @@ C: <ebnf-terminal> ebnf-terminal
 | 
			
		|||
C: <ebnf-choice> ebnf-choice
 | 
			
		||||
C: <ebnf-sequence> ebnf-sequence
 | 
			
		||||
C: <ebnf-repeat0> ebnf-repeat0
 | 
			
		||||
C: <ebnf-optional> ebnf-optional
 | 
			
		||||
C: <ebnf-rule> ebnf-rule
 | 
			
		||||
C: <ebnf-action> ebnf-action
 | 
			
		||||
C: <ebnf> ebnf
 | 
			
		||||
 | 
			
		||||
GENERIC: ebnf-compile ( ast -- quot )
 | 
			
		||||
SYMBOL: parsers
 | 
			
		||||
SYMBOL: non-terminals
 | 
			
		||||
SYMBOL: last-parser
 | 
			
		||||
 | 
			
		||||
M: ebnf-terminal ebnf-compile ( ast -- quot )
 | 
			
		||||
  [
 | 
			
		||||
    ebnf-terminal-symbol , \ token ,
 | 
			
		||||
  ] [ ] make ;
 | 
			
		||||
: reset-parser-generation ( -- ) 
 | 
			
		||||
  V{ } clone parsers set 
 | 
			
		||||
  H{ } clone non-terminals set 
 | 
			
		||||
  f last-parser set ;
 | 
			
		||||
 | 
			
		||||
M: ebnf-non-terminal ebnf-compile ( ast -- quot )
 | 
			
		||||
  [
 | 
			
		||||
    ebnf-non-terminal-symbol , \ in , \ get , \ lookup , \ execute ,
 | 
			
		||||
  ] [ ] make ;
 | 
			
		||||
: store-parser ( parser -- number )
 | 
			
		||||
  parsers get [ push ] keep length 1- ;
 | 
			
		||||
 | 
			
		||||
M: ebnf-choice ebnf-compile ( ast -- quot )
 | 
			
		||||
  [
 | 
			
		||||
    [
 | 
			
		||||
      ebnf-choice-options [
 | 
			
		||||
        ebnf-compile ,
 | 
			
		||||
      ] each
 | 
			
		||||
    ] { } make ,
 | 
			
		||||
    [ call ] , \ map , \ choice , 
 | 
			
		||||
  ] [ ] make ;
 | 
			
		||||
: get-parser ( index -- parser )
 | 
			
		||||
  parsers get nth ;
 | 
			
		||||
  
 | 
			
		||||
: non-terminal-index ( name -- number )
 | 
			
		||||
  dup non-terminals get at [
 | 
			
		||||
    nip
 | 
			
		||||
  ] [
 | 
			
		||||
    f store-parser [ swap non-terminals get set-at ] keep
 | 
			
		||||
  ] if* ;
 | 
			
		||||
 | 
			
		||||
M: ebnf-sequence ebnf-compile ( ast -- quot )
 | 
			
		||||
  [
 | 
			
		||||
    [
 | 
			
		||||
      ebnf-sequence-elements [
 | 
			
		||||
        ebnf-compile ,
 | 
			
		||||
      ] each
 | 
			
		||||
    ] { } make ,
 | 
			
		||||
    [ call ] , \ map , \ seq , 
 | 
			
		||||
  ] [ ] make ;
 | 
			
		||||
GENERIC: (generate-parser) ( ast -- id )
 | 
			
		||||
 | 
			
		||||
M: ebnf-repeat0 ebnf-compile ( ast -- quot )
 | 
			
		||||
  [
 | 
			
		||||
    ebnf-repeat0-group ebnf-compile % \ repeat0 , 
 | 
			
		||||
  ] [ ] make ;
 | 
			
		||||
: generate-parser ( ast -- id )
 | 
			
		||||
  (generate-parser) dup last-parser set ;
 | 
			
		||||
 | 
			
		||||
M: ebnf-rule ebnf-compile ( ast -- quot )
 | 
			
		||||
  [
 | 
			
		||||
    dup ebnf-rule-symbol , \ in , \ get , \ create , 
 | 
			
		||||
    ebnf-rule-elements ebnf-compile , \ define-compound , 
 | 
			
		||||
  ] [ ] make ;
 | 
			
		||||
M: ebnf-terminal (generate-parser) ( ast -- id )
 | 
			
		||||
  ebnf-terminal-symbol token sp store-parser ;
 | 
			
		||||
 | 
			
		||||
M: ebnf ebnf-compile ( ast -- quot )
 | 
			
		||||
M: ebnf-non-terminal (generate-parser) ( ast -- id )
 | 
			
		||||
  [
 | 
			
		||||
    ebnf-rules [
 | 
			
		||||
      ebnf-compile %
 | 
			
		||||
    ] each 
 | 
			
		||||
  ] [ ] make ;
 | 
			
		||||
    ebnf-non-terminal-symbol dup non-terminal-index , 
 | 
			
		||||
    parsers get , \ nth , [ search ] [ 2drop f ] recover , \ or ,
 | 
			
		||||
  ] [ ] make delay sp store-parser ;
 | 
			
		||||
 | 
			
		||||
M: ebnf-choice (generate-parser) ( ast -- id )
 | 
			
		||||
  ebnf-choice-options [
 | 
			
		||||
    generate-parser get-parser 
 | 
			
		||||
  ] map choice store-parser ;
 | 
			
		||||
 | 
			
		||||
M: ebnf-sequence (generate-parser) ( ast -- id )
 | 
			
		||||
  ebnf-sequence-elements [
 | 
			
		||||
    generate-parser get-parser
 | 
			
		||||
  ] map seq store-parser ;
 | 
			
		||||
 | 
			
		||||
M: ebnf-repeat0 (generate-parser) ( ast -- id )
 | 
			
		||||
  ebnf-repeat0-group generate-parser get-parser repeat0 store-parser ;
 | 
			
		||||
 | 
			
		||||
M: ebnf-optional (generate-parser) ( ast -- id )
 | 
			
		||||
  ebnf-optional-elements generate-parser get-parser optional store-parser ;
 | 
			
		||||
 | 
			
		||||
M: ebnf-rule (generate-parser) ( ast -- id )
 | 
			
		||||
  dup ebnf-rule-symbol non-terminal-index swap 
 | 
			
		||||
  ebnf-rule-elements generate-parser get-parser ! nt-id body
 | 
			
		||||
  swap [ parsers get set-nth ] keep ;
 | 
			
		||||
 | 
			
		||||
M: ebnf-action (generate-parser) ( ast -- id )
 | 
			
		||||
  ebnf-action-word search 1quotation 
 | 
			
		||||
  last-parser get get-parser swap action store-parser ;
 | 
			
		||||
 | 
			
		||||
M: vector (generate-parser) ( ast -- id )
 | 
			
		||||
  [ generate-parser ] map peek ;
 | 
			
		||||
 | 
			
		||||
M: f (generate-parser) ( ast -- id )
 | 
			
		||||
  drop last-parser get ;
 | 
			
		||||
 | 
			
		||||
M: ebnf (generate-parser) ( ast -- id )
 | 
			
		||||
  ebnf-rules [
 | 
			
		||||
    generate-parser 
 | 
			
		||||
  ] map peek ;
 | 
			
		||||
 | 
			
		||||
DEFER: 'rhs'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -75,32 +102,55 @@ DEFER: 'rhs'
 | 
			
		|||
  CHAR: a CHAR: z range repeat1 [ >string <ebnf-non-terminal> ] action ;
 | 
			
		||||
 | 
			
		||||
: 'terminal' ( -- parser )
 | 
			
		||||
  "\"" token hide [ CHAR: " = not ] satisfy repeat1 "\"" token hide 3array seq [ first >string <ebnf-terminal> ] action ;
 | 
			
		||||
  "'" token hide [ CHAR: ' = not ] satisfy repeat1 "'" token hide 3array seq [ first >string <ebnf-terminal> ] action ;
 | 
			
		||||
 | 
			
		||||
: 'element' ( -- parser )
 | 
			
		||||
  'non-terminal' 'terminal' 2array choice ;
 | 
			
		||||
 | 
			
		||||
: 'sequence' ( -- parser )
 | 
			
		||||
  'element' sp 
 | 
			
		||||
  "|" token sp ensure-not 2array seq [ first ] action 
 | 
			
		||||
   repeat1 [ <ebnf-sequence> ] action ;
 | 
			
		||||
  
 | 
			
		||||
: 'choice' ( -- parser )
 | 
			
		||||
  'element' sp "|" token sp list-of [ <ebnf-choice> ] action ;
 | 
			
		||||
DEFER: 'choice'
 | 
			
		||||
 | 
			
		||||
: 'group' ( -- parser )
 | 
			
		||||
  "(" token sp hide
 | 
			
		||||
  [ 'choice' sp ] delay
 | 
			
		||||
  ")" token sp hide 
 | 
			
		||||
  3array seq [ first ] action ;
 | 
			
		||||
 | 
			
		||||
: 'repeat0' ( -- parser )
 | 
			
		||||
  "{" token sp hide
 | 
			
		||||
  [ 'rhs' sp ] delay
 | 
			
		||||
  [ 'choice' sp ] delay
 | 
			
		||||
  "}" token sp hide 
 | 
			
		||||
  3array seq [ first <ebnf-repeat0> ] action ;
 | 
			
		||||
 | 
			
		||||
: 'rhs' ( -- parser )
 | 
			
		||||
  'repeat0'
 | 
			
		||||
  'sequence'
 | 
			
		||||
  'choice'
 | 
			
		||||
  'element' 
 | 
			
		||||
  4array choice ;
 | 
			
		||||
: 'optional' ( -- parser )
 | 
			
		||||
  "[" token sp hide
 | 
			
		||||
  [ 'choice' sp ] delay
 | 
			
		||||
  "]" token sp hide 
 | 
			
		||||
  3array seq [ first <ebnf-optional> ] action ;
 | 
			
		||||
 | 
			
		||||
: 'sequence' ( -- parser )
 | 
			
		||||
  [ 
 | 
			
		||||
    'element' sp ,
 | 
			
		||||
    'group' sp , 
 | 
			
		||||
    'repeat0' sp ,
 | 
			
		||||
    'optional' sp , 
 | 
			
		||||
   ] { } make  choice  
 | 
			
		||||
   repeat1 [ 
 | 
			
		||||
     dup length 1 = [ first ] [ <ebnf-sequence> ] if
 | 
			
		||||
   ] action ;  
 | 
			
		||||
 | 
			
		||||
: 'choice' ( -- parser )
 | 
			
		||||
  'sequence' sp "|" token sp list-of [ 
 | 
			
		||||
    dup length 1 = [ first ] [ <ebnf-choice> ] if
 | 
			
		||||
   ] action ;
 | 
			
		||||
 | 
			
		||||
: 'action' ( -- parser )
 | 
			
		||||
  "=>" token hide
 | 
			
		||||
  [ blank? ] satisfy ensure-not [ drop t ] satisfy 2array seq [ first ] action repeat1 [ >string ] action sp
 | 
			
		||||
  2array seq [ first <ebnf-action> ] action ;
 | 
			
		||||
  
 | 
			
		||||
: 'rhs' ( -- parser )
 | 
			
		||||
  'choice' 'action' sp optional 2array seq ;
 | 
			
		||||
 
 | 
			
		||||
: 'rule' ( -- parser )
 | 
			
		||||
  'non-terminal' [ ebnf-non-terminal-symbol ] action 
 | 
			
		||||
  "=" token sp hide 
 | 
			
		||||
| 
						 | 
				
			
			@ -112,9 +162,23 @@ DEFER: 'rhs'
 | 
			
		|||
 | 
			
		||||
: ebnf>quot ( string -- quot )
 | 
			
		||||
  'ebnf' parse [
 | 
			
		||||
     parse-result-ast ebnf-compile  
 | 
			
		||||
     parse-result-ast [
 | 
			
		||||
         reset-parser-generation
 | 
			
		||||
         generate-parser drop
 | 
			
		||||
         [
 | 
			
		||||
             non-terminals get
 | 
			
		||||
             [
 | 
			
		||||
               get-parser [
 | 
			
		||||
                 swap , \ in , \ get , \ create ,
 | 
			
		||||
                 1quotation , \ define-compound , 
 | 
			
		||||
               ] [
 | 
			
		||||
                 drop
 | 
			
		||||
               ] if*
 | 
			
		||||
             ] assoc-each
 | 
			
		||||
         ] [ ] make
 | 
			
		||||
     ] with-scope
 | 
			
		||||
   ] [
 | 
			
		||||
    f
 | 
			
		||||
   ] if* ;
 | 
			
		||||
 | 
			
		||||
: <EBNF "EBNF>" parse-tokens "" join ebnf>quot call ; parsing
 | 
			
		||||
: <EBNF "EBNF>" parse-tokens " " join ebnf>quot call ; parsing
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +1,16 @@
 | 
			
		|||
! Copyright (C) 2007 Chris Double.
 | 
			
		||||
! See http://factorcode.org/license.txt for BSD license.
 | 
			
		||||
USING: kernel sequences strings namespaces math assocs shuffle vectors combinators.lib ;
 | 
			
		||||
USING: kernel sequences strings namespaces math assocs shuffle 
 | 
			
		||||
       vectors arrays combinators.lib ;
 | 
			
		||||
IN: peg
 | 
			
		||||
 | 
			
		||||
TUPLE: parse-result remaining ast ;
 | 
			
		||||
 | 
			
		||||
GENERIC: parse ( state parser -- result )
 | 
			
		||||
GENERIC: (parse) ( state parser -- result )
 | 
			
		||||
 | 
			
		||||
<PRIVATE
 | 
			
		||||
 | 
			
		||||
SYMBOL: packrat-cache
 | 
			
		||||
SYMBOL: ignore 
 | 
			
		||||
 | 
			
		||||
: <parse-result> ( remaining ast -- parse-result )
 | 
			
		||||
| 
						 | 
				
			
			@ -24,18 +26,48 @@ TUPLE: parser id ;
 | 
			
		|||
: init-parser ( parser -- parser )
 | 
			
		||||
  get-next-id parser construct-boa over set-delegate ;
 | 
			
		||||
 | 
			
		||||
: from ( slice-or-string -- index )
 | 
			
		||||
  dup slice? [ slice-from ] [ drop 0 ] if ;
 | 
			
		||||
 | 
			
		||||
: get-cached ( input parser -- result )
 | 
			
		||||
  [ from ] dip parser-id packrat-cache get at at ;
 | 
			
		||||
 | 
			
		||||
: put-cached ( result input parser -- )
 | 
			
		||||
  parser-id dup packrat-cache get at [ 
 | 
			
		||||
    nip
 | 
			
		||||
  ] [ 
 | 
			
		||||
    H{ } clone dup >r swap packrat-cache get set-at r>
 | 
			
		||||
  ] if* 
 | 
			
		||||
  [ from ] dip set-at ;
 | 
			
		||||
 | 
			
		||||
PRIVATE>
 | 
			
		||||
 | 
			
		||||
: parse ( input parser -- result )
 | 
			
		||||
  packrat-cache get [
 | 
			
		||||
    2dup get-cached [
 | 
			
		||||
      [ (parse) dup ] 2keep put-cached
 | 
			
		||||
    ] unless* 
 | 
			
		||||
  ] [
 | 
			
		||||
    (parse)
 | 
			
		||||
  ] if ;
 | 
			
		||||
 | 
			
		||||
: packrat-parse ( input parser -- result )
 | 
			
		||||
  H{ } clone packrat-cache [ parse ] with-variable ;
 | 
			
		||||
 | 
			
		||||
<PRIVATE
 | 
			
		||||
 | 
			
		||||
TUPLE: token-parser symbol ;
 | 
			
		||||
 | 
			
		||||
M: token-parser parse ( state parser -- result )
 | 
			
		||||
M: token-parser (parse) ( input parser -- result )
 | 
			
		||||
  token-parser-symbol 2dup head? [
 | 
			
		||||
    dup >r length tail-slice r> <parse-result>
 | 
			
		||||
  ] [
 | 
			
		||||
    2drop f
 | 
			
		||||
  ] if ;
 | 
			
		||||
 | 
			
		||||
   
 | 
			
		||||
TUPLE: satisfy-parser quot ;
 | 
			
		||||
 | 
			
		||||
M: satisfy-parser parse ( state parser -- result )
 | 
			
		||||
M: satisfy-parser (parse) ( state parser -- result )
 | 
			
		||||
  over empty? [
 | 
			
		||||
    2drop f 
 | 
			
		||||
  ] [
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +80,7 @@ M: satisfy-parser parse ( state parser -- result )
 | 
			
		|||
 | 
			
		||||
TUPLE: range-parser min max ;
 | 
			
		||||
 | 
			
		||||
M: range-parser parse ( state parser -- result )
 | 
			
		||||
M: range-parser (parse) ( state parser -- result )
 | 
			
		||||
  over empty? [
 | 
			
		||||
    2drop f
 | 
			
		||||
  ] [
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +109,7 @@ TUPLE: seq-parser parsers ;
 | 
			
		|||
    drop   
 | 
			
		||||
  ] if ;
 | 
			
		||||
 | 
			
		||||
M: seq-parser parse ( state parser -- result )
 | 
			
		||||
M: seq-parser (parse) ( state parser -- result )
 | 
			
		||||
  seq-parser-parsers [ V{ } clone <parse-result> ] dip  (seq-parser) ;
 | 
			
		||||
 | 
			
		||||
TUPLE: choice-parser parsers ;
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +125,7 @@ TUPLE: choice-parser parsers ;
 | 
			
		|||
    ] if* 
 | 
			
		||||
  ] if ;
 | 
			
		||||
 | 
			
		||||
M: choice-parser parse ( state parser -- result )
 | 
			
		||||
M: choice-parser (parse) ( state parser -- result )
 | 
			
		||||
  choice-parser-parsers (choice-parser) ;
 | 
			
		||||
 | 
			
		||||
TUPLE: repeat0-parser p1 ;
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +143,7 @@ TUPLE: repeat0-parser p1 ;
 | 
			
		|||
  { parse-result-remaining parse-result-ast }
 | 
			
		||||
  get-slots 1vector  <parse-result> ;
 | 
			
		||||
 | 
			
		||||
M: repeat0-parser parse ( state parser -- result )
 | 
			
		||||
M: repeat0-parser (parse) ( state parser -- result )
 | 
			
		||||
     repeat0-parser-p1 2dup parse [ 
 | 
			
		||||
       nipd clone-result (repeat-parser) 
 | 
			
		||||
     ] [ 
 | 
			
		||||
| 
						 | 
				
			
			@ -120,17 +152,17 @@ M: repeat0-parser parse ( state parser -- result )
 | 
			
		|||
 | 
			
		||||
TUPLE: repeat1-parser p1 ;
 | 
			
		||||
 | 
			
		||||
M: repeat1-parser parse ( state parser -- result )
 | 
			
		||||
M: repeat1-parser (parse) ( state parser -- result )
 | 
			
		||||
   repeat1-parser-p1 tuck parse dup [ clone-result (repeat-parser) ] [ nip ] if ;
 | 
			
		||||
 | 
			
		||||
TUPLE: optional-parser p1 ;
 | 
			
		||||
 | 
			
		||||
M: optional-parser parse ( state parser -- result )
 | 
			
		||||
M: optional-parser (parse) ( state parser -- result )
 | 
			
		||||
   dupd optional-parser-p1 parse swap f <parse-result> or ;
 | 
			
		||||
 | 
			
		||||
TUPLE: ensure-parser p1 ;
 | 
			
		||||
 | 
			
		||||
M: ensure-parser parse ( state parser -- result )
 | 
			
		||||
M: ensure-parser (parse) ( state parser -- result )
 | 
			
		||||
   dupd ensure-parser-p1 parse [
 | 
			
		||||
     ignore <parse-result>  
 | 
			
		||||
   ] [
 | 
			
		||||
| 
						 | 
				
			
			@ -139,7 +171,7 @@ M: ensure-parser parse ( state parser -- result )
 | 
			
		|||
 | 
			
		||||
TUPLE: ensure-not-parser p1 ;
 | 
			
		||||
 | 
			
		||||
M: ensure-not-parser parse ( state parser -- result )
 | 
			
		||||
M: ensure-not-parser (parse) ( state parser -- result )
 | 
			
		||||
   dupd ensure-not-parser-p1 parse [
 | 
			
		||||
     drop f
 | 
			
		||||
   ] [
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +180,7 @@ M: ensure-not-parser parse ( state parser -- result )
 | 
			
		|||
 | 
			
		||||
TUPLE: action-parser p1 quot ;
 | 
			
		||||
 | 
			
		||||
M: action-parser parse ( state parser -- result )
 | 
			
		||||
M: action-parser (parse) ( state parser -- result )
 | 
			
		||||
   tuck action-parser-p1 parse dup [ 
 | 
			
		||||
     dup parse-result-ast rot action-parser-quot call
 | 
			
		||||
     swap [ set-parse-result-ast ] keep
 | 
			
		||||
| 
						 | 
				
			
			@ -165,12 +197,12 @@ M: action-parser parse ( state parser -- result )
 | 
			
		|||
 | 
			
		||||
TUPLE: sp-parser p1 ;
 | 
			
		||||
 | 
			
		||||
M: sp-parser parse ( state parser -- result )
 | 
			
		||||
M: sp-parser (parse) ( state parser -- result )
 | 
			
		||||
  [ left-trim-slice ] dip sp-parser-p1 parse ;
 | 
			
		||||
 | 
			
		||||
TUPLE: delay-parser quot ;
 | 
			
		||||
 | 
			
		||||
M: delay-parser parse ( state parser -- result )
 | 
			
		||||
M: delay-parser (parse) ( state parser -- result )
 | 
			
		||||
  delay-parser-quot call parse ;
 | 
			
		||||
 | 
			
		||||
PRIVATE>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,9 +5,9 @@ USING: kernel tools.test peg peg.pl0 ;
 | 
			
		|||
IN: temporary
 | 
			
		||||
 | 
			
		||||
{ "abc" } [
 | 
			
		||||
  "abc" 'ident' parse parse-result-ast 
 | 
			
		||||
  "abc" ident parse parse-result-ast 
 | 
			
		||||
] unit-test
 | 
			
		||||
 | 
			
		||||
{ 55 } [
 | 
			
		||||
  "55abc" 'number' parse parse-result-ast 
 | 
			
		||||
  "55abc" number parse parse-result-ast 
 | 
			
		||||
] unit-test
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,58 +1,29 @@
 | 
			
		|||
! Copyright (C) 2007 Chris Double.
 | 
			
		||||
! See http://factorcode.org/license.txt for BSD license.
 | 
			
		||||
USING: kernel arrays strings math.parser sequences peg ;
 | 
			
		||||
USING: kernel arrays strings math.parser sequences peg peg.ebnf ;
 | 
			
		||||
IN: peg.pl0
 | 
			
		||||
 | 
			
		||||
#! Grammar for PL/0 based on http://en.wikipedia.org/wiki/PL/0
 | 
			
		||||
 | 
			
		||||
: 'ident' ( -- parser )
 | 
			
		||||
: ident ( -- parser )
 | 
			
		||||
  CHAR: a CHAR: z range 
 | 
			
		||||
  CHAR: A CHAR: Z range 2array choice repeat1 
 | 
			
		||||
  [ >string ] action ;
 | 
			
		||||
 | 
			
		||||
: 'number' ( -- parser )
 | 
			
		||||
: number ( -- parser )
 | 
			
		||||
  CHAR: 0 CHAR: 9 range repeat1 [ string>number ] action ;
 | 
			
		||||
 | 
			
		||||
DEFER: 'factor'
 | 
			
		||||
 | 
			
		||||
: 'term' ( -- parser )
 | 
			
		||||
  'factor' "*" token "/" token 2array choice sp 'factor' sp 2array seq repeat0 2array seq ;
 | 
			
		||||
 | 
			
		||||
: 'expression' ( -- parser )
 | 
			
		||||
  [ "+" token "-" token 2array choice sp optional 'term' sp 2dup 2array seq repeat0 3array seq ] delay ;
 | 
			
		||||
 | 
			
		||||
: 'factor' ( -- parser )
 | 
			
		||||
  'ident' 'number' "(" token hide 'expression' sp ")" token sp hide 3array seq 3array choice ;
 | 
			
		||||
 | 
			
		||||
: 'condition' ( -- parser )
 | 
			
		||||
  "odd" token 'expression' sp 2array seq
 | 
			
		||||
  'expression' { "=" "#" "<=" "<" ">=" ">" } [ token ] map choice sp 'expression' sp 3array seq 
 | 
			
		||||
  2array choice ;
 | 
			
		||||
 | 
			
		||||
: 'statement' ( -- parser )
 | 
			
		||||
  [
 | 
			
		||||
    'ident' ":=" token sp 'expression' sp 3array seq
 | 
			
		||||
    "call" token 'ident' sp 2array seq
 | 
			
		||||
    "begin" token 'statement' sp ";" token sp 'statement' sp 2array seq repeat0 "end" token sp 4array seq
 | 
			
		||||
     "if" token 'condition' sp "then" token sp 'statement' sp 4array seq
 | 
			
		||||
     4array choice
 | 
			
		||||
     "while" token 'condition' sp "do" token sp 'statement' sp 4array seq
 | 
			
		||||
     2array choice optional
 | 
			
		||||
  ] delay ;
 | 
			
		||||
 | 
			
		||||
: 'block' ( -- parser )
 | 
			
		||||
 [
 | 
			
		||||
  "const" token 'ident' sp "=" token sp 'number' sp 4array seq 
 | 
			
		||||
    "," token sp 'ident' sp "=" token sp 'number' sp 4array seq repeat0
 | 
			
		||||
  ";" token sp 3array seq optional
 | 
			
		||||
  
 | 
			
		||||
  "var" token 'ident' sp "," token sp 'ident' sp 2array seq repeat0 
 | 
			
		||||
  ";" token sp 4array seq optional
 | 
			
		||||
 | 
			
		||||
  "procedure" token 'ident' sp ";" token sp 'block' sp 4array seq ";" token sp 2array seq repeat0 'statement' sp 2array seq  
 | 
			
		||||
 | 
			
		||||
  3array seq
 | 
			
		||||
 ] delay ;
 | 
			
		||||
 | 
			
		||||
: 'program' ( -- parser )
 | 
			
		||||
  'block' "." token sp 2array seq ;
 | 
			
		||||
<EBNF
 | 
			
		||||
program = block '.' .
 | 
			
		||||
block = [ 'const' ident '=' number { ',' ident '=' number } ';' ]
 | 
			
		||||
        [ 'var' ident { ',' ident } ';' ]
 | 
			
		||||
        { 'procedure' ident ';' [ block ';' ] } statement .
 | 
			
		||||
statement = [ ident ':=' expression | 'call' ident |
 | 
			
		||||
              'begin' statement {';' statement } 'end' |
 | 
			
		||||
              'if' condition 'then' statement |
 | 
			
		||||
              'while' condition 'do' statement ] .
 | 
			
		||||
condition = 'odd' expression |
 | 
			
		||||
            expression ('=' | '#' | '<=' | '<' | '>=' | '>') expression .
 | 
			
		||||
expression = ['+' | '-'] term {('+' | '-') term } .
 | 
			
		||||
term = factor {('*' | '/') factor } .
 | 
			
		||||
factor = ident | number | '(' expression ')'
 | 
			
		||||
EBNF>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue