From 8ffa68d2f005bf46c5748051251386d4044e2d25 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 7 Mar 2024 00:02:35 +0100 Subject: [PATCH] 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. --- crates/aiken-lang/src/parser.rs | 9 ++- crates/aiken-lang/src/parser/expr/mod.rs | 59 +++++++++++++++---- .../snapshots/format_block_logical_expr.snap | 3 +- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/crates/aiken-lang/src/parser.rs b/crates/aiken-lang/src/parser.rs index 451683c2..d27aabc0 100644 --- a/crates/aiken-lang/src/parser.rs +++ b/crates/aiken-lang/src/parser.rs @@ -10,15 +10,14 @@ pub mod pattern; pub mod token; 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}; +pub use annotation::parser as annotation; use chumsky::prelude::*; +pub use definition::parser as definition; use error::ParseError; +pub use expr::parser as expression; use extra::ModuleExtra; +pub use pattern::parser as pattern; pub fn module( src: &str, diff --git a/crates/aiken-lang/src/parser/expr/mod.rs b/crates/aiken-lang/src/parser/expr/mod.rs index 710c0737..d9f6afb2 100644 --- a/crates/aiken-lang/src/parser/expr/mod.rs +++ b/crates/aiken-lang/src/parser/expr/mod.rs @@ -20,6 +20,8 @@ mod tuple; mod var; 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 anonymous_function::parser as anonymous_function; pub use block::parser as block; @@ -37,9 +39,6 @@ pub use tuple::parser as tuple; pub use var::parser as var; pub use when::parser as when; -use super::{error::ParseError, token::Token}; -use crate::{ast, expr::UntypedExpr}; - pub fn parser( sequence: Recursive<'_, Token, UntypedExpr, ParseError>, ) -> impl Parser + '_ { @@ -142,28 +141,62 @@ pub fn pure_expression<'a>( .boxed(); // 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 conjunction = comparison + .clone() + .map(|e| vec![e]) .clone() .then(op.then(comparison).repeated()) - .foldl(|a, (op, b)| UntypedExpr::BinOp { - location: a.location().union(b.location()), - name: op, - left: Box::new(a), - right: Box::new(b), + .foldl(|a, (_op, b)| { + let mut tail = vec![b]; + tail.extend(a); + tail + }) + .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(); + // NOTE: see comment about conjunctions just above. // Disjunction let op = just(Token::VbarVbar).to(ast::BinOp::Or); let disjunction = conjunction .clone() + .map(|e| vec![e]) .then(op.then(conjunction).repeated()) - .foldl(|a, (op, b)| UntypedExpr::BinOp { - location: a.location().union(b.location()), - name: op, - left: Box::new(a), - right: Box::new(b), + .foldl(|a, (_op, b)| { + let mut tail = vec![b]; + tail.extend(a); + tail + }) + .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(); diff --git a/crates/aiken-lang/src/tests/snapshots/format_block_logical_expr.snap b/crates/aiken-lang/src/tests/snapshots/format_block_logical_expr.snap index c73b2863..3c67519a 100644 --- a/crates/aiken-lang/src/tests/snapshots/format_block_logical_expr.snap +++ b/crates/aiken-lang/src/tests/snapshots/format_block_logical_expr.snap @@ -11,6 +11,5 @@ fn bar() { } fn baz() { - a || b && c || d + a || ( b && c || d ) } -