Compare commits

...
Sign in to create a new pull request.

28 commits

Author SHA1 Message Date
802d776f29 Include trailing newline in pretty print output 2022-11-22 23:14:07 +01:00
af4311ba98 Remove named nils as early as possible 2022-11-22 21:56:50 +01:00
f6c9835e29 Hide warnings in pretty module for now 2022-11-22 21:50:20 +01:00
736174d470 Desugar away named nil in table literals 2022-11-22 17:49:12 +01:00
39099037a5 Remove unused functions 2022-11-22 17:39:56 +01:00
f8fa044259 Desugar all expressions 2022-11-22 17:39:02 +01:00
26dc3c3469 Desugar all function definitions 2022-11-22 17:27:06 +01:00
40c28d9496 Simplify creating Var 2022-11-22 17:14:52 +01:00
6f7683ad1e Simplify creating Field 2022-11-22 17:06:56 +01:00
009be99aaa Simplify creating Call 2022-11-22 16:55:27 +01:00
78d08968eb Move BoundedSeparated helper functions into ast 2022-11-22 16:45:31 +01:00
58106c4c5a Simplify creating TableConstrElem 2022-11-22 16:44:33 +01:00
c191486864 Simplify creating TableLitElem 2022-11-22 16:35:16 +01:00
45caafdc38 Simplify creating Lit 2022-11-22 16:29:31 +01:00
fafc567447 Simplify creating Expr 2022-11-22 16:29:21 +01:00
42369628b6 Simplify boxing Expr 2022-11-22 15:32:23 +01:00
5a977e6dde Simplify creating TableLit and TableConstr 2022-11-22 15:21:40 +01:00
c769d9e16f Simplify creating BoundedSeparated
Along with this comes the decision to no longer track whitespace and
comments across desugarings in most cases. The main reason for this
decision is that not having to track whitespace simplifies the code and
reasoning necessary.

While implementing desugarings, I also realized that the current comment
model doesn't let me accurately track whitespace across desugarings. I'm
fairly sure I haven't yet found a good model for whitespace and
comments. Once I find one, adding pretty printing support for those
should hopefully be easy though.
2022-11-22 15:21:35 +01:00
d6a0bbf2af Desugar simple anonymous function definitions 2022-11-22 12:56:09 +01:00
830ffa92c4 Desugar table destructuring 2022-11-22 10:32:27 +01:00
d4797c5894 Simplify creating string literal from ident 2022-11-22 10:32:17 +01:00
af6c171eb4 Desugar table constructors 2022-11-22 09:44:29 +01:00
74d1f640b5 Fix pretty printing of empty BoundedSeparated 2022-11-22 09:21:44 +01:00
94ea196933 Remove Separated 2022-11-22 00:00:43 +01:00
198f56226e Switch TablePattern to BoundedSeparated 2022-11-21 23:57:58 +01:00
0e9cfd67c2 Switch TablConstr to BoundedSeparated 2022-11-21 23:54:40 +01:00
e3fa3500d4 Switch TableLit and Program to BoundedSeparated 2022-11-21 23:54:30 +01:00
a1867fdc4e Add BoundedSeparated with parser and printer
This type should be able to replace Separated (with a bit of effort).

The hope is that this type is a better representation for table-like
syntax with optional trailing delimiter that will let me remove_map
elements without too much difficulty. This is necessary for desugaring
table constructors.
2022-11-21 22:56:50 +01:00
44 changed files with 1019 additions and 660 deletions

View file

@ -2,6 +2,8 @@ use std::fmt;
use crate::span::{HasSpan, Span}; use crate::span::{HasSpan, Span};
use super::{TableConstr, TableConstrElem, TableLit, TableLitElem};
#[derive(Clone)] #[derive(Clone)]
pub enum Line { pub enum Line {
Empty, Empty,
@ -37,17 +39,6 @@ impl Space {
span, span,
} }
} }
pub fn then(mut self, other: Self) -> Self {
self.lines.extend(other.lines);
self.span = self.span.join(other.span);
self
}
pub fn then_line(mut self, line: Line) -> Self {
self.lines.push(line);
self
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -78,21 +69,76 @@ impl HasSpan for Ident {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Separated<E, S1, S2> { pub struct BoundedSeparated<E> {
Empty(Span), pub elems: Vec<(Space, E, Space)>,
NonEmpty { pub trailing: Option<Space>,
first_elem: E, pub span: Span,
last_elems: Vec<(S1, E)>,
trailing: Option<S2>,
span: Span,
},
} }
impl<E, S1, S2> HasSpan for Separated<E, S1, S2> { impl<E> HasSpan for BoundedSeparated<E> {
fn span(&self) -> Span { fn span(&self) -> Span {
match self { self.span
Self::Empty(span) => *span, }
Self::NonEmpty { span, .. } => *span, }
}
impl<E> BoundedSeparated<E> {
pub fn new(span: Span) -> Self {
Self {
elems: vec![],
trailing: None,
span,
}
}
pub fn then(mut self, elem: E) -> Self {
self.elems
.push((Space::empty(self.span), elem, Space::empty(self.span)));
self
}
pub fn map<E2>(self, f: impl Fn(E) -> E2) -> BoundedSeparated<E2> {
let elems = self
.elems
.into_iter()
.map(|(s0, e, s1)| (s0, f(e), s1))
.collect::<Vec<_>>();
BoundedSeparated {
elems,
trailing: self.trailing,
span: self.span,
}
}
pub fn remove_map<E1, E2>(
self,
f: impl Fn(E) -> Result<E1, E2>,
) -> (BoundedSeparated<E1>, Vec<(Space, E2, Space)>) {
let mut kept = vec![];
let mut removed = vec![];
for (s0, elem, s1) in self.elems {
match f(elem) {
Ok(elem) => kept.push((s0, elem, s1)),
Err(elem) => removed.push((s0, elem, s1)),
}
}
let new = BoundedSeparated {
elems: kept,
trailing: self.trailing,
span: self.span,
};
(new, removed)
}
}
impl BoundedSeparated<TableLitElem> {
pub fn table_lit(self) -> TableLit {
TableLit(self)
}
}
impl BoundedSeparated<TableConstrElem> {
pub fn table_constr(self) -> TableConstr {
TableConstr(self)
} }
} }

View file

@ -46,3 +46,38 @@ impl HasSpan for Call {
} }
} }
} }
impl Call {
pub fn arg(base: Box<Expr>, arg: Box<Expr>, span: Span) -> Self {
Self::Arg {
expr: base,
s0: Space::empty(span),
s1: Space::empty(span),
arg,
s2: Space::empty(span),
span,
}
}
pub fn no_arg(base: Box<Expr>, span: Span) -> Self {
Self::NoArg {
expr: base,
s0: Space::empty(span),
s1: Space::empty(span),
span,
}
}
pub fn constr(base: Box<Expr>, constr: TableConstr, span: Span) -> Self {
Self::Constr {
expr: base,
s0: Space::empty(span),
constr,
span,
}
}
pub fn expr(self) -> Expr {
Expr::Call(self)
}
}

View file

@ -242,3 +242,9 @@ impl HasSpan for Expr {
} }
} }
} }
impl Expr {
pub fn boxed(self) -> Box<Self> {
Box::new(self)
}
}

View file

@ -67,3 +67,34 @@ impl HasSpan for Field {
} }
} }
} }
impl Field {
pub fn access(base: Box<Expr>, index: Box<Expr>, span: Span) -> Self {
Self::Access {
expr: base,
s0: Space::empty(span),
s1: Space::empty(span),
index,
s2: Space::empty(span),
span,
}
}
pub fn assign(base: Box<Expr>, index: Box<Expr>, value: Box<Expr>, span: Span) -> Self {
Self::Assign {
expr: base,
s0: Space::empty(span),
s1: Space::empty(span),
index,
s2: Space::empty(span),
s3: Space::empty(span),
s4: Space::empty(span),
value,
span,
}
}
pub fn expr(self) -> Expr {
Expr::Field(self)
}
}

View file

@ -99,3 +99,41 @@ impl HasSpan for FuncDef {
} }
} }
} }
impl FuncDef {
pub fn anon_no_arg(body: Box<Expr>, span: Span) -> Self {
Self::AnonNoArg {
s0: Space::empty(span),
s1: Space::empty(span),
s2: Space::empty(span),
body,
span,
}
}
pub fn anon_arg(arg: Ident, body: Box<Expr>, span: Span) -> Self {
Self::AnonArg {
s0: Space::empty(span),
s1: Space::empty(span),
arg,
s2: Space::empty(span),
s3: Space::empty(span),
body,
span,
}
}
pub fn anon_destr(pattern: TablePattern, body: Box<Expr>, span: Span) -> Self {
Self::AnonDestr {
s0: Space::empty(span),
pattern,
s1: Space::empty(span),
body,
span,
}
}
pub fn expr(self) -> Expr {
Expr::FuncDef(self)
}
}

View file

@ -3,7 +3,7 @@ use std::fmt;
use crate::builtin::Builtin; use crate::builtin::Builtin;
use crate::span::{HasSpan, Span}; use crate::span::{HasSpan, Span};
use super::{Expr, Ident, Separated, Space}; use super::{BoundedSeparated, Expr, Ident, Space};
#[derive(Clone)] #[derive(Clone)]
pub enum NumLitStr { pub enum NumLitStr {
@ -93,6 +93,19 @@ pub struct StringLit {
pub span: Span, pub span: Span,
} }
impl StringLit {
pub fn from_ident(ident: Ident) -> Self {
Self {
elems: vec![StringLitElem::Plain(ident.name)],
span: ident.span,
}
}
pub fn lit(self) -> Lit {
Lit::String(self)
}
}
impl HasSpan for StringLit { impl HasSpan for StringLit {
fn span(&self) -> Span { fn span(&self) -> Span {
self.span self.span
@ -125,20 +138,31 @@ impl HasSpan for TableLitElem {
} }
} }
/// `'{ a, foo: b }` impl TableLitElem {
/// pub fn named(name: Ident, value: Box<Expr>, span: Span) -> Self {
/// Structure: `'{ s0 elems s1 }` Self::Named {
#[derive(Debug, Clone)] name,
pub struct TableLit { s0: Space::empty(span),
pub s0: Space, s1: Space::empty(span),
pub elems: Separated<TableLitElem, (Space, Space), Space>, value,
pub s1: Space, span,
pub span: Span, }
}
} }
/// `'{ a, foo: b }`
#[derive(Debug, Clone)]
pub struct TableLit(pub BoundedSeparated<TableLitElem>);
impl HasSpan for TableLit { impl HasSpan for TableLit {
fn span(&self) -> Span { fn span(&self) -> Span {
self.span self.0.span()
}
}
impl TableLit {
pub fn lit(self) -> Lit {
Lit::Table(self)
} }
} }
@ -196,3 +220,9 @@ impl HasSpan for Lit {
} }
} }
} }
impl Lit {
pub fn expr(self) -> Expr {
Expr::Lit(self)
}
}

View file

@ -1,6 +1,6 @@
use crate::span::{HasSpan, Span}; use crate::span::{HasSpan, Span};
use super::{Expr, Separated, Space, TableLitElem}; use super::{BoundedSeparated, Expr, Space, TableLitElem};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Program { pub enum Program {
@ -12,12 +12,10 @@ pub enum Program {
span: Span, span: Span,
}, },
/// Structure: `s0 module s1 elems s2` /// Structure: `s0 module elems`
Module { Module {
s0: Space, s0: Space,
s1: Space, elems: BoundedSeparated<TableLitElem>,
elems: Separated<TableLitElem, (Space, Space), Space>,
s2: Space,
span: Span, span: Span,
}, },
} }

View file

@ -1,6 +1,6 @@
use crate::span::{HasSpan, Span}; use crate::span::{HasSpan, Span};
use super::{Expr, Separated, Space, TableLitElem}; use super::{BoundedSeparated, Expr, Ident, Space, TableLitElem};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum TableConstrElem { pub enum TableConstrElem {
@ -30,19 +30,28 @@ impl HasSpan for TableConstrElem {
} }
} }
/// `{ a, b, foo: c, [d]: e }` impl TableConstrElem {
/// pub fn positional(value: Box<Expr>) -> Self {
/// Structure: `{ s0 elems s1 }` Self::Lit(TableLitElem::Positional(value))
#[derive(Debug, Clone)] }
pub struct TableConstr {
pub s0: Space, pub fn named(name: Ident, value: Box<Expr>, span: Span) -> Self {
pub elems: Separated<TableConstrElem, (Space, Space), Space>, Self::Lit(TableLitElem::named(name, value, span))
pub s1: Space, }
pub span: Span,
} }
/// `{ a, b, foo: c, [d]: e }`
#[derive(Debug, Clone)]
pub struct TableConstr(pub BoundedSeparated<TableConstrElem>);
impl HasSpan for TableConstr { impl HasSpan for TableConstr {
fn span(&self) -> Span { fn span(&self) -> Span {
self.span self.0.span()
}
}
impl TableConstr {
pub fn expr(self) -> Expr {
Expr::TableConstr(self)
} }
} }

View file

@ -1,6 +1,6 @@
use crate::span::{HasSpan, Span}; use crate::span::{HasSpan, Span};
use super::{Expr, Ident, Separated, Space}; use super::{BoundedSeparated, Expr, Ident, Space};
// TODO Make table patterns recursive // TODO Make table patterns recursive
@ -34,16 +34,11 @@ impl HasSpan for TablePatternElem {
/// ///
/// Structure: `{ s0 elems s1 }` /// Structure: `{ s0 elems s1 }`
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TablePattern { pub struct TablePattern(pub BoundedSeparated<TablePatternElem>);
pub s0: Space,
pub elems: Separated<TablePatternElem, (Space, Space), Space>,
pub s1: Space,
pub span: Span,
}
impl HasSpan for TablePattern { impl HasSpan for TablePattern {
fn span(&self) -> Span { fn span(&self) -> Span {
self.span self.0.span()
} }
} }
@ -66,3 +61,26 @@ impl HasSpan for TableDestr {
self.span self.span
} }
} }
impl TableDestr {
pub fn new(local: bool, pattern: TablePattern, value: Box<Expr>, span: Span) -> Self {
let local = if local {
Some(Space::empty(span))
} else {
None
};
Self {
local,
pattern,
s0: Space::empty(span),
s1: Space::empty(span),
value,
span,
}
}
pub fn expr(self) -> Expr {
Expr::TableDestr(self)
}
}

View file

@ -56,3 +56,54 @@ impl HasSpan for Var {
} }
} }
} }
impl Var {
pub fn access(index: Box<Expr>, span: Span) -> Self {
Self::Access {
s0: Space::empty(span),
index,
s1: Space::empty(span),
span,
}
}
pub fn assign(local: bool, index: Box<Expr>, value: Box<Expr>, span: Span) -> Self {
let local = if local {
Some(Space::empty(span))
} else {
None
};
Self::Assign {
local,
s0: Space::empty(span),
index,
s1: Space::empty(span),
s2: Space::empty(span),
s3: Space::empty(span),
value,
span,
}
}
pub fn assign_ident(local: bool, name: Ident, value: Box<Expr>, span: Span) -> Self {
let local = if local {
Some(Space::empty(span))
} else {
None
};
Self::AssignIdent {
local,
name,
s0: Space::empty(span),
s1: Space::empty(span),
value,
span,
}
}
pub fn expr(self) -> Expr {
Expr::Var(self)
}
}

View file

@ -12,6 +12,21 @@ pub enum Builtin {
Scope, Scope,
Arg, Arg,
Destructure, Destructure,
Neg,
Not,
Mul,
Div,
Mod,
Add,
Sub,
Eq,
Ne,
Gt,
Ge,
Lt,
Le,
And,
Or,
} }
impl fmt::Debug for Builtin { impl fmt::Debug for Builtin {
@ -26,6 +41,21 @@ impl fmt::Debug for Builtin {
Self::Scope => write!(f, "'scope"), Self::Scope => write!(f, "'scope"),
Self::Arg => write!(f, "'arg"), Self::Arg => write!(f, "'arg"),
Self::Destructure => write!(f, "'destructure"), Self::Destructure => write!(f, "'destructure"),
Self::Neg => write!(f, "'neg"),
Self::Not => write!(f, "'not"),
Self::Mul => write!(f, "'mul"),
Self::Div => write!(f, "'div"),
Self::Mod => write!(f, "'mod"),
Self::Add => write!(f, "'add"),
Self::Sub => write!(f, "'sub"),
Self::Eq => write!(f, "'eq"),
Self::Ne => write!(f, "'ne"),
Self::Gt => write!(f, "'gt"),
Self::Ge => write!(f, "'ge"),
Self::Lt => write!(f, "'lt"),
Self::Le => write!(f, "'le"),
Self::And => write!(f, "'and"),
Self::Or => write!(f, "'or"),
} }
} }
} }

View file

@ -2,6 +2,9 @@ mod basic;
mod call; mod call;
mod expr; mod expr;
mod field; mod field;
mod func_def;
mod lit; mod lit;
mod program; mod program;
mod table_constr;
mod table_destr;
mod var; mod var;

View file

@ -1,36 +1,24 @@
use crate::ast::Separated; use crate::ast::BoundedSeparated;
impl<E, S1, S2> Separated<E, S1, S2> { impl<E> BoundedSeparated<E> {
pub fn desugar_elem(self, desugar_elem: impl Fn(E) -> (E, bool)) -> (Self, bool) { pub fn desugar(self, desugar_elem: impl Fn(E) -> (E, bool)) -> (Self, bool) {
match self { let mut desugared = false;
Self::Empty(span) => (Self::Empty(span), false), let mut elems = vec![];
for (s0, elem, s1) in self.elems {
Self::NonEmpty {
first_elem,
last_elems,
trailing,
span,
} => {
let (new_first_elem, mut desugared) = desugar_elem(first_elem);
let mut new_last_elems = vec![];
for (separator, elem) in last_elems {
if desugared { if desugared {
new_last_elems.push((separator, elem)); elems.push((s0, elem, s1));
} else { } else {
let (elem, elem_desugared) = desugar_elem(elem); let (elem, elem_desugared) = desugar_elem(elem);
desugared = desugared || elem_desugared; desugared = desugared || elem_desugared;
new_last_elems.push((separator, elem)); elems.push((s0, elem, s1));
} }
} }
let new = Self::NonEmpty { let new = Self {
first_elem: new_first_elem, elems,
last_elems: new_last_elems, trailing: self.trailing,
trailing, span: self.span,
span,
}; };
(new, desugared) (new, desugared)
} }
}
}
} }

View file

@ -1,4 +1,4 @@
use crate::ast::{Call, Expr, Ident, Lit, Separated, Space, TableLit, TableLitElem}; use crate::ast::{BoundedSeparated, Call, Expr, Ident, Lit, TableLitElem};
// TODO Add span for just the parentheses to ast, or limit span to parentheses // TODO Add span for just the parentheses to ast, or limit span to parentheses
@ -7,74 +7,37 @@ impl Call {
match self { match self {
Self::Arg { Self::Arg {
expr, expr,
s0, s0: _,
s1, s1: _,
arg, arg,
s2, s2: _,
span, span,
} => { } => {
// `expr s0 ( s1 arg s2 )` let new = BoundedSeparated::new(span)
// -> `'{ s0 call: expr, arg: s1 arg s2 }` .then(TableLitElem::named(Ident::new("call", span), expr, span))
let call = TableLitElem::Named { .then(TableLitElem::named(Ident::new("arg", span), arg, span))
name: Ident::new("call", span), .table_lit();
s0: Space::empty(span), (new.lit().expr(), true)
s1: Space::empty(span),
value: expr,
span,
};
let arg = TableLitElem::Named {
name: Ident::new("arg", span),
s0: Space::empty(span),
s1,
value: arg,
span,
};
let elems = Separated::NonEmpty {
first_elem: call,
last_elems: vec![((Space::empty(span), Space::empty(span)), arg)],
trailing: None,
span,
};
let new = Expr::Lit(Lit::Table(TableLit {
s0,
elems,
s1: s2,
span,
}));
(new, true)
} }
Self::NoArg { expr, s0, s1, span } => { Self::NoArg {
// `expr s0 ( s1 )`
// -> `expr s0 ( s1 nil )`
let new = Expr::Call(Self::Arg {
expr, expr,
s0, s0: _,
s1, s1: _,
arg: Box::new(Expr::Lit(Lit::Nil(span))),
s2: Space::empty(span),
span, span,
}); } => {
(new, true) let new = Self::arg(expr, Lit::Nil(span).expr().boxed(), span);
(new.expr(), true)
} }
Self::Constr { Self::Constr {
expr, expr,
s0, s0: _,
constr, constr,
span, span,
} => { } => {
// `expr s0 {..}` let new = Self::arg(expr, constr.expr().boxed(), span);
// -> `expr s0 ( {..} )` (new.expr(), true)
let new = Expr::Call(Self::Arg {
expr,
s0,
s1: Space::empty(span),
arg: Box::new(Expr::TableConstr(constr)),
s2: Space::empty(span),
span,
});
(new, true)
} }
} }
} }

View file

@ -1,84 +1,78 @@
use crate::ast::Expr; use crate::ast::{BinOp, BoundedSeparated, Call, Expr, Lit, TableConstrElem};
use crate::builtin::Builtin;
impl Expr { impl Expr {
pub fn desugar(self) -> (Self, bool) { pub fn desugar(self) -> (Self, bool) {
match self { match self {
Self::Lit(lit) => { Self::Lit(lit) => {
let (lit, desugared) = lit.desugar(); let (lit, desugared) = lit.desugar();
(Self::Lit(lit), desugared) (lit.expr(), desugared)
} }
Self::Call(call) => call.desugar(), Self::Call(call) => call.desugar(),
Self::Field(field) => field.desugar(), Self::Field(field) => field.desugar(),
Self::Var(var) => var.desugar(), Self::Var(var) => var.desugar(),
Self::TableConstr(constr) => constr.desugar(),
Self::TableConstr(constr) => (Self::TableConstr(constr), false), // TODO Implement Self::TableDestr(destr) => destr.desugar(),
Self::TableDestr(destr) => (Self::TableDestr(destr), false), // TODO Implement Self::FuncDef(def) => def.desugar(),
Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement
Self::Paren { Self::Paren {
s0, s0: _,
inner, inner,
s1, s1: _,
span, span: _,
} => ( } => (*inner, true),
Self::Paren {
s0,
inner,
s1,
span,
},
false,
), // TODO Implement
Self::Neg { Self::Neg {
minus, minus,
s0, s0: _,
expr, expr,
span, span,
} => ( } => {
Self::Neg { let new = Call::arg(Lit::Builtin(Builtin::Neg, minus).expr().boxed(), expr, span);
minus, (new.expr(), true)
s0, }
expr,
span,
},
false,
), // TODO Implement
Self::Not { Self::Not {
not, not,
s0, s0: _,
expr, expr,
span, span,
} => ( } => {
Self::Not { let new = Call::arg(Lit::Builtin(Builtin::Not, not).expr().boxed(), expr, span);
not, (new.expr(), true)
s0, }
expr,
span,
},
false,
), // TODO Implement
Self::BinOp { Self::BinOp {
left, left,
s0, s0: _,
op, op,
s1, s1: _,
right, right,
span, span,
} => ( } => {
Self::BinOp { let builtin = match op {
left, BinOp::Mul => Builtin::Mul,
s0, BinOp::Div => Builtin::Div,
op, BinOp::Mod => Builtin::Mod,
s1, BinOp::Add => Builtin::Add,
right, BinOp::Sub => Builtin::Sub,
span, BinOp::Eq => Builtin::Eq,
}, BinOp::Neq => Builtin::Ne,
false, BinOp::Gt => Builtin::Gt,
), // TODO Implement BinOp::Ge => Builtin::Ge,
BinOp::Lt => Builtin::Lt,
BinOp::Le => Builtin::Le,
BinOp::And => Builtin::And,
BinOp::Or => Builtin::Or,
};
let constr = BoundedSeparated::new(span)
.then(TableConstrElem::positional(left))
.then(TableConstrElem::positional(right))
.table_constr();
let new = Call::constr(Lit::Builtin(builtin, span).expr().boxed(), constr, span);
(new.expr(), true)
}
} }
} }
} }

View file

@ -1,7 +1,4 @@
use crate::ast::{ use crate::ast::{BoundedSeparated, Call, Expr, Field, Lit, StringLit, TableConstrElem};
Call, Expr, Field, Line, Lit, Separated, Space, StringLit, StringLitElem, TableConstr,
TableConstrElem, TableLitElem,
};
use crate::builtin::Builtin; use crate::builtin::Builtin;
impl Field { impl Field {
@ -9,133 +6,80 @@ impl Field {
match self { match self {
Self::Access { Self::Access {
expr, expr,
s0, s0: _,
s1, s1: _,
index, index,
s2, s2: _,
span, span,
} => { } => {
// ` expr s0 [ s1 index s2 ]` let constr = BoundedSeparated::new(span)
// -> `'get s0 { expr, s1 index s2 }` .then(TableConstrElem::positional(expr))
let elems = Separated::NonEmpty { .then(TableConstrElem::positional(index))
first_elem: TableConstrElem::Lit(TableLitElem::Positional(expr)), .table_constr();
last_elems: vec![( let new = Call::constr(
(Space::empty(span), s1), Lit::Builtin(Builtin::Get, span).expr().boxed(),
TableConstrElem::Lit(TableLitElem::Positional(index)),
)],
trailing: None,
span,
};
let constr = TableConstr {
s0: Space::empty(span),
elems,
s1: s2,
span,
};
let new = Expr::Call(Call::Constr {
expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Get, span))),
s0,
constr, constr,
span, span,
}); );
(new, true) (new.expr(), true)
} }
Self::Assign { Self::Assign {
expr, expr,
s0, s0: _,
s1, s1: _,
index, index,
s2, s2: _,
s3, s3: _,
s4, s4: _,
value, value,
span, span,
} => { } => {
// `expr s0 [ s1 index s2 ] s3 = s4 value` let constr = BoundedSeparated::new(span)
// -> `'set s0 { expr, s1 index s2, s3 s4 value }` .then(TableConstrElem::positional(expr))
let elems = Separated::NonEmpty { .then(TableConstrElem::positional(index))
first_elem: TableConstrElem::Lit(TableLitElem::Positional(expr)), .then(TableConstrElem::positional(value))
last_elems: vec![ .table_constr();
( let new = Call::constr(
(Space::empty(span), s1), Lit::Builtin(Builtin::Set, span).expr().boxed(),
TableConstrElem::Lit(TableLitElem::Positional(index)),
),
(
(s2, s3.then_line(Line::Empty).then(s4)),
TableConstrElem::Lit(TableLitElem::Positional(value)),
),
],
trailing: None,
span,
};
let constr = TableConstr {
s0: Space::empty(span),
elems,
s1: Space::empty(span),
span,
};
let new = Expr::Call(Call::Constr {
expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Set, span))),
s0,
constr, constr,
span, span,
}); );
(new, true) (new.expr(), true)
} }
Self::AccessIdent { Self::AccessIdent {
expr, expr,
s0, s0: _,
s1, s1: _,
ident, ident,
span, span,
} => { } => {
// `expr s0 . s1 ident´ let new = Self::access(
// -> `expr s0 [ s1 ident_str ]`
let ident_str = Expr::Lit(Lit::String(StringLit {
elems: vec![StringLitElem::Plain(ident.name)],
span: ident.span,
}));
let new = Expr::Field(Self::Access {
expr, expr,
s0, StringLit::from_ident(ident).lit().expr().boxed(),
s1,
index: Box::new(ident_str),
s2: Space::empty(span),
span, span,
}); );
(new, true) (new.expr(), true)
} }
Self::AssignIdent { Self::AssignIdent {
expr, expr,
s0, s0: _,
s1, s1: _,
ident, ident,
s2, s2: _,
s3, s3: _,
value, value,
span, span,
} => { } => {
// `expr s0 . s1 ident s2 = s3 value` let new = Self::assign(
// -> `expr s0 [ s1 ident_str ] s2 = s3 value`
let ident_str = Expr::Lit(Lit::String(StringLit {
elems: vec![StringLitElem::Plain(ident.name)],
span: ident.span,
}));
let new = Expr::Field(Self::Assign {
expr, expr,
s0, StringLit::from_ident(ident).lit().expr().boxed(),
s1,
index: Box::new(ident_str),
s2: Space::empty(span),
s3: s2,
s4: s3,
value, value,
span, span,
}); );
(new, true) (new.expr(), true)
} }
} }
} }

128
src/desugar/func_def.rs Normal file
View file

@ -0,0 +1,128 @@
use crate::ast::{
BoundedSeparated, Call, Expr, FuncDef, Ident, Lit, Space, TableConstrElem, TableDestr,
TableLitElem, Var,
};
use crate::builtin::Builtin;
impl FuncDef {
pub fn desugar(self) -> (Expr, bool) {
match self {
Self::AnonNoArg {
s0: _,
s1: _,
s2: _,
body,
span,
} => {
let quote = BoundedSeparated::new(span)
.then(TableLitElem::named(Ident::new("quote", span), body, span))
.table_lit();
let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span);
let new = BoundedSeparated::new(span)
.then(TableConstrElem::positional(Box::new(quote.lit().expr())))
.then(TableConstrElem::named(
Ident::new("scope", span),
scope.expr().boxed(),
span,
))
.table_constr();
(new.expr(), true)
}
Self::AnonArg {
s0: _,
s1: _,
arg,
s2: _,
s3: _,
body,
span,
} => {
let arg_call = Call::no_arg(Lit::Builtin(Builtin::Arg, span).expr().boxed(), span);
let arg_assign = Var::assign_ident(true, arg, arg_call.expr().boxed(), span);
let body = BoundedSeparated::new(span)
.then(TableLitElem::Positional(arg_assign.expr().boxed()))
.then(TableLitElem::Positional(body))
.table_lit();
let new = Self::AnonNoArg {
s0: Space::empty(span),
s1: Space::empty(span),
s2: Space::empty(span),
body: body.lit().expr().boxed(),
span,
};
(new.expr(), true)
}
Self::AnonDestr {
s0: _,
pattern,
s1: _,
body,
span,
} => {
let arg_call = Call::no_arg(Lit::Builtin(Builtin::Arg, span).expr().boxed(), span);
let arg_destr = TableDestr::new(true, pattern, arg_call.expr().boxed(), span);
let body = BoundedSeparated::new(span)
.then(TableLitElem::Positional(arg_destr.expr().boxed()))
.then(TableLitElem::Positional(body))
.table_lit();
let new = Self::AnonNoArg {
s0: Space::empty(span),
s1: Space::empty(span),
s2: Space::empty(span),
body: body.lit().expr().boxed(),
span,
};
(new.expr(), true)
}
Self::NamedNoArg {
local,
s0: _,
name,
s1: _,
s2: _,
s3: _,
body,
span,
} => {
let anon = Self::anon_no_arg(body, span);
let new = Var::assign_ident(local.is_some(), name, anon.expr().boxed(), span);
(new.expr(), true)
}
Self::NamedArg {
local,
s0: _,
name,
s1: _,
s2: _,
arg,
s3: _,
s4: _,
body,
span,
} => {
let anon = Self::anon_arg(arg, body, span);
let new = Var::assign_ident(local.is_some(), name, anon.expr().boxed(), span);
(new.expr(), true)
}
Self::NamedDestr {
local,
s0: _,
name,
s1: _,
pattern,
s2: _,
body,
span,
} => {
let anon = Self::anon_destr(pattern, body, span);
let new = Var::assign_ident(local.is_some(), name, anon.expr().boxed(), span);
(new.expr(), true)
}
}
}
}

View file

@ -1,11 +1,11 @@
use crate::ast::{Lit, TableLit, TableLitElem}; use crate::ast::{Expr, Lit, TableLit, TableLitElem};
impl TableLitElem { impl TableLitElem {
pub fn desugar(self) -> (Self, bool) { pub fn desugar(self) -> (Self, bool) {
match self { match self {
Self::Positional(expr) => { Self::Positional(expr) => {
let (expr, desugared) = expr.desugar(); let (expr, desugared) = expr.desugar();
(Self::Positional(Box::new(expr)), desugared) (Self::Positional(expr.boxed()), desugared)
} }
Self::Named { Self::Named {
@ -20,7 +20,7 @@ impl TableLitElem {
name, name,
s0, s0,
s1, s1,
value: Box::new(value), value: value.boxed(),
span, span,
}; };
(new, desugared) (new, desugared)
@ -31,21 +31,18 @@ impl TableLitElem {
impl TableLit { impl TableLit {
pub fn desugar(self) -> (Self, bool) { pub fn desugar(self) -> (Self, bool) {
let Self { let (elems, removed) = self.0.remove_map(|e| match e {
s0, TableLitElem::Named { value, .. } if matches!(*value, Expr::Lit(Lit::Nil(_))) => {
elems, Err(())
s1, }
span, e => Ok(e),
} = self; });
if removed.is_empty() {
let (elems, desugared) = elems.desugar_elem(|e| e.desugar()); let (elems, desugared) = elems.desugar(|e| e.desugar());
let new = Self { (elems.table_lit(), desugared)
s0, } else {
elems, (elems.table_lit(), true)
s1, }
span,
};
(new, desugared)
} }
} }
@ -54,7 +51,7 @@ impl Lit {
match self { match self {
Self::Table(table) => { Self::Table(table) => {
let (table, desugared) = table.desugar(); let (table, desugared) = table.desugar();
(Self::Table(table), desugared) (table.lit(), desugared)
} }
lit => (lit, false), lit => (lit, false),

View file

@ -1,4 +1,4 @@
use crate::ast::{Expr, Lit, Program, Space, TableLit}; use crate::ast::{Program, Space};
impl Program { impl Program {
pub fn desugar(self) -> (Self, bool) { pub fn desugar(self) -> (Self, bool) {
@ -9,24 +9,12 @@ impl Program {
(new, desugared) (new, desugared)
} }
Self::Module { Self::Module { s0, elems, span } => {
s0, // `s0 module elems`
s1, // -> `s0 table`
elems,
s2,
span,
} => {
// `s0 module s1 elems s2`
// -> `s0 '{ s1 elems s2 } empty`
let table = TableLit {
s0: s1,
elems,
s1: s2,
span,
};
let new = Self::Expr { let new = Self::Expr {
s0, s0,
expr: Expr::Lit(Lit::Table(table)), expr: elems.table_lit().lit().expr(),
s1: Space::empty(span), s1: Space::empty(span),
span, span,
}; };

View file

@ -0,0 +1,39 @@
use crate::ast::{
BoundedSeparated, Expr, Field, Ident, TableConstr, TableConstrElem, TableLitElem,
};
use crate::span::HasSpan;
impl TableConstr {
pub fn desugar(self) -> (Expr, bool) {
let span = self.span();
let (elems, setters) = self.0.remove_map(|e| match e {
TableConstrElem::Lit(lit) => Ok(lit),
TableConstrElem::Indexed {
s0: _,
index,
s1: _,
s2: _,
s3: _,
value,
span,
} => Err((index, value, span)),
});
let mut expr = BoundedSeparated::new(span)
.then(TableLitElem::named(
Ident::new("raw", span),
elems.table_lit().lit().expr().boxed(),
span,
))
.table_lit()
.lit()
.expr();
for (_, (index, value, span), _) in setters {
expr = Field::assign(expr.boxed(), index, value, span).expr();
}
(expr, true)
}
}

View file

@ -0,0 +1,63 @@
use crate::ast::{
BoundedSeparated, Call, Expr, Ident, Lit, StringLit, TableConstr, TableConstrElem, TableDestr,
TableLitElem, TablePattern, TablePatternElem,
};
use crate::builtin::Builtin;
fn pattern_to_constr(pattern: TablePattern) -> TableConstr {
pattern
.0
.map(|e| match e {
TablePatternElem::Positional(ident) => {
TableConstrElem::positional(StringLit::from_ident(ident).lit().expr().boxed())
}
TablePatternElem::Named {
name,
s0,
s1,
ident,
span,
} => TableConstrElem::Lit(TableLitElem::Named {
name,
s0,
s1,
value: StringLit::from_ident(ident).lit().expr().boxed(),
span,
}),
})
.table_constr()
}
impl TableDestr {
pub fn desugar(self) -> (Expr, bool) {
let Self {
local,
pattern,
s0: _,
s1: _,
value,
span,
} = self;
let mut constr = BoundedSeparated::new(span)
.then(TableConstrElem::positional(
pattern_to_constr(pattern).expr().boxed(),
))
.then(TableConstrElem::positional(value));
if local.is_some() {
constr = constr.then(TableConstrElem::named(
Ident::new("local", span),
Lit::Bool(true, span).expr().boxed(),
span,
));
}
let new = Call::constr(
Lit::Builtin(Builtin::Destructure, span).expr().boxed(),
constr.table_constr(),
span,
);
(new.expr(), true)
}
}

View file

@ -1,7 +1,4 @@
use crate::ast::{ use crate::ast::{BoundedSeparated, Call, Expr, Field, Lit, StringLit, TableConstrElem, Var};
Call, Expr, Field, Line, Lit, Separated, Space, StringLit, StringLitElem, TableConstr,
TableConstrElem, TableLitElem, Var,
};
use crate::builtin::Builtin; use crate::builtin::Builtin;
use crate::span::HasSpan; use crate::span::HasSpan;
@ -9,152 +6,76 @@ impl Var {
pub fn desugar(self) -> (Expr, bool) { pub fn desugar(self) -> (Expr, bool) {
match self { match self {
Self::Access { Self::Access {
s0, s0: _,
index, index,
s1, s1: _,
span, span,
} => { } => {
// `[ s0 index s1 ]` let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span);
// -> `'scope()[ s0 index s1 ]` let new = Field::access(scope.expr().boxed(), index, span);
let scope = Expr::Call(Call::NoArg { (new.expr(), true)
expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))),
s0: Space::empty(span),
s1: Space::empty(span),
span,
});
let new = Expr::Field(Field::Access {
expr: Box::new(scope),
s0: Space::empty(span),
s1: s0,
index,
s2: s1,
span,
});
(new, true)
} }
Self::Assign { Self::Assign {
local: None, local: None,
s0, s0: _,
index, index,
s1, s1: _,
s2, s2: _,
s3, s3: _,
value, value,
span, span,
} => { } => {
// `[ s0 index s1 ] s2 = s3 value` let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span);
// -> `'scope()[ s0 index s1 ] s2 = s3 value` let new = Field::assign(scope.expr().boxed(), index, value, span);
let scope = Expr::Call(Call::NoArg { (new.expr(), true)
expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))),
s0: Space::empty(span),
s1: Space::empty(span),
span,
});
let new = Expr::Field(Field::Assign {
expr: Box::new(scope),
s0: Space::empty(span),
s1: s0,
index,
s2: s1,
s3: s2,
s4: s3,
value,
span,
});
(new, true)
} }
Self::Assign { Self::Assign {
local: Some(local), local: Some(_),
s0, s0: _,
index, index,
s1, s1: _,
s2, s2: _,
s3, s3: _,
value, value,
span, span,
} => { } => {
// `local [ s0 index s1 ] s2 = s3 value` let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span);
// --> `'setraw { 'scope(), local s0 index s1, s2 s3 value }` let constr = BoundedSeparated::new(span)
let scope = Expr::Call(Call::NoArg { .then(TableConstrElem::positional(scope.expr().boxed()))
expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))), .then(TableConstrElem::positional(index))
s0: Space::empty(span), .then(TableConstrElem::positional(value))
s1: Space::empty(span), .table_constr();
span, let new = Call::constr(
}); Lit::Builtin(Builtin::SetRaw, span).expr().boxed(),
let elems = Separated::NonEmpty {
first_elem: TableConstrElem::Lit(TableLitElem::Positional(Box::new(scope))),
last_elems: vec![
(
(Space::empty(span), local.then_line(Line::Empty).then(s0)),
TableConstrElem::Lit(TableLitElem::Positional(index)),
),
(
(s1, s2.then_line(Line::Empty).then(s3)),
TableConstrElem::Lit(TableLitElem::Positional(value)),
),
],
trailing: None,
span,
};
let constr = TableConstr {
s0: Space::empty(span),
elems,
s1: Space::empty(span),
span,
};
let new = Expr::Call(Call::Constr {
expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::SetRaw, span))),
s0: Space::empty(span),
constr, constr,
span, span,
}); );
(new, true) (new.expr(), true)
} }
Self::AccessIdent(name) => { Self::AccessIdent(name) => {
// `name`
// -> `[ name_str ]`
let span = name.span(); let span = name.span();
let name_str = Expr::Lit(Lit::String(StringLit { let new = Self::access(StringLit::from_ident(name).lit().expr().boxed(), span);
elems: vec![StringLitElem::Plain(name.name)], (new.expr(), true)
span,
}));
let new = Expr::Var(Self::Access {
s0: Space::empty(span),
index: Box::new(name_str),
s1: Space::empty(span),
span,
});
(new, true)
} }
Self::AssignIdent { Self::AssignIdent {
local, local,
name, name,
s0, s0: _,
s1, s1: _,
value, value,
span, span,
} => { } => {
// `local name s0 = s1 value` let new = Self::assign(
// -> `local [ name_str ] s0 = s1 value` local.is_some(),
let name_str = Expr::Lit(Lit::String(StringLit { StringLit::from_ident(name).lit().expr().boxed(),
elems: vec![StringLitElem::Plain(name.name)],
span: name.span,
}));
let new = Expr::Var(Self::Assign {
local,
s0: Space::empty(span),
index: Box::new(name_str),
s1: Space::empty(span),
s2: s0,
s3: s1,
value, value,
span, span,
}); );
(new, true) (new.expr(), true)
} }
} }
} }

View file

@ -80,7 +80,7 @@ fn main() -> anyhow::Result<()> {
.parse(stream) .parse(stream)
.map_err(|e| anyhow!("{e:?}"))?; .map_err(|e| anyhow!("{e:?}"))?;
println!("{}", pretty::pretty_to_string(program, 100)); print!("{}", pretty::pretty_to_string(program, 100));
} }
Command::Desugar { Command::Desugar {

View file

@ -3,7 +3,7 @@
use chumsky::prelude::*; use chumsky::prelude::*;
use chumsky::text::Character; use chumsky::text::Character;
use crate::ast::{Ident, Line, Separated, Space}; use crate::ast::{BoundedSeparated, Ident, Line, Space};
use crate::span::Span; use crate::span::Span;
pub type Error = Simple<char, Span>; pub type Error = Simple<char, Span>;
@ -62,23 +62,42 @@ pub fn local(space: EParser<Space>) -> EParser<Option<Space>> {
// This function is more of a utility function. Because of this and to keep the // This function is more of a utility function. Because of this and to keep the
// code nicer, I have decided that the rules specified in the `parser` module // code nicer, I have decided that the rules specified in the `parser` module
// don't apply to it. // don't apply to it.
pub fn separated_by<E: 'static, S1: 'static, S2: 'static>( pub fn bounded_separated<E: 'static>(
space: impl Parser<char, Space, Error = Error> + Clone + 'static,
start: impl Parser<char, (), Error = Error> + 'static,
end: impl Parser<char, (), Error = Error> + 'static,
separator: impl Parser<char, (), Error = Error> + 'static,
elem: impl Parser<char, E, Error = Error> + Clone + 'static, elem: impl Parser<char, E, Error = Error> + Clone + 'static,
separator: impl Parser<char, S1, Error = Error> + 'static, ) -> EParser<BoundedSeparated<E>> {
trailing_separator: impl Parser<char, S2, Error = Error> + 'static, start
) -> EParser<Separated<E, S1, S2>> { .ignore_then(space.clone())
.then(
elem.clone() elem.clone()
.then(separator.then(elem).repeated()) .then(space.clone())
.then(trailing_separator.or_not()) .then_ignore(separator)
.or_not() .then(space.clone())
.map_with_span(|s, span| match s { .repeated(),
Some(((first_elem, last_elems), trailing)) => Separated::NonEmpty { )
first_elem, .then(elem.then(space).or_not())
last_elems, .then_ignore(end)
.map_with_span(|((s0, first_elems), last_elem), span| {
let mut space_before_elem = s0;
let mut elems = vec![];
for ((elem, s1), s2) in first_elems {
elems.push((space_before_elem, elem, s1));
space_before_elem = s2;
}
let trailing = if let Some((elem, s1)) = last_elem {
elems.push((space_before_elem, elem, s1));
None
} else {
Some(space_before_elem)
};
BoundedSeparated {
elems,
trailing, trailing,
span, span,
}, }
None => Separated::Empty(span),
}) })
.boxed() .boxed()
} }

View file

@ -18,7 +18,7 @@ fn atom_paren(
.then_ignore(just(')')) .then_ignore(just(')'))
.map_with_span(|((s0, inner), s1), span| Expr::Paren { .map_with_span(|((s0, inner), s1), span| Expr::Paren {
s0, s0,
inner: Box::new(inner), inner: inner.boxed(),
s1, s1,
span, span,
}) })
@ -63,11 +63,11 @@ fn left_assoc(
over.then(op_over.repeated()) over.then(op_over.repeated())
.foldl(|left, (s0, op, s1, right)| Expr::BinOp { .foldl(|left, (s0, op, s1, right)| Expr::BinOp {
span: left.span().join(right.span()), span: left.span().join(right.span()),
left: Box::new(left), left: left.boxed(),
s0, s0,
op, op,
s1, s1,
right: Box::new(right), right: right.boxed(),
}) })
.boxed() .boxed()
} }
@ -89,11 +89,11 @@ fn right_assoc(
.then(over) .then(over)
.foldr(|(left, s0, op, s1), right| Expr::BinOp { .foldr(|(left, s0, op, s1), right| Expr::BinOp {
span: left.span().join(right.span()), span: left.span().join(right.span()),
left: Box::new(left), left: left.boxed(),
s0, s0,
op, op,
s1, s1,
right: Box::new(right), right: right.boxed(),
}) })
.boxed() .boxed()
} }

View file

@ -19,7 +19,7 @@ fn func_def_anon_no_arg(
s0, s0,
s1, s1,
s2, s2,
body: Box::new(body), body: body.boxed(),
span, span,
}) })
} }
@ -45,7 +45,7 @@ fn func_def_anon_arg(
arg, arg,
s2, s2,
s3, s3,
body: Box::new(body), body: body.boxed(),
span, span,
}, },
) )
@ -65,7 +65,7 @@ fn func_def_anon_destr(
s0, s0,
pattern, pattern,
s1, s1,
body: Box::new(body), body: body.boxed(),
span, span,
}) })
} }
@ -94,7 +94,7 @@ fn func_def_named_no_arg(
s1, s1,
s2, s2,
s3, s3,
body: Box::new(body), body: body.boxed(),
span, span,
}, },
) )
@ -128,7 +128,7 @@ fn func_def_named_arg(
arg, arg,
s3, s3,
s4, s4,
body: Box::new(body), body: body.boxed(),
span, span,
}, },
) )
@ -157,7 +157,7 @@ fn func_def_named_destr(
s1, s1,
pattern, pattern,
s2, s2,
body: Box::new(body), body: body.boxed(),
span, span,
} }
}) })

View file

@ -7,7 +7,7 @@ use crate::ast::{
}; };
use crate::builtin::Builtin; use crate::builtin::Builtin;
use super::basic::{separated_by, EParser, Error}; use super::basic::{bounded_separated, EParser, Error};
fn builtin_lit() -> impl Parser<char, Builtin, Error = Error> { fn builtin_lit() -> impl Parser<char, Builtin, Error = Error> {
just('\'').ignore_then(choice(( just('\'').ignore_then(choice((
@ -132,7 +132,7 @@ pub fn table_lit_elem(
) -> EParser<TableLitElem> { ) -> EParser<TableLitElem> {
let positional = expr let positional = expr
.clone() .clone()
.map(|value| TableLitElem::Positional(Box::new(value))); .map(|value| TableLitElem::Positional(value.boxed()));
let named = ident let named = ident
.then(space.clone()) .then(space.clone())
@ -143,7 +143,7 @@ pub fn table_lit_elem(
name, name,
s0, s0,
s1, s1,
value: Box::new(value), value: value.boxed(),
span, span,
}); });
@ -154,20 +154,14 @@ fn table_lit(
space: EParser<Space>, space: EParser<Space>,
table_lit_elem: EParser<TableLitElem>, table_lit_elem: EParser<TableLitElem>,
) -> impl Parser<char, TableLit, Error = Error> { ) -> impl Parser<char, TableLit, Error = Error> {
let separator = space.clone().then_ignore(just(',')).then(space.clone()); bounded_separated(
let trailing_separator = space.clone().then_ignore(just(',')); space,
just("'{").to(()),
space just('}').to(()),
.clone() just(',').to(()),
.then(separated_by(table_lit_elem, separator, trailing_separator)) table_lit_elem,
.then(space) )
.delimited_by(just("'{"), just('}')) .map(TableLit)
.map_with_span(|((s0, elems), s1), span| TableLit {
s0,
elems,
s1,
span,
})
} }
pub fn lit(space: EParser<Space>, table_lit_elem: EParser<TableLitElem>) -> EParser<Lit> { pub fn lit(space: EParser<Space>, table_lit_elem: EParser<TableLitElem>) -> EParser<Lit> {

View file

@ -17,7 +17,7 @@ enum Prefix {
impl Prefix { impl Prefix {
fn into_expr(self, span: Span, expr: Expr) -> Expr { fn into_expr(self, span: Span, expr: Expr) -> Expr {
let expr = Box::new(expr); let expr = expr.boxed();
match self { match self {
Self::Neg { minus, s0 } => Expr::Neg { Self::Neg { minus, s0 } => Expr::Neg {
minus, minus,

View file

@ -4,7 +4,7 @@ use chumsky::prelude::*;
use crate::ast::{Expr, Program, Space, TableLitElem}; use crate::ast::{Expr, Program, Space, TableLitElem};
use super::basic::{separated_by, EParser}; use super::basic::{bounded_separated, EParser};
pub fn program( pub fn program(
space: EParser<Space>, space: EParser<Space>,
@ -17,21 +17,17 @@ pub fn program(
.then(space.clone()) .then(space.clone())
.map_with_span(|((s0, expr), s1), span| Program::Expr { s0, expr, s1, span }); .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 let module = space
.clone() .clone()
.then_ignore(text::keyword("module")) .then_ignore(text::keyword("module"))
.then(space.clone()) .then(bounded_separated(
.then(separated_by(table_lit_elem, separator, trailing_separator)) space,
.then(space.clone()) empty(),
.map_with_span(|(((s0, s1), elems), s2), span| Program::Module { empty(),
s0, just(',').to(()),
s1, table_lit_elem,
elems, ))
s2, .map_with_span(|(s0, elems), span| Program::Module { s0, elems, span });
span,
});
module.or(lit).boxed() module.or(lit).boxed()
} }

View file

@ -57,31 +57,38 @@ enum Suffix {
impl Suffix { impl Suffix {
fn into_expr(self, span: Span, expr: Expr) -> Expr { fn into_expr(self, span: Span, expr: Expr) -> Expr {
let expr = Box::new(expr); let expr = expr.boxed();
match self { match self {
Self::CallArg { s0, s1, arg, s2 } => Expr::Call(Call::Arg { Self::CallArg { s0, s1, arg, s2 } => Call::Arg {
expr, expr,
s0, s0,
s1, s1,
arg, arg,
s2, s2,
span, span,
}), }
Self::CallNoArg { s0, s1 } => Expr::Call(Call::NoArg { expr, s0, s1, span }), .expr(),
Self::CallConstr { s0, constr } => Expr::Call(Call::Constr {
Self::CallNoArg { s0, s1 } => Call::NoArg { expr, s0, s1, span }.expr(),
Self::CallConstr { s0, constr } => Call::Constr {
expr, expr,
s0, s0,
constr, constr,
span, span,
}), }
Self::FieldAccess { s0, s1, index, s2 } => Expr::Field(Field::Access { .expr(),
Self::FieldAccess { s0, s1, index, s2 } => Field::Access {
expr, expr,
s0, s0,
s1, s1,
index, index,
s2, s2,
span, span,
}), }
.expr(),
Self::FieldAssign { Self::FieldAssign {
s0, s0,
s1, s1,
@ -90,7 +97,7 @@ impl Suffix {
s3, s3,
s4, s4,
value, value,
} => Expr::Field(Field::Assign { } => Field::Assign {
expr, expr,
s0, s0,
s1, s1,
@ -100,14 +107,18 @@ impl Suffix {
s4, s4,
value, value,
span, span,
}), }
Self::FieldAccessIdent { s0, s1, ident } => Expr::Field(Field::AccessIdent { .expr(),
Self::FieldAccessIdent { s0, s1, ident } => Field::AccessIdent {
expr, expr,
s0, s0,
s1, s1,
ident, ident,
span, span,
}), }
.expr(),
Self::FieldAssignIdent { Self::FieldAssignIdent {
s0, s0,
s1, s1,
@ -115,7 +126,7 @@ impl Suffix {
s2, s2,
s3, s3,
value, value,
} => Expr::Field(Field::AssignIdent { } => Field::AssignIdent {
expr, expr,
s0, s0,
s1, s1,
@ -124,7 +135,8 @@ impl Suffix {
s3, s3,
value, value,
span, span,
}), }
.expr(),
} }
} }
} }
@ -143,7 +155,7 @@ fn suffix_call_arg(
.map(|(((s0, s1), arg), s2)| Suffix::CallArg { .map(|(((s0, s1), arg), s2)| Suffix::CallArg {
s0, s0,
s1, s1,
arg: Box::new(arg), arg: arg.boxed(),
s2, s2,
}) })
} }
@ -180,7 +192,7 @@ fn suffix_field_access(
.map(|(((s0, s1), index), s2)| Suffix::FieldAccess { .map(|(((s0, s1), index), s2)| Suffix::FieldAccess {
s0, s0,
s1, s1,
index: Box::new(index), index: index.boxed(),
s2, s2,
}) })
} }
@ -204,11 +216,11 @@ fn suffix_field_assign(
|((((((s0, s1), index), s2), s3), s4), value)| Suffix::FieldAssign { |((((((s0, s1), index), s2), s3), s4), value)| Suffix::FieldAssign {
s0, s0,
s1, s1,
index: Box::new(index), index: index.boxed(),
s2, s2,
s3, s3,
s4, s4,
value: Box::new(value), value: value.boxed(),
}, },
) )
} }
@ -246,7 +258,7 @@ fn suffix_field_assign_ident(
ident, ident,
s2, s2,
s3, s3,
value: Box::new(value), value: value.boxed(),
}, },
) )
} }

View file

@ -4,7 +4,7 @@ use chumsky::prelude::*;
use crate::ast::{Expr, Space, TableConstr, TableConstrElem, TableLitElem}; use crate::ast::{Expr, Space, TableConstr, TableConstrElem, TableLitElem};
use super::basic::{separated_by, EParser, Error}; use super::basic::{bounded_separated, EParser, Error};
fn table_constr_elem( fn table_constr_elem(
space: EParser<Space>, space: EParser<Space>,
@ -25,11 +25,11 @@ fn table_constr_elem(
.map_with_span( .map_with_span(
|(((((s0, index), s1), s2), s3), value), span| TableConstrElem::Indexed { |(((((s0, index), s1), s2), s3), value), span| TableConstrElem::Indexed {
s0, s0,
index: Box::new(index), index: index.boxed(),
s1, s1,
s2, s2,
s3, s3,
value: Box::new(value), value: value.boxed(),
span, span,
}, },
); );
@ -43,19 +43,13 @@ pub fn table_constr(
expr: EParser<Expr>, expr: EParser<Expr>,
) -> EParser<TableConstr> { ) -> EParser<TableConstr> {
let elem = table_constr_elem(space.clone(), table_lit_elem, expr); let elem = table_constr_elem(space.clone(), table_lit_elem, expr);
let separator = space.clone().then_ignore(just(',')).then(space.clone()); bounded_separated(
let trailing_separator = space.clone().then_ignore(just(',')); space,
just('{').to(()),
space just('}').to(()),
.clone() just(',').to(()),
.then(separated_by(elem, separator, trailing_separator)) elem,
.then(space) )
.delimited_by(just('{'), just('}')) .map(TableConstr)
.map_with_span(|((s0, elems), s1), span| TableConstr {
s0,
elems,
s1,
span,
})
.boxed() .boxed()
} }

View file

@ -4,7 +4,7 @@ use chumsky::prelude::*;
use crate::ast::{Expr, Ident, Space, TableDestr, TablePattern, TablePatternElem}; use crate::ast::{Expr, Ident, Space, TableDestr, TablePattern, TablePatternElem};
use super::basic::{separated_by, EParser, Error}; use super::basic::{bounded_separated, EParser, Error};
fn table_pattern_elem( fn table_pattern_elem(
space: EParser<Space>, space: EParser<Space>,
@ -31,20 +31,14 @@ fn table_pattern_elem(
pub fn table_pattern(space: EParser<Space>, ident: EParser<Ident>) -> EParser<TablePattern> { pub fn table_pattern(space: EParser<Space>, ident: EParser<Ident>) -> EParser<TablePattern> {
let elem = table_pattern_elem(space.clone(), ident); let elem = table_pattern_elem(space.clone(), ident);
let separator = space.clone().then_ignore(just(',')).then(space.clone()); bounded_separated(
let trailing_separator = space.clone().then_ignore(just(',')); space,
just('{').to(()),
space just('}').to(()),
.clone() just(',').to(()),
.then(separated_by(elem, separator, trailing_separator)) elem,
.then(space) )
.delimited_by(just('{'), just('}')) .map(TablePattern)
.map_with_span(|((s0, elems), s1), span| TablePattern {
s0,
elems,
s1,
span,
})
.boxed() .boxed()
} }
@ -65,7 +59,7 @@ pub fn table_destr(
pattern, pattern,
s0, s0,
s1, s1,
value: Box::new(value), value: value.boxed(),
span, span,
}) })
.boxed() .boxed()

View file

@ -14,7 +14,7 @@ fn var_access(space: EParser<Space>, expr: EParser<Expr>) -> impl Parser<char, V
.then_ignore(just(']')) .then_ignore(just(']'))
.map_with_span(|((s0, index), s1), span| Var::Access { .map_with_span(|((s0, index), s1), span| Var::Access {
s0, s0,
index: Box::new(index), index: index.boxed(),
s1, s1,
span, span,
}) })
@ -39,11 +39,11 @@ fn var_assign(
|((((((local, s0), index), s1), s2), s3), value), span| Var::Assign { |((((((local, s0), index), s1), s2), s3), value), span| Var::Assign {
local, local,
s0, s0,
index: Box::new(index), index: index.boxed(),
s1, s1,
s2, s2,
s3, s3,
value: Box::new(value), value: value.boxed(),
span, span,
}, },
) )
@ -67,7 +67,7 @@ fn var_assign_ident(
name, name,
s0, s0,
s1, s1,
value: Box::new(value), value: value.boxed(),
span, span,
}, },
) )

View file

@ -1,3 +1,6 @@
// TODO Remove this and print whitespace and comments properly
#![allow(unused_variables)]
use pretty::{Pretty, RcAllocator}; use pretty::{Pretty, RcAllocator};
mod basic; mod basic;
@ -18,5 +21,7 @@ pub fn pretty_to_string<P: Pretty<'static, RcAllocator>>(p: P, width: usize) ->
p.pretty(&RcAllocator) p.pretty(&RcAllocator)
.render(width, &mut out) .render(width, &mut out)
.expect("p could not be rendered"); .expect("p could not be rendered");
String::from_utf8(out).expect("p created non-utf8 string") let mut s = String::from_utf8(out).expect("p created non-utf8 string");
s.push('\n');
s
} }

View file

@ -1,6 +1,8 @@
use pretty::{DocAllocator, DocBuilder, Pretty}; use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::{Ident, Separated}; use crate::ast::{BoundedSeparated, Ident};
use super::NEST_DEPTH;
impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Ident { impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Ident {
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
@ -8,40 +10,32 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Ident {
} }
} }
impl<E, S1, S2> Separated<E, S1, S2> { impl<E> BoundedSeparated<E> {
pub fn pretty<'a, D, FE, FS1, FS2>( pub fn pretty<'a, D, FE>(
self, self,
allocator: &'a D, allocator: &'a D,
elem_to_doc: FE, start: DocBuilder<'a, D>,
separator_to_doc: FS1, end: DocBuilder<'a, D>,
trailing_separator_to_doc: FS2, separator: DocBuilder<'a, D>,
elem_pretty: FE,
) -> DocBuilder<'a, D> ) -> DocBuilder<'a, D>
where where
D: DocAllocator<'a>, D: DocAllocator<'a>,
D::Doc: Clone,
FE: Fn(E) -> DocBuilder<'a, D>, FE: Fn(E) -> DocBuilder<'a, D>,
FS1: Fn(S1) -> DocBuilder<'a, D>,
FS2: Fn(S2) -> DocBuilder<'a, D>,
{ {
match self { let elems_empty = self.elems.is_empty();
Self::Empty(_) => allocator.nil(), allocator
Self::NonEmpty { .intersperse(
first_elem, self.elems
last_elems,
trailing,
span: _span,
} => elem_to_doc(first_elem)
.append(
allocator.concat(
last_elems
.into_iter() .into_iter()
.map(|(s, e)| separator_to_doc(s).append(elem_to_doc(e))), .map(|(s0, elem, s1)| allocator.line().append(elem_pretty(elem))),
), separator.clone(),
) )
.append( .append(self.trailing.filter(|_| !elems_empty).map(|s| separator))
trailing .nest(NEST_DEPTH)
.map(trailing_separator_to_doc) .append(allocator.line())
.unwrap_or_else(|| allocator.nil()), .enclose(start, end)
), .group()
}
} }
} }

View file

@ -2,7 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::Call; 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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Self::Arg { Self::Arg {

View file

@ -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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Self::Lit(lit) => lit.pretty(allocator), Self::Lit(lit) => lit.pretty(allocator),

View file

@ -2,7 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::Field; 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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Self::Access { Self::Access {

View file

@ -2,7 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::FuncDef; 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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Self::AnonNoArg { Self::AnonNoArg {

View file

@ -2,8 +2,6 @@ use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::{Lit, NumLit, StringLit, StringLitElem, TableLit, TableLitElem}; use crate::ast::{Lit, NumLit, StringLit, StringLitElem, TableLit, TableLitElem};
use super::NEST_DEPTH;
impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for NumLit { impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for NumLit {
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
allocator.text(format!("{self:?}")) 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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Self::Positional(expr) => expr.pretty(allocator), 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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
self.elems self.0.pretty(
.pretty(
allocator, allocator,
|e| allocator.line().append(e.pretty(allocator)), allocator.text("'{"),
|(s0, s1)| allocator.text(","), allocator.text("}"),
|s| allocator.text(","), allocator.text(","),
|e| e.pretty(allocator),
) )
.nest(NEST_DEPTH)
.append(allocator.line())
.enclose(allocator.text("'{"), allocator.text("}"))
.group()
} }
} }
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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Self::Nil(_) => allocator.text("nil"), Self::Nil(_) => allocator.text("nil"),

View file

@ -2,7 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::Program; 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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Self::Expr { Self::Expr {
@ -11,22 +15,19 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Program {
s1, s1,
span: _, span: _,
} => expr.pretty(allocator), } => expr.pretty(allocator),
Self::Module {
s0, Self::Module { s0, elems, span: _ } => {
s1, allocator.text("module").append(allocator.line()).append(
elems, allocator
s2, .intersperse(
span: _, elems.elems.into_iter().map(|(s0, elem, s1)| {
} => allocator allocator.line().append(elem.pretty(allocator))
.text("module") }),
.append(allocator.line()) allocator.text(","),
.append(allocator.line()) )
.append(elems.pretty( .append(elems.trailing.map(|s| allocator.text(","))),
allocator, )
|e| e.pretty(allocator), }
|(s0, s1)| allocator.text(",").append(allocator.line()),
|s| allocator.text(","),
)),
} }
} }
} }

View file

@ -2,9 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::{TableConstr, TableConstrElem}; use crate::ast::{TableConstr, TableConstrElem};
use super::NEST_DEPTH; impl<'a, D> Pretty<'a, D> for TableConstrElem
where
impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableConstrElem { D: DocAllocator<'a>,
D::Doc: Clone,
{
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Self::Lit(lit) => lit.pretty(allocator), Self::Lit(lit) => lit.pretty(allocator),
@ -25,18 +27,18 @@ 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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
self.elems self.0.pretty(
.pretty(
allocator, allocator,
|e| allocator.line().append(e.pretty(allocator)), allocator.text("{"),
|(s0, s1)| allocator.text(","), allocator.text("}"),
|s| allocator.text(","), allocator.text(","),
|e| e.pretty(allocator),
) )
.nest(NEST_DEPTH)
.append(allocator.line())
.braces()
.group()
} }
} }

View file

@ -2,8 +2,6 @@ use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::{TableDestr, TablePattern, TablePatternElem}; use crate::ast::{TableDestr, TablePattern, TablePatternElem};
use super::NEST_DEPTH;
impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePatternElem { impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePatternElem {
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
@ -22,23 +20,27 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePatternElem {
} }
} }
impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePattern { impl<'a, D> Pretty<'a, D> for TablePattern
where
D: DocAllocator<'a>,
D::Doc: Clone,
{
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
self.elems self.0.pretty(
.pretty(
allocator, allocator,
|e| allocator.line().append(e.pretty(allocator)), allocator.text("{"),
|(s0, s1)| allocator.text(","), allocator.text("}"),
|s| allocator.text(","), allocator.text(","),
|e| e.pretty(allocator),
) )
.nest(NEST_DEPTH)
.append(allocator.line())
.braces()
.group()
} }
} }
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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
// TODO Handle spaces // TODO Handle spaces
self.local self.local

View file

@ -2,7 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty};
use crate::ast::Var; 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> { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
match self { match self {
Self::Access { Self::Access {