···351351352352353353def parse_assign(tokens: typing.List[Token], p: float = 0) -> "Assign":
354354- assign = parse(tokens, p)
354354+ assign = parse_binary(tokens, p)
355355 if isinstance(assign, Spread):
356356 return Assign(Var("..."), assign)
357357 if not isinstance(assign, Assign):
···371371gensym_reset()
372372373373374374-def parse(tokens: typing.List[Token], p: float = 0) -> "Object":
374374+def parse_unary(tokens: typing.List[Token], p: float) -> "Object":
375375 if not tokens:
376376 raise UnexpectedEOFError("unexpected end of input")
377377 token = tokens.pop(0)
378378 l: Object
379379 if isinstance(token, IntLit):
380380- l = Int(token.value)
380380+ return Int(token.value)
381381 elif isinstance(token, FloatLit):
382382- l = Float(token.value)
382382+ return Float(token.value)
383383 elif isinstance(token, Name):
384384 # TODO: Handle kebab case vars
385385- l = Var(token.value)
385385+ return Var(token.value)
386386 elif isinstance(token, VariantToken):
387387 # It needs to be higher than the precedence of the -> operator so that
388388 # we can match variants in MatchFunction
···390390 # we can use #true() and #false() in boolean expressions
391391 # It needs to be higher than the precedence of juxtaposition so that
392392 # f #true() #false() is parsed as f(TRUE)(FALSE)
393393- l = Variant(token.value, parse(tokens, PS[""].pr + 1))
393393+ return Variant(token.value, parse_binary(tokens, PS[""].pr + 1))
394394 elif isinstance(token, BytesLit):
395395 base = token.base
396396 if base == 85:
···403403 l = Bytes(base64.b16decode(token.value))
404404 else:
405405 raise ParseError(f"unexpected base {base!r} in {token!r}")
406406+ return l
406407 elif isinstance(token, StringLit):
407407- l = String(token.value)
408408+ return String(token.value)
408409 elif token == Operator("..."):
409410 if tokens and isinstance(tokens[0], Name):
410411 name = tokens[0].value
411412 tokens.pop(0)
412412- l = Spread(name)
413413+ return Spread(name)
413414 else:
414414- l = Spread()
415415+ return Spread()
415416 elif token == Operator("|"):
416416- expr = parse(tokens, PS["|"].pr) # TODO: make this work for larger arities
417417+ expr = parse_binary(tokens, PS["|"].pr) # TODO: make this work for larger arities
417418 if not isinstance(expr, Function):
418419 raise ParseError(f"expected function in match expression {expr!r}")
419420 cases = [MatchCase(expr.arg, expr.body)]
420421 while tokens and tokens[0] == Operator("|"):
421422 tokens.pop(0)
422422- expr = parse(tokens, PS["|"].pr) # TODO: make this work for larger arities
423423+ expr = parse_binary(tokens, PS["|"].pr) # TODO: make this work for larger arities
423424 if not isinstance(expr, Function):
424425 raise ParseError(f"expected function in match expression {expr!r}")
425426 cases.append(MatchCase(expr.arg, expr.body))
426426- l = MatchFunction(cases)
427427+ return MatchFunction(cases)
427428 elif isinstance(token, LeftParen):
428429 if isinstance(tokens[0], RightParen):
429430 l = Hole()
430431 else:
431432 l = parse(tokens)
432433 tokens.pop(0)
434434+ return l
433435 elif isinstance(token, LeftBracket):
434436 l = List([])
435437 token = tokens[0]
436438 if isinstance(token, RightBracket):
437439 tokens.pop(0)
438440 else:
439439- l.items.append(parse(tokens, 2))
441441+ l.items.append(parse_binary(tokens, 2))
440442 while not isinstance(tokens.pop(0), RightBracket):
441443 if isinstance(l.items[-1], Spread):
442444 raise ParseError("spread must come at end of list match")
443445 # TODO: Implement .. operator
444444- l.items.append(parse(tokens, 2))
446446+ l.items.append(parse_binary(tokens, 2))
447447+ return l
445448 elif isinstance(token, LeftBrace):
446449 l = Record({})
447450 token = tokens[0]
···456459 # TODO: Implement .. operator
457460 assign = parse_assign(tokens, 2)
458461 l.data[assign.name.name] = assign.value
462462+ return l
459463 elif token == Operator("-"):
460464 # Unary minus
461465 # Precedence was chosen to be higher than binary ops so that -a op
462466 # b is (-a) op b and not -(a op b).
463467 # Precedence was chosen to be higher than function application so that
464468 # -a b is (-a) b and not -(a b).
465465- r = parse(tokens, HIGHEST_PREC + 1)
466466- l = Binop(BinopKind.SUB, Int(0), r)
469469+ r = parse_binary(tokens, HIGHEST_PREC + 1)
470470+ return Binop(BinopKind.SUB, Int(0), r)
467471 else:
468472 raise ParseError(f"unexpected token {token!r}")
469473474474+475475+def parse_binary(tokens: typing.List[Token], p: float) -> "Object":
476476+ l: Object = parse_unary(tokens, p)
470477 while True:
471478 if not tokens:
472479 break
···478485 pl, pr = prec.pl, prec.pr
479486 if pl < p:
480487 break
481481- l = Apply(l, parse(tokens, pr))
488488+ l = Apply(l, parse_binary(tokens, pr))
482489 continue
483490 prec = PS[op.value]
484491 pl, pr = prec.pl, prec.pr
···488495 if op == Operator("="):
489496 if not isinstance(l, Var):
490497 raise ParseError(f"expected variable in assignment {l!r}")
491491- l = Assign(l, parse(tokens, pr))
498498+ l = Assign(l, parse_binary(tokens, pr))
492499 elif op == Operator("->"):
493493- l = Function(l, parse(tokens, pr))
500500+ l = Function(l, parse_binary(tokens, pr))
494501 elif op == Operator("|>"):
495495- l = Apply(parse(tokens, pr), l)
502502+ l = Apply(parse_binary(tokens, pr), l)
496503 elif op == Operator("<|"):
497497- l = Apply(l, parse(tokens, pr))
504504+ l = Apply(l, parse_binary(tokens, pr))
498505 elif op == Operator(">>"):
499499- r = parse(tokens, pr)
506506+ r = parse_binary(tokens, pr)
500507 varname = gensym()
501508 l = Function(Var(varname), Apply(r, Apply(l, Var(varname))))
502509 elif op == Operator("<<"):
503503- r = parse(tokens, pr)
510510+ r = parse_binary(tokens, pr)
504511 varname = gensym()
505512 l = Function(Var(varname), Apply(l, Apply(r, Var(varname))))
506513 elif op == Operator("."):
507507- l = Where(l, parse(tokens, pr))
514514+ l = Where(l, parse_binary(tokens, pr))
508515 elif op == Operator("?"):
509509- l = Assert(l, parse(tokens, pr))
516516+ l = Assert(l, parse_binary(tokens, pr))
510517 elif op == Operator("@"):
511518 # TODO: revisit whether to use @ or . for field access
512512- l = Access(l, parse(tokens, pr))
519519+ l = Access(l, parse_binary(tokens, pr))
513520 else:
514521 assert isinstance(op, Operator)
515515- l = Binop(BinopKind.from_str(op.value), l, parse(tokens, pr))
522522+ l = Binop(BinopKind.from_str(op.value), l, parse_binary(tokens, pr))
516523 return l
524524+525525+526526+def parse(tokens: typing.List[Token]) -> "Object":
527527+ return parse_binary(tokens, 0)
517528518529519530@dataclass(eq=True, frozen=True, unsafe_hash=True)