1 ! Copyright (C) 2008, 2010 Slava Pestov, Joe Groff.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays combinators continuations io kernel
4 kernel.private math math.parser namespaces sequences
5 sequences.private source-files.errors strings vectors ;
12 { line-length fixnum }
14 { parsing-words vector } ;
16 TUPLE: lexer-parsing-word word line line-text column ;
18 ERROR: not-a-lexer object ;
20 : check-lexer ( lexer -- lexer )
21 dup lexer? [ not-a-lexer ] unless ; inline
23 : next-line ( lexer -- )
25 dup [ line>> ] [ text>> ] bi ?nth "" or
26 [ >>line-text ] [ length >>line-length ] bi
31 : push-parsing-word ( word -- )
32 lexer get check-lexer [
33 [ line>> ] [ line-text>> ] [ column>> ] tri
34 lexer-parsing-word boa
35 ] [ parsing-words>> push ] bi ;
37 : pop-parsing-word ( -- )
38 lexer get check-lexer parsing-words>> pop* ;
40 : new-lexer ( text class -- lexer )
44 V{ } clone >>parsing-words
45 dup next-line ; inline
47 : <lexer> ( text -- lexer )
50 ERROR: unexpected want got ;
52 : forbid-tab ( c -- c )
53 [ CHAR: \t eq? [ "[space]" "[tab]" unexpected ] when ] keep ; inline
55 : skip ( i seq ? -- n )
57 [ swap forbid-tab CHAR: \s eq? xor ] curry find-from drop
60 : change-lexer-column ( ..a lexer quot: ( ..a col line -- ..b newcol ) -- ..b )
61 [ check-lexer [ column>> ] [ line-text>> ] bi ] prepose
62 keep column<< ; inline
64 GENERIC: skip-blank ( lexer -- )
68 : shebang? ( lexer -- lexer ? )
71 dup line-text>> "#!" head?
79 [ nip length ] change-lexer-column
81 [ t skip ] change-lexer-column
84 GENERIC: skip-word ( lexer -- )
88 2dup nth CHAR: \" eq? [ drop 1 + ] [ f skip ] if
89 ] change-lexer-column ;
91 : still-parsing? ( lexer -- ? )
92 check-lexer [ line>> ] [ text>> length ] bi <= ;
94 : still-parsing-line? ( lexer -- ? )
95 check-lexer [ column>> ] [ line-length>> ] bi < ;
97 : (parse-raw) ( lexer -- str )
105 : parse-raw ( lexer -- str/f )
108 dup still-parsing-line?
109 [ (parse-raw) ] [ dup next-line parse-raw ] if
114 : skip-comments ( lexer str -- str' )
116 drop [ next-line ] keep parse-token
121 : parse-token ( lexer -- str/f )
122 dup parse-raw [ skip-comments ] [ drop f ] if* ;
124 : ?scan-token ( -- str/f ) lexer get parse-token ;
126 PREDICATE: unexpected-eof < unexpected got>> not ;
128 : throw-unexpected-eof ( word -- * ) f unexpected ;
130 : scan-token ( -- str )
131 ?scan-token [ "token" throw-unexpected-eof ] unless* ;
133 : expect ( token -- )
134 scan-token 2dup = [ 2drop ] [ unexpected ] if ;
136 : each-token ( ... end quot: ( ... token -- ... ) -- ... )
137 [ scan-token ] 2dip 2over =
138 [ 3drop ] [ [ nip call ] [ each-token ] 2bi ] if ; inline recursive
140 : map-tokens ( ... end quot: ( ... token -- ... elt ) -- ... seq )
141 collector [ each-token ] dip { } like ; inline
143 : parse-tokens ( end -- seq )
146 TUPLE: lexer-error line column line-text parsing-words error ;
148 M: lexer-error error-file error>> error-file ;
150 M: lexer-error error-line [ error>> error-line ] [ line>> ] bi or ;
152 : <lexer-error> ( msg -- error )
158 [ parsing-words>> clone ]
160 ] dip lexer-error boa ;
162 : simple-lexer-dump ( error -- )
163 [ line>> number>string ": " append ]
166 pick length + CHAR: \s <string>
167 [ write ] [ print ] [ write "^" print ] tri* ;
169 : (parsing-word-lexer-dump) ( error parsing-word -- )
172 over line>> number>string length
175 ] [ line-text>> print ] bi
178 : parsing-word-lexer-dump ( error parsing-word -- )
179 2dup [ line>> ] same?
180 [ drop simple-lexer-dump ]
181 [ (parsing-word-lexer-dump) ] if ;
183 : lexer-dump ( error -- )
185 [ simple-lexer-dump ]
186 [ last parsing-word-lexer-dump ] if-empty ;
188 : with-lexer ( lexer quot -- newquot )
189 [ [ <lexer-error> rethrow ] recover ] curry
190 [ lexer ] dip with-variable ; inline