factor/basis/state-parser/state-parser.factor

159 lines
4.5 KiB
Factor
Raw Normal View History

2007-09-20 18:09:08 -04:00
! Copyright (C) 2005, 2006 Daniel Ehrenberg
! See http://factorcode.org/license.txt for BSD license.
USING: io io.streams.string kernel math namespaces sequences
2008-07-02 01:20:01 -04:00
strings circular prettyprint debugger ascii sbufs fry summary
2008-05-02 18:11:51 -04:00
accessors sequences.lib ;
2007-09-20 18:09:08 -04:00
IN: state-parser
! * Basic underlying words
! Code stored in stdio
! Spot is composite so it won't be lost in sub-scopes
TUPLE: spot char line column next ;
C: <spot> spot
2008-05-02 18:11:51 -04:00
: get-char ( -- char ) spot get char>> ;
: set-char ( char -- ) spot get swap >>char drop ;
: get-line ( -- line ) spot get line>> ;
: set-line ( line -- ) spot get swap >>line drop ;
: get-column ( -- column ) spot get column>> ;
: set-column ( column -- ) spot get swap >>column drop ;
: get-next ( -- char ) spot get next>> ;
: set-next ( char -- ) spot get swap >>next drop ;
2007-09-20 18:09:08 -04:00
! * Errors
TUPLE: parsing-error line column ;
2008-05-02 18:11:51 -04:00
: parsing-error ( class -- obj )
new
get-line >>line
get-column >>column ;
M: parsing-error summary ( obj -- str )
[
"Parsing error" print
"Line: " write dup line>> .
"Column: " write column>> .
] with-string-writer ;
TUPLE: expected < parsing-error should-be was ;
: expected ( should-be was -- * )
\ expected parsing-error
swap >>was
swap >>should-be throw ;
M: expected summary ( obj -- str )
[
dup call-next-method write
"Token expected: " write dup should-be>> print
"Token present: " write was>> print
] with-string-writer ;
TUPLE: unexpected-end < parsing-error ;
: unexpected-end ( -- * ) \ unexpected-end parsing-error throw ;
2008-05-02 18:11:51 -04:00
M: unexpected-end summary ( obj -- str )
[
call-next-method write
"File unexpectedly ended." print
] with-string-writer ;
TUPLE: missing-close < parsing-error ;
: missing-close ( -- * ) \ missing-close parsing-error throw ;
2008-05-02 18:11:51 -04:00
M: missing-close summary ( obj -- str )
[
call-next-method write
"Missing closing token." print
] with-string-writer ;
2007-09-20 18:09:08 -04:00
SYMBOL: prolog-data
! * Basic utility words
: record ( char -- )
CHAR: \n =
[ 0 get-line 1+ set-line ] [ get-column 1+ ] if
set-column ;
2008-05-02 18:11:51 -04:00
! (next) normalizes \r\n and \r
: (next) ( -- char )
2007-09-20 18:09:08 -04:00
get-next read1
2dup swap CHAR: \r = [
CHAR: \n =
[ nip read1 ] [ nip CHAR: \n swap ] if
] [ drop ] if
set-next dup set-char ;
: next ( -- )
#! Increment spot.
2008-05-02 18:11:51 -04:00
get-char [ unexpected-end ] unless (next) record ;
2007-09-20 18:09:08 -04:00
: next* ( -- )
get-char [ (next) record ] when ;
2008-08-28 23:28:34 -04:00
: skip-until ( quot: ( -- ? ) -- )
2007-09-20 18:09:08 -04:00
get-char [
[ call ] keep swap [ drop ] [
next skip-until
] if
2008-08-27 18:02:54 -04:00
] [ drop ] if ; inline recursive
2007-09-20 18:09:08 -04:00
: take-until ( quot -- string )
#! Take the substring of a string starting at spot
#! from code until the quotation given is true and
#! advance spot to after the substring.
2008-05-02 18:11:51 -04:00
10 <sbuf> [
'[ @ [ t ] [ get-char , push f ] if ] skip-until
] keep >string ; inline
2007-09-20 18:09:08 -04:00
2008-04-26 19:44:28 -04:00
: take-rest ( -- string )
2007-09-20 18:09:08 -04:00
[ f ] take-until ;
: take-char ( ch -- string )
[ dup get-char = ] take-until nip ;
2008-05-02 18:11:51 -04:00
TUPLE: not-enough-characters < parsing-error ;
: not-enough-characters ( -- * )
2008-05-02 18:11:51 -04:00
\ not-enough-characters parsing-error throw ;
M: not-enough-characters summary ( obj -- str )
[
call-next-method write
"Not enough characters" print
] with-string-writer ;
: take ( n -- string )
[ 1- ] [ <sbuf> ] bi [
'[ drop get-char [ next , push f ] [ t ] if* ] attempt-each drop
] keep get-char [ over push ] when* >string ;
2007-09-20 18:09:08 -04:00
: pass-blank ( -- )
#! Advance code past any whitespace, including newlines
[ get-char blank? not ] skip-until ;
: string-matches? ( string circular -- ? )
get-char over push-circular
sequence= ;
: take-string ( match -- string )
dup length <circular-string>
[ 2dup string-matches? ] take-until nip
dup length rot length 1- - head
2008-05-02 18:11:51 -04:00
get-char [ missing-close ] unless next ;
2007-09-20 18:09:08 -04:00
: expect ( ch -- )
get-char 2dup = [ 2drop ] [
2008-05-02 18:11:51 -04:00
>r 1string r> 1string expected
2007-09-20 18:09:08 -04:00
] if next ;
: expect-string ( string -- )
dup [ get-char next ] replicate 2dup =
2008-05-02 18:11:51 -04:00
[ 2drop ] [ expected ] if ;
2007-09-20 18:09:08 -04:00
: init-parser ( -- )
0 1 0 f <spot> spot set
read1 set-next next ;
: state-parse ( stream quot -- )
! with-input-stream implicitly creates a new scope which we use
swap [ init-parser call ] with-input-stream ; inline
2007-09-20 18:09:08 -04:00
: string-parse ( input quot -- )
>r <string-reader> r> state-parse ; inline