| 
									
										
										
										
											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 ;
 | 
					
						
							| 
									
										
										
										
											2008-06-09 03:14:14 -04:00
										 |  |  | : 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 ;
 | 
					
						
							| 
									
										
										
										
											2008-06-09 03:14:14 -04:00
										 |  |  | : 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 ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : skip-until ( quot -- )
 | 
					
						
							|  |  |  |     #! quot: ( -- ? ) | 
					
						
							|  |  |  |     get-char [ | 
					
						
							|  |  |  |         [ call ] keep swap [ drop ] [ | 
					
						
							|  |  |  |             next skip-until | 
					
						
							|  |  |  |         ] if
 | 
					
						
							|  |  |  |     ] [ drop ] if ; inline
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : 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 ;
 | 
					
						
							| 
									
										
										
										
											2008-06-09 03:14:14 -04:00
										 |  |  | : 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 -- )
 | 
					
						
							| 
									
										
										
										
											2008-06-13 02:51:46 -04:00
										 |  |  |     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 -- )
 | 
					
						
							| 
									
										
										
										
											2008-05-05 03:19:25 -04:00
										 |  |  |     ! 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
 |