fix a few bugs with the new precedence rules
This commit is contained in:
parent
29a80854a4
commit
9808d3227f
3 changed files with 113 additions and 59 deletions
|
@ -329,7 +329,7 @@ fn tighter(left: (TokenKind, Spaces), right: (TokenKind, Spaces)) -> Tighter {
|
|||
| TokenKind::GreaterEqual => 2,
|
||||
TokenKind::Plus | TokenKind::Minus | TokenKind::Star | TokenKind::Slash => 3,
|
||||
// 4: reserve for `.`
|
||||
_ if PREFIX_TOKENS.contains(kind) => 5,
|
||||
_ if is_prefix_token((kind, spaces)) => 5,
|
||||
_ => return None, // not an infix operator
|
||||
};
|
||||
Some(match kind {
|
||||
|
@ -341,11 +341,11 @@ fn tighter(left: (TokenKind, Spaces), right: (TokenKind, Spaces)) -> Tighter {
|
|||
|
||||
// For unary -, we treat it as having Tight spacing rather than Call, else it would
|
||||
// be allowed to begin function calls.
|
||||
TokenKind::Minus if spaces.pair() == (true, false) => Tightness::Tight(index),
|
||||
TokenKind::Minus if !spaces.are_balanced() => Tightness::Tight(index),
|
||||
|
||||
// For calls, there is a special intermediate level, such that they can sit between
|
||||
// loose operators and tight operators.
|
||||
_ if PREFIX_TOKENS.contains(kind) => Tightness::Call,
|
||||
_ if is_prefix_token((kind, spaces)) => Tightness::Call,
|
||||
|
||||
// For everything else, the usual rules apply.
|
||||
_ => match spaces.pair() {
|
||||
|
@ -366,7 +366,7 @@ fn tighter(left: (TokenKind, Spaces), right: (TokenKind, Spaces)) -> Tighter {
|
|||
|
||||
// When we're inside a call, subsequent arguments must not be slurped into the current
|
||||
// expression, as it would result in calls being parsed as (vec (1 (-1))), which is not correct.
|
||||
if left_tightness == Tightness::Call {
|
||||
if left_tightness == Tightness::Call && right.0 == TokenKind::Minus && !right.1.are_balanced() {
|
||||
return Tighter::Left;
|
||||
}
|
||||
|
||||
|
@ -579,13 +579,15 @@ fn if_expr(p: &mut Parser) -> Closed {
|
|||
p.close(o, NodeKind::If)
|
||||
}
|
||||
|
||||
// TODO: There is a lot of special casing around `-` being both a prefix and an infix token.
|
||||
// Maybe there's a way to simplify it?
|
||||
|
||||
// NOTE: This must be synchronised with the match expression in prefix().
|
||||
const PREFIX_TOKENS: TokenKindSet = TokenKindSet::new(&[
|
||||
TokenKind::Ident,
|
||||
TokenKind::Tag,
|
||||
TokenKind::Number,
|
||||
TokenKind::Color,
|
||||
TokenKind::Minus,
|
||||
TokenKind::Not,
|
||||
TokenKind::LParen,
|
||||
TokenKind::Backslash,
|
||||
|
@ -593,6 +595,10 @@ const PREFIX_TOKENS: TokenKindSet = TokenKindSet::new(&[
|
|||
TokenKind::LBrack,
|
||||
]);
|
||||
|
||||
fn is_prefix_token((kind, spaces): (TokenKind, Spaces)) -> bool {
|
||||
PREFIX_TOKENS.contains(kind) || (kind == TokenKind::Minus && !spaces.are_balanced())
|
||||
}
|
||||
|
||||
fn prefix(p: &mut Parser) -> Closed {
|
||||
let (kind, spaces) = p.peek_with_spaces();
|
||||
match kind {
|
||||
|
@ -602,7 +608,7 @@ fn prefix(p: &mut Parser) -> Closed {
|
|||
TokenKind::Color => one(p, NodeKind::Color),
|
||||
TokenKind::LBrack => list(p),
|
||||
|
||||
TokenKind::Minus if !spaces.right() => unary(p),
|
||||
TokenKind::Minus if spaces.pair() == (true, false) => unary(p),
|
||||
TokenKind::Not => unary(p),
|
||||
TokenKind::LParen => paren(p),
|
||||
TokenKind::Backslash => lambda(p),
|
||||
|
@ -619,9 +625,9 @@ fn prefix(p: &mut Parser) -> Closed {
|
|||
|
||||
_ => {
|
||||
assert!(
|
||||
!PREFIX_TOKENS.contains(p.peek()),
|
||||
"{:?} found in PREFIX_TOKENS",
|
||||
p.peek()
|
||||
!is_prefix_token(p.peek_with_spaces()),
|
||||
"{:?} is not a prefix token",
|
||||
p.peek_with_spaces()
|
||||
);
|
||||
|
||||
let span = p.span();
|
||||
|
@ -651,7 +657,7 @@ fn infix(p: &mut Parser, op: (TokenKind, Spaces)) -> NodeKind {
|
|||
|
||||
TokenKind::Equal => infix_let(p, op),
|
||||
|
||||
_ if PREFIX_TOKENS.contains(op.0) => infix_call(p, op),
|
||||
_ if is_prefix_token(op) => infix_call(p, op),
|
||||
|
||||
_ => panic!("unhandled infix operator {op:?}"),
|
||||
}
|
||||
|
@ -671,7 +677,7 @@ fn infix_binary(p: &mut Parser, op: (TokenKind, Spaces)) -> NodeKind {
|
|||
}
|
||||
|
||||
fn infix_call(p: &mut Parser, mut arg: (TokenKind, Spaces)) -> NodeKind {
|
||||
while PREFIX_TOKENS.contains(p.peek()) {
|
||||
while is_prefix_token(p.peek_with_spaces()) {
|
||||
precedence_parse(p, arg);
|
||||
arg = p.peek_with_spaces();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue