private Expr ParseLet() { Span prev = CurrentSpan(); Consume(TokenType.Let); Expr.Variable variable = ParseVar(); Consume("=", TokenType.Operator); Expr expr = ParseExpr(); return(new Expr.Assignment(variable, expr, prev.Combine(expr.Span))); }
public string Visit(Expr.Variable variable) { return($"`{variable.Name}`"); }
private Expr ParseExpr(int minBp = 0) { Expr item; if (Check(TokenType.Operator)) { // Prefix operator Token op = Consume(TokenType.Operator); int rBp = _ops.PrefixBp(op.Contents !, op.Span); Expr opE = new Expr.Variable($"@({op.Contents})", true, op.Span); Expr rhs = ParseExpr(rBp); item = new Expr.Application(opE, rhs, op.Span.Combine(rhs.Span)); } else { item = ParseExprItem(); } while (true) { if (IsAtEnd() || Check(TokenType.LineBreak) || Check(TokenType.RParen)) { break; } Span span = CurrentSpan(); Token op = Check(TokenType.Operator) ? Peek() : new Token(_fnApp, TokenType.Operator, item.Span.Between(span)); if (op.Contents != _fnApp) { // Possible postfix operator if (_ops.Postfix.ContainsKey(op.Contents !) && // If it's contained as a postfix op... // ... and it isn't a binary operator, or it's at the end of a line/eof/paren (!_ops.Binary.ContainsKey(op.Contents !) || IsAtEnd() || Check(TokenType.LineBreak) || Check(TokenType.RParen))) { // then it's a postfix operator! var lBpPost = _ops.PostfixBp(op.Contents !, op.Span); if (lBpPost < minBp) { break; } Advance(); Expr opE = new Expr.Variable($"({op.Contents!})@", true, op.Span); item = new Expr.Application(opE, item, item.Span.Combine(opE.Span)); continue; } } var(lBp, rBp) = _ops.BinaryBp(op.Contents !, op.Span); if (lBp < minBp) { break; } if (op.Contents != _fnApp) { Advance(); } Expr rhs = ParseExpr(rBp); Span sp = item.Span.Combine(rhs.Span); if (op.Contents == _fnApp) { item = new Expr.Application(item, rhs, sp); } else { Expr opE = new Expr.Variable(op.Contents !, true, op.Span); item = new Expr.Application(new Expr.Application(opE, item, sp), rhs, sp); } } return(item); }