@@ -351,7 +351,7 @@ class UnexpectedEOFError(ParseError):
351
351
352
352
353
353
def parse_assign (tokens : typing .List [Token ], p : float = 0 ) -> "Assign" :
354
- assign = parse (tokens , p )
354
+ assign = parse_binary (tokens , p )
355
355
if isinstance (assign , Spread ):
356
356
return Assign (Var ("..." ), assign )
357
357
if not isinstance (assign , Assign ):
@@ -371,26 +371,26 @@ def gensym_reset() -> None:
371
371
gensym_reset ()
372
372
373
373
374
- def parse (tokens : typing .List [Token ], p : float = 0 ) -> "Object" :
374
+ def parse_unary (tokens : typing .List [Token ], p : float ) -> "Object" :
375
375
if not tokens :
376
376
raise UnexpectedEOFError ("unexpected end of input" )
377
377
token = tokens .pop (0 )
378
378
l : Object
379
379
if isinstance (token , IntLit ):
380
- l = Int (token .value )
380
+ return Int (token .value )
381
381
elif isinstance (token , FloatLit ):
382
- l = Float (token .value )
382
+ return Float (token .value )
383
383
elif isinstance (token , Name ):
384
384
# TODO: Handle kebab case vars
385
- l = Var (token .value )
385
+ return Var (token .value )
386
386
elif isinstance (token , VariantToken ):
387
387
# It needs to be higher than the precedence of the -> operator so that
388
388
# we can match variants in MatchFunction
389
389
# It needs to be higher than the precedence of the && operator so that
390
390
# we can use #true() and #false() in boolean expressions
391
391
# It needs to be higher than the precedence of juxtaposition so that
392
392
# f #true() #false() is parsed as f(TRUE)(FALSE)
393
- l = Variant (token .value , parse (tokens , PS ["" ].pr + 1 ))
393
+ return Variant (token .value , parse_binary (tokens , PS ["" ].pr + 1 ))
394
394
elif isinstance (token , BytesLit ):
395
395
base = token .base
396
396
if base == 85 :
@@ -403,45 +403,48 @@ def parse(tokens: typing.List[Token], p: float = 0) -> "Object":
403
403
l = Bytes (base64 .b16decode (token .value ))
404
404
else :
405
405
raise ParseError (f"unexpected base { base !r} in { token !r} " )
406
+ return l
406
407
elif isinstance (token , StringLit ):
407
- l = String (token .value )
408
+ return String (token .value )
408
409
elif token == Operator ("..." ):
409
410
if tokens and isinstance (tokens [0 ], Name ):
410
411
name = tokens [0 ].value
411
412
tokens .pop (0 )
412
- l = Spread (name )
413
+ return Spread (name )
413
414
else :
414
- l = Spread ()
415
+ return Spread ()
415
416
elif token == Operator ("|" ):
416
- expr = parse (tokens , PS ["|" ].pr ) # TODO: make this work for larger arities
417
+ expr = parse_binary (tokens , PS ["|" ].pr ) # TODO: make this work for larger arities
417
418
if not isinstance (expr , Function ):
418
419
raise ParseError (f"expected function in match expression { expr !r} " )
419
420
cases = [MatchCase (expr .arg , expr .body )]
420
421
while tokens and tokens [0 ] == Operator ("|" ):
421
422
tokens .pop (0 )
422
- expr = parse (tokens , PS ["|" ].pr ) # TODO: make this work for larger arities
423
+ expr = parse_binary (tokens , PS ["|" ].pr ) # TODO: make this work for larger arities
423
424
if not isinstance (expr , Function ):
424
425
raise ParseError (f"expected function in match expression { expr !r} " )
425
426
cases .append (MatchCase (expr .arg , expr .body ))
426
- l = MatchFunction (cases )
427
+ return MatchFunction (cases )
427
428
elif isinstance (token , LeftParen ):
428
429
if isinstance (tokens [0 ], RightParen ):
429
430
l = Hole ()
430
431
else :
431
432
l = parse (tokens )
432
433
tokens .pop (0 )
434
+ return l
433
435
elif isinstance (token , LeftBracket ):
434
436
l = List ([])
435
437
token = tokens [0 ]
436
438
if isinstance (token , RightBracket ):
437
439
tokens .pop (0 )
438
440
else :
439
- l .items .append (parse (tokens , 2 ))
441
+ l .items .append (parse_binary (tokens , 2 ))
440
442
while not isinstance (tokens .pop (0 ), RightBracket ):
441
443
if isinstance (l .items [- 1 ], Spread ):
442
444
raise ParseError ("spread must come at end of list match" )
443
445
# TODO: Implement .. operator
444
- l .items .append (parse (tokens , 2 ))
446
+ l .items .append (parse_binary (tokens , 2 ))
447
+ return l
445
448
elif isinstance (token , LeftBrace ):
446
449
l = Record ({})
447
450
token = tokens [0 ]
@@ -456,17 +459,21 @@ def parse(tokens: typing.List[Token], p: float = 0) -> "Object":
456
459
# TODO: Implement .. operator
457
460
assign = parse_assign (tokens , 2 )
458
461
l .data [assign .name .name ] = assign .value
462
+ return l
459
463
elif token == Operator ("-" ):
460
464
# Unary minus
461
465
# Precedence was chosen to be higher than binary ops so that -a op
462
466
# b is (-a) op b and not -(a op b).
463
467
# Precedence was chosen to be higher than function application so that
464
468
# -a b is (-a) b and not -(a b).
465
- r = parse (tokens , HIGHEST_PREC + 1 )
466
- l = Binop (BinopKind .SUB , Int (0 ), r )
469
+ r = parse_binary (tokens , HIGHEST_PREC + 1 )
470
+ return Binop (BinopKind .SUB , Int (0 ), r )
467
471
else :
468
472
raise ParseError (f"unexpected token { token !r} " )
469
473
474
+
475
+ def parse_binary (tokens : typing .List [Token ], p : float ) -> "Object" :
476
+ l : Object = parse_unary (tokens , p )
470
477
while True :
471
478
if not tokens :
472
479
break
@@ -478,7 +485,7 @@ def parse(tokens: typing.List[Token], p: float = 0) -> "Object":
478
485
pl , pr = prec .pl , prec .pr
479
486
if pl < p :
480
487
break
481
- l = Apply (l , parse (tokens , pr ))
488
+ l = Apply (l , parse_binary (tokens , pr ))
482
489
continue
483
490
prec = PS [op .value ]
484
491
pl , pr = prec .pl , prec .pr
@@ -488,34 +495,38 @@ def parse(tokens: typing.List[Token], p: float = 0) -> "Object":
488
495
if op == Operator ("=" ):
489
496
if not isinstance (l , Var ):
490
497
raise ParseError (f"expected variable in assignment { l !r} " )
491
- l = Assign (l , parse (tokens , pr ))
498
+ l = Assign (l , parse_binary (tokens , pr ))
492
499
elif op == Operator ("->" ):
493
- l = Function (l , parse (tokens , pr ))
500
+ l = Function (l , parse_binary (tokens , pr ))
494
501
elif op == Operator ("|>" ):
495
- l = Apply (parse (tokens , pr ), l )
502
+ l = Apply (parse_binary (tokens , pr ), l )
496
503
elif op == Operator ("<|" ):
497
- l = Apply (l , parse (tokens , pr ))
504
+ l = Apply (l , parse_binary (tokens , pr ))
498
505
elif op == Operator (">>" ):
499
- r = parse (tokens , pr )
506
+ r = parse_binary (tokens , pr )
500
507
varname = gensym ()
501
508
l = Function (Var (varname ), Apply (r , Apply (l , Var (varname ))))
502
509
elif op == Operator ("<<" ):
503
- r = parse (tokens , pr )
510
+ r = parse_binary (tokens , pr )
504
511
varname = gensym ()
505
512
l = Function (Var (varname ), Apply (l , Apply (r , Var (varname ))))
506
513
elif op == Operator ("." ):
507
- l = Where (l , parse (tokens , pr ))
514
+ l = Where (l , parse_binary (tokens , pr ))
508
515
elif op == Operator ("?" ):
509
- l = Assert (l , parse (tokens , pr ))
516
+ l = Assert (l , parse_binary (tokens , pr ))
510
517
elif op == Operator ("@" ):
511
518
# TODO: revisit whether to use @ or . for field access
512
- l = Access (l , parse (tokens , pr ))
519
+ l = Access (l , parse_binary (tokens , pr ))
513
520
else :
514
521
assert isinstance (op , Operator )
515
- l = Binop (BinopKind .from_str (op .value ), l , parse (tokens , pr ))
522
+ l = Binop (BinopKind .from_str (op .value ), l , parse_binary (tokens , pr ))
516
523
return l
517
524
518
525
526
+ def parse (tokens : typing .List [Token ]) -> "Object" :
527
+ return parse_binary (tokens , 0 )
528
+
529
+
519
530
@dataclass (eq = True , frozen = True , unsafe_hash = True )
520
531
class Object :
521
532
def __str__ (self ) -> str :
0 commit comments