diff --git a/src/ast/lit.rs b/src/ast/lit.rs index 63ced41..61bb9e1 100644 --- a/src/ast/lit.rs +++ b/src/ast/lit.rs @@ -3,7 +3,7 @@ use std::fmt; use crate::builtin::Builtin; use crate::span::{HasSpan, Span}; -use super::{Expr, Ident, Separated, Space}; +use super::{BoundedSeparated, Expr, Ident, Space}; #[derive(Clone)] pub enum NumLitStr { @@ -129,16 +129,11 @@ impl HasSpan for TableLitElem { /// /// Structure: `'{ s0 elems s1 }` #[derive(Debug, Clone)] -pub struct TableLit { - pub s0: Space, - pub elems: Separated, - pub s1: Space, - pub span: Span, -} +pub struct TableLit(pub BoundedSeparated); impl HasSpan for TableLit { fn span(&self) -> Span { - self.span + self.0.span() } } diff --git a/src/ast/program.rs b/src/ast/program.rs index 2020225..a77abf4 100644 --- a/src/ast/program.rs +++ b/src/ast/program.rs @@ -1,6 +1,6 @@ use crate::span::{HasSpan, Span}; -use super::{Expr, Separated, Space, TableLitElem}; +use super::{BoundedSeparated, Expr, Space, TableLitElem}; #[derive(Debug, Clone)] pub enum Program { @@ -12,12 +12,10 @@ pub enum Program { span: Span, }, - /// Structure: `s0 module s1 elems s2` + /// Structure: `s0 module elems` Module { s0: Space, - s1: Space, - elems: Separated, - s2: Space, + elems: BoundedSeparated, span: Span, }, } diff --git a/src/desugar/basic.rs b/src/desugar/basic.rs index ba2fde0..1b0f4fc 100644 --- a/src/desugar/basic.rs +++ b/src/desugar/basic.rs @@ -1,4 +1,4 @@ -use crate::ast::Separated; +use crate::ast::{BoundedSeparated, Separated}; impl Separated { pub fn desugar_elem(self, desugar_elem: impl Fn(E) -> (E, bool)) -> (Self, bool) { @@ -34,3 +34,26 @@ impl Separated { } } } + +impl BoundedSeparated { + pub fn desugar(self, desugar_elem: impl Fn(E) -> (E, bool)) -> (Self, bool) { + let mut desugared = false; + let mut elems = vec![]; + for (s0, elem, s1) in self.elems { + if desugared { + elems.push((s0, elem, s1)); + } else { + let (elem, elem_desugared) = desugar_elem(elem); + desugared = desugared || elem_desugared; + elems.push((s0, elem, s1)); + } + } + + let new = Self { + elems, + trailing: self.trailing, + span: self.span, + }; + (new, desugared) + } +} diff --git a/src/desugar/call.rs b/src/desugar/call.rs index 690f99e..70cd2c4 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -1,4 +1,4 @@ -use crate::ast::{Call, Expr, Ident, Lit, Separated, Space, TableLit, TableLitElem}; +use crate::ast::{BoundedSeparated, Call, Expr, Ident, Lit, Space, TableLit, TableLitElem}; // TODO Add span for just the parentheses to ast, or limit span to parentheses @@ -29,18 +29,15 @@ impl Call { value: arg, span, }; - let elems = Separated::NonEmpty { - first_elem: call, - last_elems: vec![((Space::empty(span), Space::empty(span)), arg)], + let elems = vec![ + (s0, call, Space::empty(span)), + (Space::empty(span), arg, s2), + ]; + let new = Expr::Lit(Lit::Table(TableLit(BoundedSeparated { + elems, trailing: None, span, - }; - let new = Expr::Lit(Lit::Table(TableLit { - s0, - elems, - s1: s2, - span, - })); + }))); (new, true) } diff --git a/src/desugar/lit.rs b/src/desugar/lit.rs index 348c3c7..4f32a38 100644 --- a/src/desugar/lit.rs +++ b/src/desugar/lit.rs @@ -31,21 +31,8 @@ impl TableLitElem { impl TableLit { pub fn desugar(self) -> (Self, bool) { - let Self { - s0, - elems, - s1, - span, - } = self; - - let (elems, desugared) = elems.desugar_elem(|e| e.desugar()); - let new = Self { - s0, - elems, - s1, - span, - }; - (new, desugared) + let (elems, desugared) = self.0.desugar(|e| e.desugar()); + (Self(elems), desugared) } } diff --git a/src/desugar/program.rs b/src/desugar/program.rs index 7960cbc..50b11eb 100644 --- a/src/desugar/program.rs +++ b/src/desugar/program.rs @@ -9,24 +9,12 @@ impl Program { (new, desugared) } - Self::Module { - s0, - s1, - elems, - s2, - span, - } => { - // `s0 module s1 elems s2` - // -> `s0 '{ s1 elems s2 } empty` - let table = TableLit { - s0: s1, - elems, - s1: s2, - span, - }; + Self::Module { s0, elems, span } => { + // `s0 module elems` + // -> `s0 table` let new = Self::Expr { s0, - expr: Expr::Lit(Lit::Table(table)), + expr: Expr::Lit(Lit::Table(TableLit(elems))), s1: Space::empty(span), span, }; diff --git a/src/parser/basic.rs b/src/parser/basic.rs index 300e953..2c8254d 100644 --- a/src/parser/basic.rs +++ b/src/parser/basic.rs @@ -83,11 +83,11 @@ pub fn separated_by( .boxed() } -pub fn bounded_separated( +pub fn bounded_separated( space: impl Parser + Clone + 'static, - start: impl Parser + 'static, - end: impl Parser + 'static, - separator: impl Parser + 'static, + start: impl Parser + 'static, + end: impl Parser + 'static, + separator: impl Parser + 'static, elem: impl Parser + Clone + 'static, ) -> EParser> { start diff --git a/src/parser/lit.rs b/src/parser/lit.rs index 0bdf12a..6b09982 100644 --- a/src/parser/lit.rs +++ b/src/parser/lit.rs @@ -7,7 +7,7 @@ use crate::ast::{ }; use crate::builtin::Builtin; -use super::basic::{separated_by, EParser, Error}; +use super::basic::{bounded_separated, EParser, Error}; fn builtin_lit() -> impl Parser { just('\'').ignore_then(choice(( @@ -154,20 +154,14 @@ fn table_lit( space: EParser, table_lit_elem: EParser, ) -> impl Parser { - let separator = space.clone().then_ignore(just(',')).then(space.clone()); - let trailing_separator = space.clone().then_ignore(just(',')); - - space - .clone() - .then(separated_by(table_lit_elem, separator, trailing_separator)) - .then(space) - .delimited_by(just("'{"), just('}')) - .map_with_span(|((s0, elems), s1), span| TableLit { - s0, - elems, - s1, - span, - }) + bounded_separated( + space, + just("'{").to(()), + just('}').to(()), + just(',').to(()), + table_lit_elem, + ) + .map(TableLit) } pub fn lit(space: EParser, table_lit_elem: EParser) -> EParser { diff --git a/src/parser/program.rs b/src/parser/program.rs index 0b46f94..96c3cab 100644 --- a/src/parser/program.rs +++ b/src/parser/program.rs @@ -4,7 +4,7 @@ use chumsky::prelude::*; use crate::ast::{Expr, Program, Space, TableLitElem}; -use super::basic::{separated_by, EParser}; +use super::basic::{bounded_separated, EParser}; pub fn program( space: EParser, @@ -17,21 +17,17 @@ pub fn program( .then(space.clone()) .map_with_span(|((s0, expr), s1), span| Program::Expr { s0, expr, s1, span }); - let separator = space.clone().then_ignore(just(',')).then(space.clone()); - let trailing_separator = space.clone().then_ignore(just(',')); let module = space .clone() .then_ignore(text::keyword("module")) - .then(space.clone()) - .then(separated_by(table_lit_elem, separator, trailing_separator)) - .then(space.clone()) - .map_with_span(|(((s0, s1), elems), s2), span| Program::Module { - s0, - s1, - elems, - s2, - span, - }); + .then(bounded_separated( + space, + empty(), + empty(), + just(',').to(()), + table_lit_elem, + )) + .map_with_span(|(s0, elems), span| Program::Module { s0, elems, span }); module.or(lit).boxed() } diff --git a/src/pretty/call.rs b/src/pretty/call.rs index 84d2b5b..6cf26fc 100644 --- a/src/pretty/call.rs +++ b/src/pretty/call.rs @@ -2,7 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; use crate::ast::Call; -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Call { +impl<'a, D> Pretty<'a, D> for Call +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Self::Arg { diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index 7919963..ddf7634 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -22,7 +22,11 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for BinOp { } } -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { +impl<'a, D> Pretty<'a, D> for Expr +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Self::Lit(lit) => lit.pretty(allocator), diff --git a/src/pretty/field.rs b/src/pretty/field.rs index ce5b28f..eb547f0 100644 --- a/src/pretty/field.rs +++ b/src/pretty/field.rs @@ -2,7 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; use crate::ast::Field; -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Field { +impl<'a, D> Pretty<'a, D> for Field +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Self::Access { diff --git a/src/pretty/func_def.rs b/src/pretty/func_def.rs index 6fd8140..dce23e6 100644 --- a/src/pretty/func_def.rs +++ b/src/pretty/func_def.rs @@ -2,7 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; use crate::ast::FuncDef; -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for FuncDef { +impl<'a, D> Pretty<'a, D> for FuncDef +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Self::AnonNoArg { diff --git a/src/pretty/lit.rs b/src/pretty/lit.rs index 45dd034..84f3055 100644 --- a/src/pretty/lit.rs +++ b/src/pretty/lit.rs @@ -2,8 +2,6 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; use crate::ast::{Lit, NumLit, StringLit, StringLitElem, TableLit, TableLitElem}; -use super::NEST_DEPTH; - impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for NumLit { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { allocator.text(format!("{self:?}")) @@ -32,7 +30,11 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for StringLit { } } -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableLitElem { +impl<'a, D> Pretty<'a, D> for TableLitElem +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Self::Positional(expr) => expr.pretty(allocator), @@ -50,23 +52,27 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableLitElem { } } -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableLit { +impl<'a, D> Pretty<'a, D> for TableLit +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { - self.elems - .pretty( - allocator, - |e| allocator.line().append(e.pretty(allocator)), - |(s0, s1)| allocator.text(","), - |s| allocator.text(","), - ) - .nest(NEST_DEPTH) - .append(allocator.line()) - .enclose(allocator.text("'{"), allocator.text("}")) - .group() + self.0.pretty( + allocator, + allocator.text("'{"), + allocator.text("}"), + allocator.text(","), + |e| e.pretty(allocator), + ) } } -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Lit { +impl<'a, D> Pretty<'a, D> for Lit +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Self::Nil(_) => allocator.text("nil"), diff --git a/src/pretty/program.rs b/src/pretty/program.rs index 20c5cb1..1ff7863 100644 --- a/src/pretty/program.rs +++ b/src/pretty/program.rs @@ -2,7 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; use crate::ast::Program; -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Program { +impl<'a, D> Pretty<'a, D> for Program +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Self::Expr { @@ -11,22 +15,19 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Program { s1, span: _, } => expr.pretty(allocator), - Self::Module { - s0, - s1, - elems, - s2, - span: _, - } => allocator - .text("module") - .append(allocator.line()) - .append(allocator.line()) - .append(elems.pretty( - allocator, - |e| e.pretty(allocator), - |(s0, s1)| allocator.text(",").append(allocator.line()), - |s| allocator.text(","), - )), + + Self::Module { s0, elems, span: _ } => { + allocator.text("module").append(allocator.line()).append( + allocator + .intersperse( + elems.elems.into_iter().map(|(s0, elem, s1)| { + allocator.line().append(elem.pretty(allocator)) + }), + allocator.text(","), + ) + .append(elems.trailing.map(|s| allocator.text(","))), + ) + } } } } diff --git a/src/pretty/table_constr.rs b/src/pretty/table_constr.rs index 5c9a058..704ab3e 100644 --- a/src/pretty/table_constr.rs +++ b/src/pretty/table_constr.rs @@ -4,7 +4,11 @@ use crate::ast::{TableConstr, TableConstrElem}; use super::NEST_DEPTH; -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableConstrElem { +impl<'a, D> Pretty<'a, D> for TableConstrElem +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Self::Lit(lit) => lit.pretty(allocator), @@ -25,7 +29,11 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableConstrElem { } } -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableConstr { +impl<'a, D> Pretty<'a, D> for TableConstr +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { self.elems .pretty( diff --git a/src/pretty/table_destr.rs b/src/pretty/table_destr.rs index 50fab7b..795bfa2 100644 --- a/src/pretty/table_destr.rs +++ b/src/pretty/table_destr.rs @@ -38,7 +38,11 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePattern { } } -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableDestr { +impl<'a, D> Pretty<'a, D> for TableDestr +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { // TODO Handle spaces self.local diff --git a/src/pretty/var.rs b/src/pretty/var.rs index a3b5418..662b34e 100644 --- a/src/pretty/var.rs +++ b/src/pretty/var.rs @@ -2,7 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; use crate::ast::Var; -impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Var { +impl<'a, D> Pretty<'a, D> for Var +where + D: DocAllocator<'a>, + D::Doc: Clone, +{ fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Self::Access {