@@ -38,9 +38,12 @@ pub(crate) enum Statement<'src> {
38
38
expr : Expression < ' src > ,
39
39
lines : Lines < ' src > ,
40
40
} ,
41
+ Return {
42
+ expr : Option < Expression < ' src > > ,
43
+ } ,
41
44
}
42
45
43
- #[ derive( Debug ) ]
46
+ #[ derive( Debug , PartialEq ) ]
44
47
pub ( crate ) enum Atom < ' src > {
45
48
Name ( & ' src str ) ,
46
49
Real ( Real ) ,
@@ -156,11 +159,19 @@ impl<'src> Function<'src> {
156
159
None => err ! ( UnexpectedEOL , 0 , 0 ) ,
157
160
}
158
161
159
- let parameters = Vec :: new ( ) ;
162
+ let mut parameters = Vec :: new ( ) ;
160
163
loop {
161
164
match skip_whitespace ( tokens) {
162
165
Some ( ( Token :: BracketRoundClose , _, _) ) => break ,
163
- _ => todo ! ( ) ,
166
+ Some ( ( Token :: Name ( a) , l, c) ) => {
167
+ parameters. push ( a) ;
168
+ match skip_whitespace ( tokens) {
169
+ Some ( ( Token :: BracketRoundClose , ..) ) => break ,
170
+ Some ( ( Token :: Comma , ..) ) => ( ) ,
171
+ e => todo ! ( "{:?}" , e) ,
172
+ }
173
+ }
174
+ e => todo ! ( "{:?}" , e) ,
164
175
}
165
176
}
166
177
@@ -216,8 +227,8 @@ impl<'src> Function<'src> {
216
227
let ( expr, last_tk) = Expression :: parse ( pre, tokens) ?;
217
228
args. push ( expr) ;
218
229
match last_tk {
219
- Token :: Comma => ( ) ,
220
- Token :: BracketRoundClose => break ,
230
+ Some ( Token :: Comma ) => ( ) ,
231
+ Some ( Token :: BracketRoundClose ) => break ,
221
232
tk => {
222
233
panic ! ( "Expression did not parse all tokens: {:?}" , tk)
223
234
}
@@ -249,7 +260,7 @@ impl<'src> Function<'src> {
249
260
Some ( ( tk, ..) ) => Expression :: parse ( tk, tokens) ?,
250
261
None => err ! ( UnexpectedEOL , line, column) ,
251
262
} ;
252
- if tk == Token :: EOL {
263
+ if tk == Some ( Token :: EOL ) {
253
264
let expected_indent = expected_indent + 1 ;
254
265
' eol: loop {
255
266
for i in 0 ..expected_indent {
@@ -279,10 +290,18 @@ impl<'src> Function<'src> {
279
290
}
280
291
}
281
292
Some ( ( Token :: Pass , ..) ) => ( ) ,
282
- Some ( ( tk, ..) ) => {
283
- dbg ! ( tk) ;
284
- todo ! ( )
285
- }
293
+ Some ( ( Token :: Return , l, c) ) => {
294
+ if let Some ( ( tk, l, c) ) = skip_whitespace ( tokens) {
295
+ let expr = match Expression :: parse ( tk, tokens) {
296
+ Ok ( expr) => Some ( expr. 0 ) ,
297
+ e => todo ! ( "{:?}" , e) ,
298
+ } ;
299
+ lines. push ( Statement :: Return { expr } ) ;
300
+ } else {
301
+ err ! ( UnexpectedEOL , l, c) ;
302
+ }
303
+ }
304
+ Some ( ( tk, ..) ) => todo ! ( "{:?}" , tk) ,
286
305
None => return Ok ( ( lines, 0 ) ) ,
287
306
} ;
288
307
}
@@ -293,44 +312,108 @@ impl<'src> Expression<'src> {
293
312
fn parse (
294
313
pre : Token < ' src > ,
295
314
tokens : & mut impl Iterator < Item = ( Token < ' src > , usize , usize ) > ,
296
- ) -> Result < ( Self , Token < ' src > ) , Error > {
315
+ ) -> Result < ( Self , Option < Token < ' src > > ) , Error > {
297
316
let ( lhs, last_tk) = match pre {
298
317
Token :: BracketRoundOpen => match skip_whitespace ( tokens) {
299
- Some ( ( pre, ..) ) => Self :: parse ( pre, tokens) . map ( |( e, t) | ( e, Some ( t ) ) ) ?,
318
+ Some ( ( pre, ..) ) => Self :: parse ( pre, tokens) . map ( |( e, t) | ( e, t ) ) ?,
300
319
None => err ! ( UnexpectedEOL , 0 , 0 ) ,
301
320
} ,
302
321
Token :: String ( s) => ( Expression :: Atom ( Atom :: String ( s) ) , None ) ,
303
322
Token :: Number ( n) => (
304
323
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)
324
+ n
308
325
} else {
309
- dbg ! ( n) ;
310
326
err ! ( NotANumber , 0 , 0 ) ;
311
327
} ) ,
312
328
None ,
313
329
) ,
314
- e => {
315
- dbg ! ( e) ;
316
- todo ! ( )
317
- }
330
+ Token :: Name ( name) => {
331
+ match skip_whitespace ( tokens) {
332
+ Some ( ( Token :: BracketRoundOpen , ..) ) => {
333
+ let mut arguments = Vec :: new ( ) ;
334
+ loop {
335
+ match skip_whitespace ( tokens) {
336
+ Some ( ( Token :: Number ( n) , l, c) ) => {
337
+ if let Ok ( n) = parse_integer ( n) {
338
+ arguments. push ( Expression :: Atom ( n) ) ;
339
+ } else {
340
+ err ! ( NotANumber , l, c) ;
341
+ }
342
+ } ,
343
+ e => todo ! ( "{:?}" , e) ,
344
+ }
345
+ match skip_whitespace ( tokens) {
346
+ Some ( ( Token :: Comma , ..) ) => ( ) ,
347
+ Some ( ( Token :: BracketRoundClose , ..) ) => break ,
348
+ Some ( ( _, l, c) ) => err ! ( UnexpectedToken , l, c) ,
349
+ None => err ! ( UnexpectedEOL , 0 , 0 ) ,
350
+ }
351
+ }
352
+ ( Expression :: Function { name, arguments } , None )
353
+ }
354
+ Some ( ( tk, ..) ) => ( Expression :: Atom ( Atom :: Name ( name) ) , Some ( tk) ) ,
355
+ e => todo ! ( "{:?}" , e) ,
356
+ }
357
+ }
358
+ e => todo ! ( "{:?}" , e) ,
318
359
} ;
319
- match skip_whitespace ( tokens) {
320
- Some ( ( Token :: BracketRoundClose , ..) ) => return Ok ( ( lhs, Token :: BracketRoundClose ) ) ,
321
- Some ( ( Token :: Comma , ..) ) => return Ok ( ( lhs, Token :: Comma ) ) ,
322
- Some ( ( Token :: EOL , ..) ) => return Ok ( ( lhs, Token :: EOL ) ) ,
323
- Some ( ( tk, ..) ) => todo ! ( "{:?}" , tk) ,
324
- None => todo ! ( "none" ) ,
325
- }
326
- /*
327
- let lhs = match skip_whitespace(tokens) {
328
- Some((Token::BracketRoundOpen, ..)) => Self::parse(tokens)?,
329
- Some((Token::String(s), ..)) => Expression::Atom(Atom::String(s)),
330
- Some(e) => { dbg!(e); todo!() },
331
- None => todo!(),
332
- };
333
- */
360
+ if let Some ( last_tk) = last_tk {
361
+ match last_tk {
362
+ Token :: Op ( opl) => {
363
+ match skip_whitespace ( tokens) {
364
+ Some ( ( Token :: Name ( mid) , ..) ) => {
365
+ let mid = Expression :: Atom ( Atom :: Name ( mid) ) ;
366
+ match skip_whitespace ( tokens) {
367
+ Some ( ( Token :: Op ( opr) , ..) ) => {
368
+ match skip_whitespace ( tokens) {
369
+ Some ( ( Token :: Name ( rhs) , ..) ) => {
370
+ let ( left, op, right) = if opl >= opr {
371
+ let rhs = Expression :: parse ( Token :: Name ( rhs) , tokens) ?. 0 ;
372
+ let lhs = Expression :: Operation {
373
+ op : opl,
374
+ left : Box :: new ( lhs) ,
375
+ right : Box :: new ( mid) ,
376
+ } ;
377
+ ( lhs, opr, rhs)
378
+ } else {
379
+ let rhs = Expression :: Atom ( Atom :: Name ( rhs) ) ;
380
+ let rhs = Expression :: Operation {
381
+ op : opr,
382
+ left : Box :: new ( mid) ,
383
+ right : Box :: new ( rhs) ,
384
+ } ;
385
+ ( lhs, opl, rhs)
386
+ } ;
387
+ let ( left, right) = ( Box :: new ( left) , Box :: new ( right) ) ;
388
+ Ok ( ( Expression :: Operation { left, op, right } , skip_whitespace ( tokens) . map ( |v| v. 0 ) ) )
389
+ }
390
+ e => todo ! ( "{:?}" , e) ,
391
+ }
392
+ }
393
+ Some ( ( tk, ..) ) if tk == Token :: BracketRoundClose || tk == Token :: EOL => {
394
+ Ok ( ( Expression :: Operation {
395
+ left : Box :: new ( lhs) ,
396
+ op : opl,
397
+ right : Box :: new ( mid) ,
398
+ } , Some ( tk) ) )
399
+ }
400
+ e => todo ! ( "{:?}" , e) ,
401
+ }
402
+ }
403
+ e => todo ! ( "{:?}" , e) ,
404
+ }
405
+ }
406
+ e => todo ! ( "{:?}" , e) ,
407
+ }
408
+ } else {
409
+ match skip_whitespace ( tokens) {
410
+ Some ( ( Token :: BracketRoundClose , ..) ) => return Ok ( ( lhs, Some ( Token :: BracketRoundClose ) ) ) ,
411
+ Some ( ( Token :: Comma , ..) ) => return Ok ( ( lhs, Some ( Token :: Comma ) ) ) ,
412
+ Some ( ( Token :: EOL , ..) ) => return Ok ( ( lhs, Some ( Token :: EOL ) ) ) ,
413
+ Some ( ( tk, ..) ) => todo ! ( "{:?}" , tk) ,
414
+ None => todo ! ( "none" ) ,
415
+ }
416
+ }
334
417
}
335
418
}
336
419
@@ -344,45 +427,100 @@ impl Error {
344
427
}
345
428
}
346
429
430
+ #[ derive( Debug , PartialEq ) ]
347
431
enum NumberParseError {
348
432
InvalidBase ,
349
433
InvalidDigit ,
350
434
Empty ,
435
+ SeparatorInWrongPosition ,
351
436
}
352
437
353
- /// Custom integer parsing function that allows underscores
354
- fn parse_integer ( s : & str ) -> Result < Integer , NumberParseError > {
438
+ /// Custom number parsing function that allows underscores
439
+ fn parse_integer ( s : & str ) -> Result < Atom , NumberParseError > {
355
440
let mut chars = s. chars ( ) ;
356
441
let ( mut chars, base) = if chars. next ( ) == Some ( '0' ) {
357
442
if let Some ( c) = chars. next ( ) {
358
- let b = match c {
359
- 'x' => 16 ,
360
- 'b' => 2 ,
361
- 'o' => 8 ,
443
+ if let Some ( b) = match c {
444
+ 'x' => Some ( 16 ) ,
445
+ 'b' => Some ( 2 ) ,
446
+ 'o' => Some ( 8 ) ,
447
+ '0' | '.' => None ,
362
448
_ => return Err ( NumberParseError :: InvalidBase ) ,
363
- } ;
364
- ( chars, b)
449
+ } {
450
+ ( chars, b)
451
+ } else {
452
+ ( s. chars ( ) , 10 )
453
+ }
365
454
} else {
366
- return Ok ( 0 ) ;
455
+ return Ok ( Atom :: Integer ( 0 ) ) ;
367
456
}
368
457
} else {
369
458
( s. chars ( ) , 10 )
370
459
} ;
371
460
if s == "" {
372
461
Err ( NumberParseError :: Empty )
373
462
} 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 } )
463
+ let mut chars = chars. peekable ( ) ;
464
+ let neg = if chars. peek ( ) == Some ( & '-' ) {
465
+ chars. next ( ) ;
466
+ true
467
+ } else {
468
+ false
469
+ } ;
470
+ let mut chars = chars. filter ( |& c| c != '_' ) . peekable ( ) ;
471
+ // Real numbers and integers have to be processed separately as the range of a real can
472
+ // exceed that of an integer
473
+ if s. contains ( '.' ) {
474
+ // Don't accept '.0', '0.' or even '.'. While many languages accept the former two,
475
+ // I believe they are a poor choice for readability, hence they are disallowed.
476
+ if chars. peek ( ) . unwrap ( ) == & '.' {
477
+ return Err ( NumberParseError :: SeparatorInWrongPosition ) ;
478
+ }
479
+ let mut n = 0.0 ;
480
+ loop {
481
+ let c = chars. next ( ) . unwrap ( ) ;
482
+ if c == '.' {
483
+ break ;
484
+ }
485
+ n *= base as Real ;
486
+ n += c. to_digit ( base) . ok_or ( NumberParseError :: InvalidDigit ) ? as Real ;
487
+ }
488
+ if chars. peek ( ) == None {
489
+ return Err ( NumberParseError :: SeparatorInWrongPosition ) ;
490
+ }
491
+ let mut i = 1.0 / base as Real ;
492
+ for c in chars {
493
+ n += ( c. to_digit ( base) . ok_or ( NumberParseError :: InvalidDigit ) ? as Real ) * i;
494
+ i /= base as Real ;
495
+ }
496
+ Ok ( Atom :: Real ( if neg { -n } else { n } ) )
497
+ } else {
498
+ let mut n = 0 ;
499
+ for c in chars {
500
+ n *= base as Integer ;
501
+ // Negative numbers have a larger range than positive numbers (e.g. i8 has range -128..127)
502
+ n -= c. to_digit ( base) . ok_or ( NumberParseError :: InvalidDigit ) ? as Integer ;
503
+ }
504
+ Ok ( Atom :: Integer ( if neg { n } else { -n } ) )
505
+ }
387
506
}
388
507
}
508
+
509
+ #[ cfg( test) ]
510
+ mod test {
511
+ use super :: * ;
512
+
513
+ #[ test]
514
+ fn number ( ) {
515
+ assert_eq ! ( parse_integer( "0" ) , Ok ( Atom :: Integer ( 0 ) ) ) ;
516
+ assert_eq ! ( parse_integer( "32" ) , Ok ( Atom :: Integer ( 32 ) ) ) ;
517
+ assert_eq ! ( parse_integer( "0.0" ) , Ok ( Atom :: Real ( 0.0 ) ) ) ;
518
+ match parse_integer ( "13.37" ) {
519
+ Ok ( Atom :: Real ( f) ) => assert ! ( ( f - 13.37 ) . abs( ) <= Real :: EPSILON * 13.37 ) ,
520
+ r => panic ! ( "{:?}" , r) ,
521
+ }
522
+ assert_eq ! ( parse_integer( "." ) , Err ( NumberParseError :: SeparatorInWrongPosition ) ) ;
523
+ assert_eq ! ( parse_integer( "0." ) , Err ( NumberParseError :: SeparatorInWrongPosition ) ) ;
524
+ assert_eq ! ( parse_integer( ".0" ) , Err ( NumberParseError :: SeparatorInWrongPosition ) ) ;
525
+ }
526
+ }
0 commit comments