1 ! Copyright (C) 2008, 2010 Slava Pestov, Joe Groff.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: kernel sequences accessors namespaces math words strings
4 io vectors arrays math.parser combinators continuations
11 { line-text maybe{ string } }
12 { line-length fixnum }
14 { parsing-words vector } ;
16 TUPLE: lexer-parsing-word word line line-text column ;
18 : next-line ( lexer -- )
19 dup [ line>> ] [ text>> ] bi ?nth
20 [ >>line-text ] [ length >>line-length ] bi
25 : push-parsing-word ( word -- )
26 lexer-parsing-word new
30 [ line-text>> >>line-text ]
31 [ column>> >>column ] tri
32 ] [ parsing-words>> push ] bi ;
34 : pop-parsing-word ( -- )
35 lexer get parsing-words>> pop* ;
37 : new-lexer ( text class -- lexer )
41 V{ } clone >>parsing-words
42 dup next-line ; inline
44 : <lexer> ( text -- lexer )
47 ERROR: unexpected want got ;
49 : forbid-tab ( c -- c )
50 [ CHAR: \t eq? [ "[space]" "[tab]" unexpected ] when ] keep ; inline
52 : skip ( i seq ? -- n )
54 [ [ swap forbid-tab CHAR: \s eq? xor ] curry find-from drop ] dip or ;
56 : change-lexer-column ( lexer quot -- )
57 [ [ column>> ] [ line-text>> ] bi ] prepose keep
60 GENERIC: skip-blank ( lexer -- )
62 M: lexer skip-blank ( lexer -- )
63 [ t skip ] change-lexer-column ;
65 GENERIC: skip-word ( lexer -- )
69 : quote? ( column text -- ? )
70 nth CHAR: " eq? ; inline
72 : shebang? ( column text -- ? )
73 swap zero? [ "#!" head? ] [ drop f ] if ; inline
77 M: lexer skip-word ( lexer -- )
80 { [ 2dup quote? ] [ drop 1 + ] }
81 { [ 2dup shebang? ] [ drop 2 + ] }
84 ] change-lexer-column ;
86 : still-parsing? ( lexer -- ? )
87 [ line>> ] [ text>> length ] bi <= ;
89 : still-parsing-line? ( lexer -- ? )
90 [ column>> ] [ line-length>> ] bi < ;
92 : (parse-token) ( lexer -- str )
100 : parse-token ( lexer -- str/f )
103 dup still-parsing-line?
104 [ (parse-token) ] [ dup next-line parse-token ] if
107 : (scan-token) ( -- str/f ) lexer get parse-token ;
109 PREDICATE: unexpected-eof < unexpected got>> not ;
111 : unexpected-eof ( word -- * ) f unexpected ;
113 : scan-token ( -- str ) (scan-token) [ "token" unexpected-eof ] unless* ;
115 : expect ( token -- )
116 scan-token 2dup = [ 2drop ] [ unexpected ] if ;
118 : each-token ( ... end quot: ( ... token -- ... ) -- ... )
119 [ scan-token ] 2dip 2over =
120 [ 3drop ] [ [ nip call ] [ each-token ] 2bi ] if ; inline recursive
122 : map-tokens ( ... end quot: ( ... token -- ... elt ) -- ... seq )
123 collector [ each-token ] dip { } like ; inline
125 : parse-tokens ( end -- seq )
128 TUPLE: lexer-error line column line-text parsing-words error ;
130 M: lexer-error error-file error>> error-file ;
132 M: lexer-error error-line [ error>> error-line ] [ line>> ] bi or ;
134 : <lexer-error> ( msg -- error )
138 [ column>> >>column ] bi
140 [ line-text>> >>line-text ]
141 [ parsing-words>> clone >>parsing-words ] bi
145 : simple-lexer-dump ( error -- )
146 [ line>> number>string ": " append ]
147 [ line-text>> dup string? [ drop "" ] unless ]
148 [ column>> 0 or ] tri
149 pick length + CHAR: \s <string>
150 [ write ] [ print ] [ write "^" print ] tri* ;
152 : (parsing-word-lexer-dump) ( error parsing-word -- )
155 over line>> number>string length
158 ] [ line-text>> dup string? [ drop "" ] unless print ] bi
161 : parsing-word-lexer-dump ( error parsing-word -- )
162 2dup [ line>> ] same?
163 [ drop simple-lexer-dump ]
164 [ (parsing-word-lexer-dump) ] if ;
166 : lexer-dump ( error -- )
168 [ simple-lexer-dump ]
169 [ last parsing-word-lexer-dump ] if-empty ;
171 : with-lexer ( lexer quot -- newquot )
172 [ lexer set ] dip [ <lexer-error> rethrow ] recover ; inline