]> gitweb.factorcode.org Git - factor.git/blob - core/lexer/lexer.factor
core: whoops, all these moves got missed.
[factor.git] / core / lexer / lexer.factor
1 ! Copyright (C) 2008, 2010 Slava Pestov, Joe Groff.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays classes combinators continuations io
4 kernel kernel.private math math.parser namespaces sequences
5 sequences.private source-files.errors strings vectors ;
6 IN: lexer
7
8 TUPLE: lexer
9     { text array }
10     { line fixnum }
11     { line-text string }
12     { line-length fixnum }
13     { column fixnum }
14     { parsing-words vector } ;
15
16 TUPLE: lexer-parsing-word word line line-text column ;
17
18 : next-line ( lexer -- )
19     lexer check-instance
20     dup [ line>> ] [ text>> ] bi ?nth "" or
21     [ >>line-text ] [ length >>line-length ] bi
22     [ 1 + ] change-line
23     0 >>column
24     drop ;
25
26 : push-parsing-word ( word -- )
27     lexer get lexer check-instance [
28         [ line>> ] [ line-text>> ] [ column>> ] tri
29         lexer-parsing-word boa
30     ] [ parsing-words>> push ] bi ;
31
32 : pop-parsing-word ( -- )
33     lexer get lexer check-instance parsing-words>> pop* ;
34
35 : new-lexer ( text class -- lexer )
36     new
37         0 >>line
38         swap >>text
39         V{ } clone >>parsing-words
40     dup next-line ; inline
41
42 : <lexer> ( text -- lexer )
43     lexer new-lexer ;
44
45 ERROR: unexpected want got ;
46
47 : change-lexer-column ( ..a lexer quot: ( ..a col line -- ..b newcol ) -- ..b )
48     [ lexer check-instance [ column>> ] [ line-text>> ] bi ] prepose
49     keep column<< ; inline
50
51 <PRIVATE
52
53 : shebang? ( lexer -- lexer ? )
54     dup line>> 1 = [
55         dup column>> zero? [
56             dup line-text>> "#!" head?
57         ] [ f ] if
58     ] [ f ] if ; inline
59
60 : forbid-tab ( c -- c )
61     [ CHAR: \t eq? [ "[space]" "[tab]" unexpected ] when ] keep ; inline
62
63 PRIVATE>
64
65 SBUF""
66 URL"google.com"
67
68 GENERIC: skip-blank ( lexer -- )
69
70 M: lexer skip-blank
71     shebang? [
72         [ nip length ] change-lexer-column
73     ] [
74         [
75             [ [ forbid-tab CHAR: \s eq? not ] find-from drop ]
76             [ length or ] bi
77         ] change-lexer-column
78     ] if ;
79
80 GENERIC: skip-word ( lexer -- )
81
82 M: lexer skip-word
83     [
84         [ [ forbid-tab " \"" member-eq? ] find-from CHAR: \" eq? [ 1 + ] when ]
85         [ length or ] bi
86     ] change-lexer-column ;
87
88 : still-parsing? ( lexer -- ? )
89     lexer check-instance [ line>> ] [ text>> length ] bi <= ;
90
91 : still-parsing-line? ( lexer -- ? )
92     lexer check-instance [ column>> ] [ line-length>> ] bi < ;
93
94 : (parse-raw) ( lexer -- str )
95     lexer check-instance {
96         [ column>> ]
97         [ skip-word ]
98         [ column>> ]
99         [ line-text>> ]
100     } cleave subseq ;
101
102 : parse-raw ( lexer -- str/f )
103     dup still-parsing? [
104         dup skip-blank
105         dup still-parsing-line?
106         [ (parse-raw) ] [ dup next-line parse-raw ] if
107     ] [ drop f ] if ;
108
109 DEFER: parse-token
110
111 : skip-comments ( lexer str -- str' )
112     dup "!" = [
113         drop [ next-line ] keep parse-token
114     ] [
115         nip
116     ] if ;
117
118 : parse-token ( lexer -- str/f )
119     dup parse-raw [ skip-comments ] [ drop f ] if* ;
120
121 : ?scan-token ( -- str/f ) lexer get parse-token ;
122
123 PREDICATE: unexpected-eof < unexpected got>> not ;
124
125 : throw-unexpected-eof ( word -- * ) f unexpected ;
126
127 : scan-token ( -- str )
128     ?scan-token [ "token" throw-unexpected-eof ] unless* ;
129
130 : expect ( token -- )
131     scan-token 2dup = [ 2drop ] [ unexpected ] if ;
132
133 : each-token ( ... end quot: ( ... token -- ... ) -- ... )
134     [ scan-token ] 2dip 2over =
135     [ 3drop ] [ [ nip call ] [ each-token ] 2bi ] if ; inline recursive
136
137 : map-tokens ( ... end quot: ( ... token -- ... elt ) -- ... seq )
138     collector [ each-token ] dip { } like ; inline
139
140 : parse-tokens ( end -- seq )
141     [ ] map-tokens ;
142
143 TUPLE: lexer-error line column line-text parsing-words error ;
144
145 M: lexer-error error-file error>> error-file ;
146
147 M: lexer-error error-line [ error>> error-line ] [ line>> ] bi or ;
148
149 : <lexer-error> ( msg -- error )
150     [
151         lexer get {
152             [ line>> ]
153             [ column>> ]
154             [ line-text>> ]
155             [ parsing-words>> clone ]
156         } cleave
157     ] dip lexer-error boa ;
158
159 <PRIVATE
160
161 : simple-lexer-dump ( error -- )
162     [ line>> number>string ": " append ]
163     [ line-text>> ]
164     [ column>> ] tri
165     pick length + CHAR: \s <string>
166     [ write ] [ print ] [ write "^" print ] tri* ;
167
168 : parsing-word-lexer-dump ( error parsing-word -- error )
169     2dup [ line>> ] same? [ drop ] [
170         [
171             line>> number>string
172             over line>> number>string length
173             CHAR: \s pad-head
174             ": " append write
175         ] [ line-text>> print ] bi
176     ] if ;
177
178 PRIVATE>
179
180 : lexer-dump ( error -- )
181     dup parsing-words>> ?last [
182         parsing-word-lexer-dump
183     ] when* simple-lexer-dump ;
184
185 : with-lexer ( lexer quot -- newquot )
186     [ [ <lexer-error> rethrow ] recover ] curry
187     [ lexer ] dip with-variable ; inline