From 346df47232bb5d6bae4a4339fa5822711990b3b7 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 6 Jul 2023 14:11:32 +0200 Subject: [PATCH] Refactor chain parser The main goal is to make the parser more reusable to be used for when-clauses, instead of the expression parser. A side goal has been to make it more readable by moving the construction of some untyped expression as method on UntypedExpr. Doing so, I got rid of the extra temporary 'ParseArg' type and re-used the generic 'CallArg' instead by simply using an Option as value to get the same semantic as 'ParseArg' (which would distinguish between plain call args and holes). Now the chained parser is in a bit more reusable state. --- crates/aiken-lang/src/ast.rs | 1 + crates/aiken-lang/src/expr.rs | 88 +++++++++++++++++++- crates/aiken-lang/src/parser/chain/call.rs | 19 ++--- crates/aiken-lang/src/parser/chain/mod.rs | 15 +--- crates/aiken-lang/src/parser/expr/chained.rs | 82 +++--------------- crates/aiken-lang/src/parser/expr/mod.rs | 12 +-- 6 files changed, 110 insertions(+), 107 deletions(-) diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs index a2b1ad89..81acaa96 100644 --- a/crates/aiken-lang/src/ast.rs +++ b/crates/aiken-lang/src/ast.rs @@ -475,6 +475,7 @@ impl Constant { } pub type TypedCallArg = CallArg; +pub type ParsedCallArg = CallArg>; #[derive(Debug, Clone, PartialEq, Eq)] pub struct CallArg { diff --git a/crates/aiken-lang/src/expr.rs b/crates/aiken-lang/src/expr.rs index cf66cb82..73bdf354 100644 --- a/crates/aiken-lang/src/expr.rs +++ b/crates/aiken-lang/src/expr.rs @@ -4,9 +4,9 @@ use vec1::Vec1; use crate::{ ast::{ - Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, - DefinitionLocation, IfBranch, Pattern, RecordUpdateSpread, Span, TraceKind, TypedClause, - TypedRecordUpdateArg, UnOp, UntypedClause, UntypedRecordUpdateArg, + self, Annotation, Arg, AssignmentKind, BinOp, ByteArrayFormatPreference, CallArg, + DefinitionLocation, IfBranch, ParsedCallArg, Pattern, RecordUpdateSpread, Span, TraceKind, + TypedClause, TypedRecordUpdateArg, UnOp, UntypedClause, UntypedRecordUpdateArg, }, builtins::void, parser::token::Base, @@ -564,6 +564,88 @@ impl UntypedExpr { } } + pub fn tuple_index(self, index: usize, location: Span) -> Self { + UntypedExpr::TupleIndex { + location: self.location().union(location), + index, + tuple: Box::new(self), + } + } + + pub fn field_access(self, label: String, location: Span) -> Self { + UntypedExpr::FieldAccess { + location: self.location().union(location), + label, + container: Box::new(self), + } + } + + pub fn call(self, args: Vec, location: Span) -> Self { + let mut holes = Vec::new(); + + let args = args + .into_iter() + .enumerate() + .map(|(index, a)| match a { + CallArg { + value: Some(value), + label, + location, + } => CallArg { + value, + label, + location, + }, + CallArg { + value: None, + label, + location, + } => { + let name = format!("{}__{index}", ast::CAPTURE_VARIABLE); + + holes.push(ast::Arg { + location: Span::empty(), + annotation: None, + arg_name: ast::ArgName::Named { + label: name.clone(), + name, + location: Span::empty(), + is_validator_param: false, + }, + tipo: (), + }); + + ast::CallArg { + label, + location, + value: UntypedExpr::Var { + location, + name: format!("{}__{index}", ast::CAPTURE_VARIABLE), + }, + } + } + }) + .collect(); + + let call = UntypedExpr::Call { + location: self.location().union(location), + fun: Box::new(self), + arguments: args, + }; + + if holes.is_empty() { + call + } else { + UntypedExpr::Fn { + location: call.location(), + fn_style: FnStyle::Capture, + arguments: holes, + body: Box::new(call), + return_annotation: None, + } + } + } + pub fn append_in_sequence(self, next: Self) -> Self { let location = Span { start: self.location().start, diff --git a/crates/aiken-lang/src/parser/chain/call.rs b/crates/aiken-lang/src/parser/chain/call.rs index 42e7b222..a60b9abe 100644 --- a/crates/aiken-lang/src/parser/chain/call.rs +++ b/crates/aiken-lang/src/parser/chain/call.rs @@ -1,8 +1,8 @@ use chumsky::prelude::*; -use super::{Chain, ParserArg}; +use super::Chain; use crate::{ - ast, + ast::CallArg, expr::UntypedExpr, parser::{token::Token, ParseError}, }; @@ -15,20 +15,19 @@ pub(crate) fn parser( .then_ignore(just(Token::Colon)) .or_not() .then(expression) - .map_with_span(|(label, value), span| { - ParserArg::Arg(Box::new(ast::CallArg { - label, - location: span, - value, - })) + .map_with_span(|(label, value), location| CallArg { + label, + location, + value: Some(value), }), select! { Token::Name { name } => name } .then_ignore(just(Token::Colon)) .or_not() .then_ignore(select! {Token::DiscardName {name} => name }) - .map_with_span(|label, span| ParserArg::Hole { - location: span, + .map_with_span(|label, location| CallArg { + location, label, + value: None, }), )) .separated_by(just(Token::Comma)) diff --git a/crates/aiken-lang/src/parser/chain/mod.rs b/crates/aiken-lang/src/parser/chain/mod.rs index baad4516..c56ff929 100644 --- a/crates/aiken-lang/src/parser/chain/mod.rs +++ b/crates/aiken-lang/src/parser/chain/mod.rs @@ -1,22 +1,11 @@ -use crate::ast::{self, Span}; -use crate::expr::UntypedExpr; +use crate::ast::{ParsedCallArg, Span}; pub(crate) mod call; pub(crate) mod field_access; pub(crate) mod tuple_index; pub(crate) enum Chain { - Call(Vec, Span), + Call(Vec, Span), FieldAccess(String, Span), TupleIndex(usize, Span), } - -// Parsing a function call into the appropriate structure -#[derive(Debug)] -pub(crate) enum ParserArg { - Arg(Box>), - Hole { - location: Span, - label: Option, - }, -} diff --git a/crates/aiken-lang/src/parser/expr/chained.rs b/crates/aiken-lang/src/parser/expr/chained.rs index 2a12e96d..b09927e3 100644 --- a/crates/aiken-lang/src/parser/expr/chained.rs +++ b/crates/aiken-lang/src/parser/expr/chained.rs @@ -16,13 +16,9 @@ use super::var::parser as var; use super::when::parser as when; use crate::{ - ast::{self, Span}, - expr::{FnStyle, UntypedExpr}, + expr::UntypedExpr, parser::{ - chain::{ - call::parser as call, field_access, tuple_index::parser as tuple_index, Chain, - ParserArg, - }, + chain::{call::parser as call, field_access, tuple_index::parser as tuple_index, Chain}, error::ParseError, token::Token, }, @@ -40,71 +36,17 @@ pub fn parser<'a>( chain_start(sequence, expression) .then(chain.repeated()) .foldl(|expr, chain| match chain { - Chain::Call(args, span) => { - let mut holes = Vec::new(); - - let args = args - .into_iter() - .enumerate() - .map(|(index, a)| match a { - ParserArg::Arg(arg) => *arg, - ParserArg::Hole { location, label } => { - let name = format!("{}__{index}", ast::CAPTURE_VARIABLE); - - holes.push(ast::Arg { - location: Span::empty(), - annotation: None, - arg_name: ast::ArgName::Named { - label: name.clone(), - name, - location: Span::empty(), - is_validator_param: false, - }, - tipo: (), - }); - - ast::CallArg { - label, - location, - value: UntypedExpr::Var { - location, - name: format!("{}__{index}", ast::CAPTURE_VARIABLE), - }, - } - } - }) - .collect(); - - let call = UntypedExpr::Call { - location: expr.location().union(span), - fun: Box::new(expr), - arguments: args, - }; - - if holes.is_empty() { - call - } else { - UntypedExpr::Fn { - location: call.location(), - fn_style: FnStyle::Capture, - arguments: holes, - body: Box::new(call), - return_annotation: None, - } - } - } - - Chain::FieldAccess(label, span) => UntypedExpr::FieldAccess { - location: expr.location().union(span), - label, - container: Box::new(expr), - }, - - Chain::TupleIndex(index, span) => UntypedExpr::TupleIndex { - location: expr.location().union(span), - index, - tuple: Box::new(expr), + Chain::Call(args, span) => expr.call(args, span), + Chain::FieldAccess(label, span) => expr.field_access(label, span), + Chain::TupleIndex(index, span) => expr.tuple_index(index, span), + }) + .then(just(Token::Question).or_not()) + .map_with_span(|(value, token), location| match token { + Some(_) => UntypedExpr::TraceIfFalse { + value: Box::new(value), + location, }, + None => value, }) } diff --git a/crates/aiken-lang/src/parser/expr/mod.rs b/crates/aiken-lang/src/parser/expr/mod.rs index 4f651c0d..1f5cd277 100644 --- a/crates/aiken-lang/src/parser/expr/mod.rs +++ b/crates/aiken-lang/src/parser/expr/mod.rs @@ -53,16 +53,6 @@ pub fn pure_expression<'a>( sequence: Recursive<'a, Token, UntypedExpr, ParseError>, expression: Recursive<'a, Token, UntypedExpr, ParseError>, ) -> impl Parser + 'a { - let chained_debugged = chained(sequence, expression) - .then(just(Token::Question).or_not()) - .map_with_span(|(value, token), location| match token { - Some(_) => UntypedExpr::TraceIfFalse { - value: Box::new(value), - location, - }, - None => value, - }); - // Negate let op = choice(( just(Token::Bang).to(ast::UnOp::Not), @@ -85,7 +75,7 @@ pub fn pure_expression<'a>( let unary = op .map_with_span(|op, span| (op, span)) .repeated() - .then(chained_debugged) + .then(chained(sequence, expression)) .foldr(|(un_op, span), value| UntypedExpr::UnOp { op: un_op, location: span.union(value.location()),