1
1
use crate :: tokenizer:: * ;
2
+ use core:: str:: FromStr ;
2
3
3
4
type Integer = isize ;
4
5
type Real = f64 ;
@@ -32,6 +33,11 @@ pub(crate) enum Statement<'src> {
32
33
func : & ' src str ,
33
34
args : Vec < Expression < ' src > > ,
34
35
} ,
36
+ For {
37
+ var : & ' src str ,
38
+ expr : Expression < ' src > ,
39
+ lines : Lines < ' src > ,
40
+ } ,
35
41
}
36
42
37
43
#[ derive( Debug ) ]
@@ -71,6 +77,7 @@ pub enum ErrorType {
71
77
UnexpectedEOL ,
72
78
UnexpectedSpace ,
73
79
Noop ,
80
+ NotANumber ,
74
81
}
75
82
76
83
macro_rules! err {
@@ -134,10 +141,10 @@ impl<'src> Script<'src> {
134
141
}
135
142
}
136
143
144
+ type TokenGroup < ' src > = ( Token < ' src > , usize , usize ) ;
145
+
137
146
impl < ' src > Function < ' src > {
138
- fn parse (
139
- tokens : & mut impl Iterator < Item = ( Token < ' src > , usize , usize ) > ,
140
- ) -> Result < Self , Error > {
147
+ fn parse ( tokens : & mut impl Iterator < Item = TokenGroup < ' src > > ) -> Result < Self , Error > {
141
148
let name = match skip_whitespace ( tokens) {
142
149
Some ( ( Token :: Name ( name) , _, _) ) => name,
143
150
Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
@@ -162,27 +169,46 @@ impl<'src> Function<'src> {
162
169
Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
163
170
None => err ! ( UnexpectedEOL , 0 , 0 ) ,
164
171
}
165
- let mut tab_count = 0 ;
166
- let ( mut tk, mut line, mut column) = loop {
167
- match tokens. next ( ) {
168
- Some ( ( Token :: Tab , _, _) ) => tab_count += 1 ,
169
- Some ( e) => break e,
170
- None => err ! ( UnexpectedEOL , 0 , 0 ) ,
171
- }
172
+
173
+ // Ensure there is one and only one tab
174
+ let ( l, c) = match tokens. next ( ) {
175
+ Some ( ( Token :: Tab , l, c) ) => ( l, c) ,
176
+ Some ( ( e, l, c) ) => err ! ( UnexpectedToken , l, c) ,
177
+ None => err ! ( UnexpectedEOL , 0 , 0 ) ,
172
178
} ;
173
- let tab_count = tab_count;
174
179
180
+ Ok ( Self {
181
+ name,
182
+ parameters,
183
+ lines : Self :: parse_block ( tokens, 1 , l, c) ?. 0 ,
184
+ } )
185
+ }
186
+
187
+ fn parse_block (
188
+ tokens : & mut impl Iterator < Item = TokenGroup < ' src > > ,
189
+ expected_indent : u8 ,
190
+ mut line : usize ,
191
+ mut column : usize ,
192
+ ) -> Result < ( Lines < ' src > , u8 ) , Error > {
175
193
let mut lines = Lines :: new ( ) ;
176
- let mut curr_tabs = 0 ;
177
194
loop {
178
- match tk {
179
- Token :: Space => err ! ( UnexpectedSpace , line, column) ,
180
- Token :: Tab => curr_tabs += 1 ,
181
- Token :: EOL => curr_tabs = 0 ,
182
- Token :: Name ( name) => {
195
+ match tokens. next ( ) {
196
+ Some ( ( Token :: EOL , ..) ) => {
197
+ for i in 0 ..expected_indent {
198
+ if let Some ( ( tk, l, c) ) = tokens. next ( ) {
199
+ if tk == Token :: Space {
200
+ err ! ( UnexpectedToken , l, c) ;
201
+ } else if tk != Token :: Tab {
202
+ return Ok ( ( lines, i) ) ;
203
+ }
204
+ }
205
+ }
206
+ }
207
+ Some ( ( Token :: Tab , l, c) ) => err ! ( UnexpectedToken , l, c) ,
208
+ Some ( ( Token :: Name ( name) , ll, lc) ) => {
183
209
let mut args = Vec :: new ( ) ;
184
210
match skip_whitespace ( tokens) {
185
- Some ( ( Token :: EOL , ..) ) => break ,
211
+ Some ( ( Token :: EOL , ..) ) => continue ,
186
212
Some ( ( Token :: BracketRoundOpen , l, c) ) => match skip_whitespace ( tokens) {
187
213
Some ( ( Token :: BracketRoundClose , ..) ) => ( ) ,
188
214
Some ( ( pre, ..) ) => {
@@ -205,18 +231,61 @@ impl<'src> Function<'src> {
205
231
dbg ! ( e) ;
206
232
todo ! ( )
207
233
}
208
- None => err ! ( UnexpectedEOL , 0 , 0 ) ,
234
+ None => err ! ( UnexpectedEOL , ll , lc ) ,
209
235
}
210
236
}
211
- _ => todo ! ( ) ,
212
- }
237
+ Some ( ( Token :: For , mut ll, mut lc) ) => {
238
+ let var = match skip_whitespace ( tokens) {
239
+ Some ( ( Token :: Name ( n) , ..) ) => n,
240
+ Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
241
+ None => err ! ( UnexpectedEOL , line, column) ,
242
+ } ;
243
+ match skip_whitespace ( tokens) {
244
+ Some ( ( Token :: In , ..) ) => ( ) ,
245
+ Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
246
+ None => err ! ( UnexpectedEOL , line, column) ,
247
+ }
248
+ let ( expr, tk) = match skip_whitespace ( tokens) {
249
+ Some ( ( tk, ..) ) => Expression :: parse ( tk, tokens) ?,
250
+ None => err ! ( UnexpectedEOL , line, column) ,
251
+ } ;
252
+ if tk == Token :: EOL {
253
+ let expected_indent = expected_indent + 1 ;
254
+ ' eol: loop {
255
+ for i in 0 ..expected_indent {
256
+ match tokens. next ( ) {
257
+ Some ( ( Token :: Tab , l, c) ) => {
258
+ ll = l;
259
+ lc = c;
260
+ }
261
+ Some ( ( Token :: EOL , l, c) ) => {
262
+ ll = l;
263
+ lc = c;
264
+ continue ' eol;
265
+ }
266
+ Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
267
+ None => err ! ( UnexpectedEOL , ll, lc) ,
268
+ }
269
+ }
270
+ break ;
271
+ }
272
+ lines. push ( Statement :: For {
273
+ var,
274
+ expr,
275
+ lines : Self :: parse_block ( tokens, expected_indent, ll, lc) ?. 0 ,
276
+ } ) ;
277
+ } else {
278
+ err ! ( UnexpectedToken , 0 , 0 ) ;
279
+ }
280
+ }
281
+ Some ( ( Token :: Pass , ..) ) => ( ) ,
282
+ Some ( ( tk, ..) ) => {
283
+ dbg ! ( tk) ;
284
+ todo ! ( )
285
+ }
286
+ None => return Ok ( ( lines, 0 ) ) ,
287
+ } ;
213
288
}
214
-
215
- Ok ( Self {
216
- name,
217
- parameters,
218
- lines,
219
- } )
220
289
}
221
290
}
222
291
@@ -231,6 +300,17 @@ impl<'src> Expression<'src> {
231
300
None => err ! ( UnexpectedEOL , 0 , 0 ) ,
232
301
} ,
233
302
Token :: String ( s) => ( Expression :: Atom ( Atom :: String ( s) ) , None ) ,
303
+ Token :: Number ( n) => (
304
+ Expression :: Atom ( if let Ok ( n) = parse_integer ( n) {
305
+ Atom :: Integer ( n)
306
+ } else if let Ok ( n) = Real :: from_str ( n) {
307
+ Atom :: Real ( n)
308
+ } else {
309
+ dbg ! ( n) ;
310
+ err ! ( NotANumber , 0 , 0 ) ;
311
+ } ) ,
312
+ None ,
313
+ ) ,
234
314
e => {
235
315
dbg ! ( e) ;
236
316
todo ! ( )
@@ -239,7 +319,9 @@ impl<'src> Expression<'src> {
239
319
match skip_whitespace ( tokens) {
240
320
Some ( ( Token :: BracketRoundClose , ..) ) => return Ok ( ( lhs, Token :: BracketRoundClose ) ) ,
241
321
Some ( ( Token :: Comma , ..) ) => return Ok ( ( lhs, Token :: Comma ) ) ,
242
- _ => todo ! ( ) ,
322
+ Some ( ( Token :: EOL , ..) ) => return Ok ( ( lhs, Token :: EOL ) ) ,
323
+ Some ( ( tk, ..) ) => todo ! ( "{:?}" , tk) ,
324
+ None => todo ! ( "none" ) ,
243
325
}
244
326
/*
245
327
let lhs = match skip_whitespace(tokens) {
@@ -261,3 +343,46 @@ impl Error {
261
343
} )
262
344
}
263
345
}
346
+
347
+ enum NumberParseError {
348
+ InvalidBase ,
349
+ InvalidDigit ,
350
+ Empty ,
351
+ }
352
+
353
+ /// Custom integer parsing function that allows underscores
354
+ fn parse_integer ( s : & str ) -> Result < Integer , NumberParseError > {
355
+ let mut chars = s. chars ( ) ;
356
+ let ( mut chars, base) = if chars. next ( ) == Some ( '0' ) {
357
+ if let Some ( c) = chars. next ( ) {
358
+ let b = match c {
359
+ 'x' => 16 ,
360
+ 'b' => 2 ,
361
+ 'o' => 8 ,
362
+ _ => return Err ( NumberParseError :: InvalidBase ) ,
363
+ } ;
364
+ ( chars, b)
365
+ } else {
366
+ return Ok ( 0 ) ;
367
+ }
368
+ } else {
369
+ ( s. chars ( ) , 10 )
370
+ } ;
371
+ if s == "" {
372
+ Err ( NumberParseError :: Empty )
373
+ } else {
374
+ let mut chars = chars. peekable ( ) ;
375
+ let neg = if chars. peek ( ) == Some ( & '-' ) {
376
+ chars. next ( ) ;
377
+ true
378
+ } else {
379
+ false
380
+ } ;
381
+ let mut n = 0 ;
382
+ for c in chars. filter ( |& c| c != '_' ) {
383
+ n *= base as Integer ;
384
+ n += c. to_digit ( base) . ok_or ( NumberParseError :: InvalidDigit ) ? as isize ;
385
+ }
386
+ Ok ( if neg { -n } else { n } )
387
+ }
388
+ }
0 commit comments