Fix && and || associativity.

Somehow, these have always been right-associative, when the natural thing to expect is left-associativity. It now matters when trying to crawl down binary tree to display them properly.
This commit is contained in:
KtorZ 2024-03-07 00:02:35 +01:00
parent c9ab1aec98
commit 8ffa68d2f0
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
3 changed files with 51 additions and 20 deletions

View File

@ -10,15 +10,14 @@ pub mod pattern;
pub mod token; pub mod token;
mod utils; mod utils;
pub use annotation::parser as annotation;
pub use definition::parser as definition;
pub use expr::parser as expression;
pub use pattern::parser as pattern;
use crate::{ast, line_numbers::LineNumbers}; use crate::{ast, line_numbers::LineNumbers};
pub use annotation::parser as annotation;
use chumsky::prelude::*; use chumsky::prelude::*;
pub use definition::parser as definition;
use error::ParseError; use error::ParseError;
pub use expr::parser as expression;
use extra::ModuleExtra; use extra::ModuleExtra;
pub use pattern::parser as pattern;
pub fn module( pub fn module(
src: &str, src: &str,

View File

@ -20,6 +20,8 @@ mod tuple;
mod var; mod var;
pub mod when; pub mod when;
use super::{error::ParseError, token::Token};
use crate::{ast, expr::UntypedExpr};
pub use and_or_chain::parser as and_or_chain; pub use and_or_chain::parser as and_or_chain;
pub use anonymous_function::parser as anonymous_function; pub use anonymous_function::parser as anonymous_function;
pub use block::parser as block; pub use block::parser as block;
@ -37,9 +39,6 @@ pub use tuple::parser as tuple;
pub use var::parser as var; pub use var::parser as var;
pub use when::parser as when; pub use when::parser as when;
use super::{error::ParseError, token::Token};
use crate::{ast, expr::UntypedExpr};
pub fn parser( pub fn parser(
sequence: Recursive<'_, Token, UntypedExpr, ParseError>, sequence: Recursive<'_, Token, UntypedExpr, ParseError>,
) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ { ) -> impl Parser<Token, UntypedExpr, Error = ParseError> + '_ {
@ -142,28 +141,62 @@ pub fn pure_expression<'a>(
.boxed(); .boxed();
// Conjunction // Conjunction
//
// NOTE: This can be written in a nicer way with `foldl_with` in chumsky =^ 1.0.0.
// DO NOT however try to write this as:
//
// comparison
// .clone()
// .then(op)
// .repeated
// .then(comparison)
// .foldr(...)
//
// This has somehow incredibly slow performances in Chumsky. Hence the approach below.
let op = just(Token::AmperAmper).to(ast::BinOp::And); let op = just(Token::AmperAmper).to(ast::BinOp::And);
let conjunction = comparison let conjunction = comparison
.clone()
.map(|e| vec![e])
.clone() .clone()
.then(op.then(comparison).repeated()) .then(op.then(comparison).repeated())
.foldl(|a, (op, b)| UntypedExpr::BinOp { .foldl(|a, (_op, b)| {
location: a.location().union(b.location()), let mut tail = vec![b];
name: op, tail.extend(a);
left: Box::new(a), tail
right: Box::new(b), })
.map(|xs| {
xs.into_iter()
.reduce(|right, left| UntypedExpr::BinOp {
location: left.location().union(right.location()),
name: ast::BinOp::And,
left: Box::new(left),
right: Box::new(right),
})
.unwrap()
}) })
.boxed(); .boxed();
// NOTE: see comment about conjunctions just above.
// Disjunction // Disjunction
let op = just(Token::VbarVbar).to(ast::BinOp::Or); let op = just(Token::VbarVbar).to(ast::BinOp::Or);
let disjunction = conjunction let disjunction = conjunction
.clone() .clone()
.map(|e| vec![e])
.then(op.then(conjunction).repeated()) .then(op.then(conjunction).repeated())
.foldl(|a, (op, b)| UntypedExpr::BinOp { .foldl(|a, (_op, b)| {
location: a.location().union(b.location()), let mut tail = vec![b];
name: op, tail.extend(a);
left: Box::new(a), tail
right: Box::new(b), })
.map(|xs| {
xs.into_iter()
.reduce(|right, left| UntypedExpr::BinOp {
location: left.location().union(right.location()),
name: ast::BinOp::Or,
left: Box::new(left),
right: Box::new(right),
})
.unwrap()
}) })
.boxed(); .boxed();

View File

@ -11,6 +11,5 @@ fn bar() {
} }
fn baz() { fn baz() {
a || b && c || d a || ( b && c || d )
} }