From b009a9c4ec36082478dd1e26f8709df23d34339c Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 20:25:39 +0100 Subject: [PATCH 01/70] Handle things separated by things differently I noticed that programs like '{} would parse correctly while '{ } would expect an inner element. This was because the leading space was actually part of the element parser, which is a violation of the (as of yet unspoken) rule that parsers should not parse surrounding whitespace. Because whitespace whas treated differently from everywhere else and because this implementation was wrong, I decided to reimplement it, abstracting the concept of things separated by other things with optional trailing things. I did this in such a way that surrounding whitespace is not touched. --- src/ast/basic.rs | 20 ++++++++++++++++++++ src/ast/lit.rs | 10 ++++++---- src/ast/program.rs | 10 +++++----- src/ast/table_constr.rs | 10 ++++++---- src/ast/table_destr.rs | 12 +++++++----- src/parser/basic.rs | 26 +++++++++++++++++++++++++- src/parser/lit.rs | 26 +++++++++++--------------- src/parser/program.rs | 21 ++++++++++----------- src/parser/table_constr.rs | 29 +++++++++++++---------------- src/parser/table_destr.rs | 29 +++++++++++++---------------- 10 files changed, 116 insertions(+), 77 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index e472e39..1194111 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -47,3 +47,23 @@ impl HasSpan for Ident { self.span } } + +#[derive(Debug, Clone)] +pub enum Separated { + Empty(Span), + NonEmpty { + first_elem: E, + last_elems: Vec<(S1, E)>, + trailing: Option, + span: Span, + }, +} + +impl HasSpan for Separated { + fn span(&self) -> Span { + match self { + Separated::Empty(span) => *span, + Separated::NonEmpty { span, .. } => *span, + } + } +} diff --git a/src/ast/lit.rs b/src/ast/lit.rs index 299bc1c..c079955 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, Space}; +use super::{Expr, Ident, Separated, Space}; #[derive(Clone)] pub enum NumLitStr { @@ -126,11 +126,13 @@ impl HasSpan for TableLitElem { } /// `'{ a, foo: b }` +/// +/// Structure: `'{ s0 elems s1 }` #[derive(Debug, Clone)] pub struct TableLit { - pub elems: Vec<(Space, TableLitElem, Space)>, - /// `Some` if there is a trailing comma, `None` otherwise. - pub trailing_comma: Option, + pub s0: Space, + pub elems: Separated, + pub s1: Space, pub span: Span, } diff --git a/src/ast/program.rs b/src/ast/program.rs index 5a198d0..1a219f5 100644 --- a/src/ast/program.rs +++ b/src/ast/program.rs @@ -1,6 +1,6 @@ use crate::span::{HasSpan, Span}; -use super::{Expr, Space, TableLitElem}; +use super::{Expr, Separated, Space, TableLitElem}; #[derive(Debug, Clone)] pub enum Program { @@ -12,12 +12,12 @@ pub enum Program { span: Span, }, - /// Structure: `s0 module elems trailing_comma` + /// Structure: `s0 module s1 elems s2` Module { s0: Space, - elems: Vec<(Space, TableLitElem, Space)>, - /// `Some` if there is a trailing comma, `None` otherwise. - trailing_comma: Option, + s1: Space, + elems: Separated, + s2: Space, span: Span, }, } diff --git a/src/ast/table_constr.rs b/src/ast/table_constr.rs index 0b699cc..741a30c 100644 --- a/src/ast/table_constr.rs +++ b/src/ast/table_constr.rs @@ -1,6 +1,6 @@ use crate::span::{HasSpan, Span}; -use super::{Expr, Space, TableLitElem}; +use super::{Expr, Separated, Space, TableLitElem}; #[derive(Debug, Clone)] pub enum TableConstrElem { @@ -31,11 +31,13 @@ impl HasSpan for TableConstrElem { } /// `{ a, b, foo: c, [d]: e }` +/// +/// Structure: `{ s0 elems s1 }` #[derive(Debug, Clone)] pub struct TableConstr { - pub elems: Vec<(Space, TableConstrElem, Space)>, - /// `Some` if there is a trailing comma, `None` otherwise. - pub trailing_comma: Option, + pub s0: Space, + pub elems: Separated, + pub s1: Space, pub span: Span, } diff --git a/src/ast/table_destr.rs b/src/ast/table_destr.rs index 56c8d36..9cbf46a 100644 --- a/src/ast/table_destr.rs +++ b/src/ast/table_destr.rs @@ -1,6 +1,6 @@ use crate::span::{HasSpan, Span}; -use super::{Expr, Ident, Space}; +use super::{Expr, Ident, Separated, Space}; // TODO Make table patterns recursive @@ -30,12 +30,14 @@ impl HasSpan for TablePatternElem { } } -/// `'{ foo, bar: baz }` +/// `{ foo, bar: baz }` +/// +/// Structure: `{ s0 elems s1 }` #[derive(Debug, Clone)] pub struct TablePattern { - pub elems: Vec<(Space, TablePatternElem, Space)>, - /// `Some` if there is a trailing comma, `None` otherwise. - pub trailing_comma: Option, + pub s0: Space, + pub elems: Separated, + pub s1: Space, pub span: Span, } diff --git a/src/parser/basic.rs b/src/parser/basic.rs index 8d7ba1d..2a65c68 100644 --- a/src/parser/basic.rs +++ b/src/parser/basic.rs @@ -3,7 +3,7 @@ use chumsky::prelude::*; use chumsky::text::Character; -use crate::ast::{Ident, Line, Space}; +use crate::ast::{Ident, Line, Separated, Space}; use crate::span::Span; pub type Error = Simple; @@ -58,3 +58,27 @@ pub fn ident() -> EParser { pub fn local(space: EParser) -> EParser> { text::keyword("local").ignore_then(space).or_not().boxed() } + +// 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 +// don't apply to it. +pub fn separated_by( + elem: impl Parser + Clone + 'static, + separator: impl Parser + 'static, + trailing_separator: impl Parser + 'static, +) -> EParser> { + elem.clone() + .then(separator.then(elem).repeated()) + .then(trailing_separator.or_not()) + .or_not() + .map_with_span(|s, span| match s { + Some(((first_elem, last_elems), trailing)) => Separated::NonEmpty { + first_elem, + last_elems, + trailing, + span, + }, + None => Separated::Empty(span), + }) + .boxed() +} diff --git a/src/parser/lit.rs b/src/parser/lit.rs index 7d04e1f..0bdf12a 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::{EParser, Error}; +use super::basic::{separated_by, EParser, Error}; fn builtin_lit() -> impl Parser { just('\'').ignore_then(choice(( @@ -154,22 +154,18 @@ fn table_lit( space: EParser, table_lit_elem: EParser, ) -> impl Parser { - let elem = space + let separator = space.clone().then_ignore(just(',')).then(space.clone()); + let trailing_separator = space.clone().then_ignore(just(',')); + + space .clone() - .then(table_lit_elem) - .then(space.clone()) - .map(|((s0, elem), s1)| (s0, elem, s1)); - - let trailing_comma = just(',').ignore_then(space).or_not(); - - let elems = elem.separated_by(just(',')).then(trailing_comma); - - just("'{") - .ignore_then(elems) - .then_ignore(just('}')) - .map_with_span(|(elems, trailing_comma), span| TableLit { + .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, - trailing_comma, + s1, span, }) } diff --git a/src/parser/program.rs b/src/parser/program.rs index 26e12fd..0b46f94 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::EParser; +use super::basic::{separated_by, EParser}; pub fn program( space: EParser, @@ -17,20 +17,19 @@ pub fn program( .then(space.clone()) .map_with_span(|((s0, expr), s1), span| Program::Expr { s0, expr, s1, span }); - let elem = space - .clone() - .then(table_lit_elem) - .then(space.clone()) - .map(|((s0, elem), s1)| (s0, elem, s1)); - let trailing_comma = just(',').ignore_then(space.clone()).or_not(); + 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(elem.separated_by(just(','))) - .then(trailing_comma) - .map_with_span(|((s0, elems), trailing_comma), span| Program::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, - trailing_comma, + s2, span, }); diff --git a/src/parser/table_constr.rs b/src/parser/table_constr.rs index ac0bb04..fd6aefd 100644 --- a/src/parser/table_constr.rs +++ b/src/parser/table_constr.rs @@ -4,13 +4,13 @@ use chumsky::prelude::*; use crate::ast::{Expr, Space, TableConstr, TableConstrElem, TableLitElem}; -use super::basic::{EParser, Error}; +use super::basic::{separated_by, EParser, Error}; fn table_constr_elem( space: EParser, table_lit_elem: EParser, expr: EParser, -) -> impl Parser { +) -> impl Parser + Clone { let lit = table_lit_elem.map(TableConstrElem::Lit); let indexed = just('[') @@ -42,22 +42,19 @@ pub fn table_constr( table_lit_elem: EParser, expr: EParser, ) -> EParser { - let elem = space + let elem = table_constr_elem(space.clone(), table_lit_elem, expr); + let separator = space.clone().then_ignore(just(',')).then(space.clone()); + let trailing_separator = space.clone().then_ignore(just(',')); + + space .clone() - .then(table_constr_elem(space.clone(), table_lit_elem, expr)) - .then(space.clone()) - .map(|((s0, elem), s1)| (s0, elem, s1)); - - let trailing_comma = just(',').ignore_then(space).or_not(); - - let elems = elem.separated_by(just(',')).then(trailing_comma); - - just('{') - .ignore_then(elems) - .then_ignore(just('}')) - .map_with_span(|(elems, trailing_comma), span| TableConstr { + .then(separated_by(elem, separator, trailing_separator)) + .then(space) + .delimited_by(just('{'), just('}')) + .map_with_span(|((s0, elems), s1), span| TableConstr { + s0, elems, - trailing_comma, + s1, span, }) .boxed() diff --git a/src/parser/table_destr.rs b/src/parser/table_destr.rs index dfde71e..4fb5eda 100644 --- a/src/parser/table_destr.rs +++ b/src/parser/table_destr.rs @@ -4,12 +4,12 @@ use chumsky::prelude::*; use crate::ast::{Expr, Ident, Space, TableDestr, TablePattern, TablePatternElem}; -use super::basic::{EParser, Error}; +use super::basic::{separated_by, EParser, Error}; fn table_pattern_elem( space: EParser, ident: EParser, -) -> impl Parser { +) -> impl Parser + Clone { let positional = ident.clone().map(TablePatternElem::Positional); let named = ident @@ -30,22 +30,19 @@ fn table_pattern_elem( } pub fn table_pattern(space: EParser, ident: EParser) -> EParser { - let elem = space + let elem = table_pattern_elem(space.clone(), ident); + let separator = space.clone().then_ignore(just(',')).then(space.clone()); + let trailing_separator = space.clone().then_ignore(just(',')); + + space .clone() - .then(table_pattern_elem(space.clone(), ident)) - .then(space.clone()) - .map(|((s0, elem), s1)| (s0, elem, s1)); - - let trailing_comma = just(',').ignore_then(space).or_not(); - - let elems = elem.separated_by(just(',')).then(trailing_comma); - - just('{') - .ignore_then(elems) - .then_ignore(just('}')) - .map_with_span(|(elems, trailing_comma), span| TablePattern { + .then(separated_by(elem, separator, trailing_separator)) + .then(space) + .delimited_by(just('{'), just('}')) + .map_with_span(|((s0, elems), s1), span| TablePattern { + s0, elems, - trailing_comma, + s1, span, }) .boxed() From 969570fc4b193ccd6ec822188dcc43a4d7d1393c Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 20:30:09 +0100 Subject: [PATCH 02/70] Make rule about consuming surrounding whitespace --- src/parser.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/parser.rs b/src/parser.rs index 72d26c6..1650d97 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,6 +2,7 @@ //! //! # Rules //! +//! - Parsers must not consume surrounding whitespace. //! - Public parser functions must return [`basic::EParser`]. //! - Public parser functions must receive public subparsers via their arguments. //! - Each public parser function must be called exactly once, inside this file. From b21619dabdce636add1ad9c03125e23179cd5dff Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 20:32:14 +0100 Subject: [PATCH 03/70] Pretty print programs partially --- src/main.rs | 12 ++++-------- src/pretty.rs | 10 +--------- src/pretty/program.rs | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+), 17 deletions(-) create mode 100644 src/pretty/program.rs diff --git a/src/main.rs b/src/main.rs index 57f1850..ee5f73a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ use std::fs; use std::path::PathBuf; -use ::pretty::{Pretty, RcAllocator}; use chumsky::Parser as _; use clap::Parser; @@ -48,17 +47,14 @@ fn main() -> anyhow::Result<()> { let stream = span::stream_from_str(&content); match parser::parser().parse(stream) { Ok(program) => { - println!("Successful parse"); - let doc = program.pretty(&RcAllocator); let mut out = vec![]; - doc.render(100, &mut out)?; - let str = String::from_utf8(out)?; - println!("{str}"); + program.to_doc().render(100, &mut out)?; + println!("{}", String::from_utf8(out)?); } Err(errs) => { - println!("Parsing failed"); + eprintln!("Parsing failed"); for err in errs { - println!("{err:?}"); + eprintln!("{err:?}"); } } } diff --git a/src/pretty.rs b/src/pretty.rs index 1d8e288..3847c62 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -1,9 +1 @@ -use pretty::{DocAllocator, DocBuilder, Pretty}; - -use crate::ast::Program; - -impl<'a, A: DocAllocator<'a>> Pretty<'a, A> for Program { - fn pretty(self, allocator: &'a A) -> DocBuilder<'a, A, ()> { - allocator.text("Hello world") - } -} +mod program; diff --git a/src/pretty/program.rs b/src/pretty/program.rs new file mode 100644 index 0000000..60a5ca0 --- /dev/null +++ b/src/pretty/program.rs @@ -0,0 +1,23 @@ +use pretty::RcDoc; + +use crate::ast::Program; + +impl Program { + pub fn to_doc(&self) -> RcDoc { + match self { + Program::Expr { + s0, + expr, + s1, + span: _, + } => RcDoc::nil(), + Program::Module { + s0, + s1, + elems, + s2, + span: _, + } => RcDoc::text("module"), + } + } +} From a18532a23ad9c68266a5f45ce6d7569458df436b Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 20:33:29 +0100 Subject: [PATCH 04/70] Start pretty printing comments --- src/pretty/basic.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/pretty/basic.rs diff --git a/src/pretty/basic.rs b/src/pretty/basic.rs new file mode 100644 index 0000000..c3e6dcc --- /dev/null +++ b/src/pretty/basic.rs @@ -0,0 +1,86 @@ +use std::mem; + +use pretty::{DocAllocator, DocBuilder, Pretty, RcAllocator, RcDoc}; + +use crate::ast::{Ident, Line, Space}; + +pub enum Group<'a> { + EmptyLine, + CommentBlock(Vec<&'a str>), +} + +/// Group comments and deduplicate empty lines +fn group_comments(lines: &[Line]) -> Vec { + let mut result = vec![]; + + let mut current_block = vec![]; + let mut last_line_was_empty = false; + for line in lines { + match line { + Line::Empty if last_line_was_empty => {} + Line::Empty => { + last_line_was_empty = true; + if !current_block.is_empty() { + result.push(Group::CommentBlock(mem::take(&mut current_block))); + } + result.push(Group::EmptyLine); + } + Line::Comment(comment) => { + last_line_was_empty = false; + current_block.push(comment); + } + } + } + + if !current_block.is_empty() { + result.push(Group::CommentBlock(current_block)); + } + + result +} + +fn remove_leading_empty_line(groups: &mut Vec) { + if let Some(Group::EmptyLine) = groups.first() { + groups.remove(0); + } +} + +fn remove_trailing_empty_line(groups: &mut Vec) { + if let Some(Group::EmptyLine) = groups.last() { + groups.pop(); + } +} + +fn comment_group_to_doc(comment: Vec<&str>) -> RcDoc { + RcAllocator + .concat(comment.into_iter().map(|c| { + RcDoc::text("# ") + .append(RcDoc::text(c)) + .append(RcDoc::hardline()) + })) + .indent(0) + .into_doc() +} + +impl Space { + /// Format as document for inline use, prefering nil if possible. + pub fn to_doc_inline_nospace(&self) -> RcDoc { + RcDoc::nil() + } + + /// Format as document, prefering a single space if possible. + pub fn to_doc_inline_space(&self) -> RcDoc { + RcDoc::space() + } + + /// Format as document, prefering a newline if possible. + pub fn to_doc_newline(&self) -> RcDoc { + RcDoc::line() + } +} + +impl Ident { + pub fn to_doc(&self) -> RcDoc { + RcDoc::text(&self.name) + } +} From 6533c9dcf7bc00587d5f22927c99cb69575818f7 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 20:25:39 +0100 Subject: [PATCH 05/70] Handle things separated by things differently I noticed that programs like '{} would parse correctly while '{ } would expect an inner element. This was because the leading space was actually part of the element parser, which is a violation of the (as of yet unspoken) rule that parsers should not parse surrounding whitespace. Because whitespace whas treated differently from everywhere else and because this implementation was wrong, I decided to reimplement it, abstracting the concept of things separated by other things with optional trailing things. I did this in such a way that surrounding whitespace is not touched. --- src/ast/basic.rs | 20 ++++++++++++++++++++ src/ast/lit.rs | 10 ++++++---- src/ast/program.rs | 10 +++++----- src/ast/table_constr.rs | 10 ++++++---- src/ast/table_destr.rs | 12 +++++++----- src/parser/basic.rs | 26 +++++++++++++++++++++++++- src/parser/lit.rs | 26 +++++++++++--------------- src/parser/program.rs | 21 ++++++++++----------- src/parser/table_constr.rs | 29 +++++++++++++---------------- src/parser/table_destr.rs | 29 +++++++++++++---------------- 10 files changed, 116 insertions(+), 77 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index e472e39..1194111 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -47,3 +47,23 @@ impl HasSpan for Ident { self.span } } + +#[derive(Debug, Clone)] +pub enum Separated { + Empty(Span), + NonEmpty { + first_elem: E, + last_elems: Vec<(S1, E)>, + trailing: Option, + span: Span, + }, +} + +impl HasSpan for Separated { + fn span(&self) -> Span { + match self { + Separated::Empty(span) => *span, + Separated::NonEmpty { span, .. } => *span, + } + } +} diff --git a/src/ast/lit.rs b/src/ast/lit.rs index 299bc1c..c079955 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, Space}; +use super::{Expr, Ident, Separated, Space}; #[derive(Clone)] pub enum NumLitStr { @@ -126,11 +126,13 @@ impl HasSpan for TableLitElem { } /// `'{ a, foo: b }` +/// +/// Structure: `'{ s0 elems s1 }` #[derive(Debug, Clone)] pub struct TableLit { - pub elems: Vec<(Space, TableLitElem, Space)>, - /// `Some` if there is a trailing comma, `None` otherwise. - pub trailing_comma: Option, + pub s0: Space, + pub elems: Separated, + pub s1: Space, pub span: Span, } diff --git a/src/ast/program.rs b/src/ast/program.rs index 5a198d0..1a219f5 100644 --- a/src/ast/program.rs +++ b/src/ast/program.rs @@ -1,6 +1,6 @@ use crate::span::{HasSpan, Span}; -use super::{Expr, Space, TableLitElem}; +use super::{Expr, Separated, Space, TableLitElem}; #[derive(Debug, Clone)] pub enum Program { @@ -12,12 +12,12 @@ pub enum Program { span: Span, }, - /// Structure: `s0 module elems trailing_comma` + /// Structure: `s0 module s1 elems s2` Module { s0: Space, - elems: Vec<(Space, TableLitElem, Space)>, - /// `Some` if there is a trailing comma, `None` otherwise. - trailing_comma: Option, + s1: Space, + elems: Separated, + s2: Space, span: Span, }, } diff --git a/src/ast/table_constr.rs b/src/ast/table_constr.rs index 0b699cc..bf6b517 100644 --- a/src/ast/table_constr.rs +++ b/src/ast/table_constr.rs @@ -1,6 +1,6 @@ use crate::span::{HasSpan, Span}; -use super::{Expr, Space, TableLitElem}; +use super::{Expr, Separated, Space, TableLitElem}; #[derive(Debug, Clone)] pub enum TableConstrElem { @@ -31,11 +31,13 @@ impl HasSpan for TableConstrElem { } /// `{ a, b, foo: c, [d]: e }` +/// +/// Structure: `{ s0 elems s1 }` #[derive(Debug, Clone)] pub struct TableConstr { - pub elems: Vec<(Space, TableConstrElem, Space)>, - /// `Some` if there is a trailing comma, `None` otherwise. - pub trailing_comma: Option, + pub s0: Space, + pub elems: Separated, + pub s1: Space, pub span: Span, } diff --git a/src/ast/table_destr.rs b/src/ast/table_destr.rs index 56c8d36..3d90fb3 100644 --- a/src/ast/table_destr.rs +++ b/src/ast/table_destr.rs @@ -1,6 +1,6 @@ use crate::span::{HasSpan, Span}; -use super::{Expr, Ident, Space}; +use super::{Expr, Ident, Separated, Space}; // TODO Make table patterns recursive @@ -30,12 +30,14 @@ impl HasSpan for TablePatternElem { } } -/// `'{ foo, bar: baz }` +/// `{ foo, bar: baz }` +/// +/// Structure: `{ s0 elems s1 }` #[derive(Debug, Clone)] pub struct TablePattern { - pub elems: Vec<(Space, TablePatternElem, Space)>, - /// `Some` if there is a trailing comma, `None` otherwise. - pub trailing_comma: Option, + pub s0: Space, + pub elems: Separated, + pub s1: Space, pub span: Span, } diff --git a/src/parser/basic.rs b/src/parser/basic.rs index 8d7ba1d..2a65c68 100644 --- a/src/parser/basic.rs +++ b/src/parser/basic.rs @@ -3,7 +3,7 @@ use chumsky::prelude::*; use chumsky::text::Character; -use crate::ast::{Ident, Line, Space}; +use crate::ast::{Ident, Line, Separated, Space}; use crate::span::Span; pub type Error = Simple; @@ -58,3 +58,27 @@ pub fn ident() -> EParser { pub fn local(space: EParser) -> EParser> { text::keyword("local").ignore_then(space).or_not().boxed() } + +// 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 +// don't apply to it. +pub fn separated_by( + elem: impl Parser + Clone + 'static, + separator: impl Parser + 'static, + trailing_separator: impl Parser + 'static, +) -> EParser> { + elem.clone() + .then(separator.then(elem).repeated()) + .then(trailing_separator.or_not()) + .or_not() + .map_with_span(|s, span| match s { + Some(((first_elem, last_elems), trailing)) => Separated::NonEmpty { + first_elem, + last_elems, + trailing, + span, + }, + None => Separated::Empty(span), + }) + .boxed() +} diff --git a/src/parser/lit.rs b/src/parser/lit.rs index 7d04e1f..0bdf12a 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::{EParser, Error}; +use super::basic::{separated_by, EParser, Error}; fn builtin_lit() -> impl Parser { just('\'').ignore_then(choice(( @@ -154,22 +154,18 @@ fn table_lit( space: EParser, table_lit_elem: EParser, ) -> impl Parser { - let elem = space + let separator = space.clone().then_ignore(just(',')).then(space.clone()); + let trailing_separator = space.clone().then_ignore(just(',')); + + space .clone() - .then(table_lit_elem) - .then(space.clone()) - .map(|((s0, elem), s1)| (s0, elem, s1)); - - let trailing_comma = just(',').ignore_then(space).or_not(); - - let elems = elem.separated_by(just(',')).then(trailing_comma); - - just("'{") - .ignore_then(elems) - .then_ignore(just('}')) - .map_with_span(|(elems, trailing_comma), span| TableLit { + .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, - trailing_comma, + s1, span, }) } diff --git a/src/parser/program.rs b/src/parser/program.rs index 26e12fd..0b46f94 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::EParser; +use super::basic::{separated_by, EParser}; pub fn program( space: EParser, @@ -17,20 +17,19 @@ pub fn program( .then(space.clone()) .map_with_span(|((s0, expr), s1), span| Program::Expr { s0, expr, s1, span }); - let elem = space - .clone() - .then(table_lit_elem) - .then(space.clone()) - .map(|((s0, elem), s1)| (s0, elem, s1)); - let trailing_comma = just(',').ignore_then(space.clone()).or_not(); + 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(elem.separated_by(just(','))) - .then(trailing_comma) - .map_with_span(|((s0, elems), trailing_comma), span| Program::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, - trailing_comma, + s2, span, }); diff --git a/src/parser/table_constr.rs b/src/parser/table_constr.rs index ac0bb04..fd6aefd 100644 --- a/src/parser/table_constr.rs +++ b/src/parser/table_constr.rs @@ -4,13 +4,13 @@ use chumsky::prelude::*; use crate::ast::{Expr, Space, TableConstr, TableConstrElem, TableLitElem}; -use super::basic::{EParser, Error}; +use super::basic::{separated_by, EParser, Error}; fn table_constr_elem( space: EParser, table_lit_elem: EParser, expr: EParser, -) -> impl Parser { +) -> impl Parser + Clone { let lit = table_lit_elem.map(TableConstrElem::Lit); let indexed = just('[') @@ -42,22 +42,19 @@ pub fn table_constr( table_lit_elem: EParser, expr: EParser, ) -> EParser { - let elem = space + let elem = table_constr_elem(space.clone(), table_lit_elem, expr); + let separator = space.clone().then_ignore(just(',')).then(space.clone()); + let trailing_separator = space.clone().then_ignore(just(',')); + + space .clone() - .then(table_constr_elem(space.clone(), table_lit_elem, expr)) - .then(space.clone()) - .map(|((s0, elem), s1)| (s0, elem, s1)); - - let trailing_comma = just(',').ignore_then(space).or_not(); - - let elems = elem.separated_by(just(',')).then(trailing_comma); - - just('{') - .ignore_then(elems) - .then_ignore(just('}')) - .map_with_span(|(elems, trailing_comma), span| TableConstr { + .then(separated_by(elem, separator, trailing_separator)) + .then(space) + .delimited_by(just('{'), just('}')) + .map_with_span(|((s0, elems), s1), span| TableConstr { + s0, elems, - trailing_comma, + s1, span, }) .boxed() diff --git a/src/parser/table_destr.rs b/src/parser/table_destr.rs index dfde71e..4fb5eda 100644 --- a/src/parser/table_destr.rs +++ b/src/parser/table_destr.rs @@ -4,12 +4,12 @@ use chumsky::prelude::*; use crate::ast::{Expr, Ident, Space, TableDestr, TablePattern, TablePatternElem}; -use super::basic::{EParser, Error}; +use super::basic::{separated_by, EParser, Error}; fn table_pattern_elem( space: EParser, ident: EParser, -) -> impl Parser { +) -> impl Parser + Clone { let positional = ident.clone().map(TablePatternElem::Positional); let named = ident @@ -30,22 +30,19 @@ fn table_pattern_elem( } pub fn table_pattern(space: EParser, ident: EParser) -> EParser { - let elem = space + let elem = table_pattern_elem(space.clone(), ident); + let separator = space.clone().then_ignore(just(',')).then(space.clone()); + let trailing_separator = space.clone().then_ignore(just(',')); + + space .clone() - .then(table_pattern_elem(space.clone(), ident)) - .then(space.clone()) - .map(|((s0, elem), s1)| (s0, elem, s1)); - - let trailing_comma = just(',').ignore_then(space).or_not(); - - let elems = elem.separated_by(just(',')).then(trailing_comma); - - just('{') - .ignore_then(elems) - .then_ignore(just('}')) - .map_with_span(|(elems, trailing_comma), span| TablePattern { + .then(separated_by(elem, separator, trailing_separator)) + .then(space) + .delimited_by(just('{'), just('}')) + .map_with_span(|((s0, elems), s1), span| TablePattern { + s0, elems, - trailing_comma, + s1, span, }) .boxed() From 1b364061e46f4a9cbc5d8f503093c0dd3b7f86cb Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 20:30:09 +0100 Subject: [PATCH 06/70] Make rule about consuming surrounding whitespace --- src/parser.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/parser.rs b/src/parser.rs index 72d26c6..1650d97 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,6 +2,7 @@ //! //! # Rules //! +//! - Parsers must not consume surrounding whitespace. //! - Public parser functions must return [`basic::EParser`]. //! - Public parser functions must receive public subparsers via their arguments. //! - Each public parser function must be called exactly once, inside this file. From 200b653e619ec869acc37671c2a615cd4facebab Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 20:32:14 +0100 Subject: [PATCH 07/70] Pretty print programs partially --- src/main.rs | 12 ++++-------- src/pretty.rs | 10 +--------- src/pretty/program.rs | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+), 17 deletions(-) create mode 100644 src/pretty/program.rs diff --git a/src/main.rs b/src/main.rs index 57f1850..ee5f73a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ use std::fs; use std::path::PathBuf; -use ::pretty::{Pretty, RcAllocator}; use chumsky::Parser as _; use clap::Parser; @@ -48,17 +47,14 @@ fn main() -> anyhow::Result<()> { let stream = span::stream_from_str(&content); match parser::parser().parse(stream) { Ok(program) => { - println!("Successful parse"); - let doc = program.pretty(&RcAllocator); let mut out = vec![]; - doc.render(100, &mut out)?; - let str = String::from_utf8(out)?; - println!("{str}"); + program.to_doc().render(100, &mut out)?; + println!("{}", String::from_utf8(out)?); } Err(errs) => { - println!("Parsing failed"); + eprintln!("Parsing failed"); for err in errs { - println!("{err:?}"); + eprintln!("{err:?}"); } } } diff --git a/src/pretty.rs b/src/pretty.rs index 1d8e288..3847c62 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -1,9 +1 @@ -use pretty::{DocAllocator, DocBuilder, Pretty}; - -use crate::ast::Program; - -impl<'a, A: DocAllocator<'a>> Pretty<'a, A> for Program { - fn pretty(self, allocator: &'a A) -> DocBuilder<'a, A, ()> { - allocator.text("Hello world") - } -} +mod program; diff --git a/src/pretty/program.rs b/src/pretty/program.rs new file mode 100644 index 0000000..60a5ca0 --- /dev/null +++ b/src/pretty/program.rs @@ -0,0 +1,23 @@ +use pretty::RcDoc; + +use crate::ast::Program; + +impl Program { + pub fn to_doc(&self) -> RcDoc { + match self { + Program::Expr { + s0, + expr, + s1, + span: _, + } => RcDoc::nil(), + Program::Module { + s0, + s1, + elems, + s2, + span: _, + } => RcDoc::text("module"), + } + } +} From 23796e53a9f227b81da5d84a61ebc2eaa274ed97 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 21:10:19 +0100 Subject: [PATCH 08/70] Pretty print program elements --- src/pretty.rs | 1 + src/pretty/basic.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/pretty/program.rs | 11 +++++++++-- 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 src/pretty/basic.rs diff --git a/src/pretty.rs b/src/pretty.rs index 3847c62..4fe06c6 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -1 +1,2 @@ +mod basic; mod program; diff --git a/src/pretty/basic.rs b/src/pretty/basic.rs new file mode 100644 index 0000000..2ee19db --- /dev/null +++ b/src/pretty/basic.rs @@ -0,0 +1,38 @@ +use pretty::RcDoc; + +use crate::ast::Separated; + +impl Separated { + pub fn to_doc( + &self, + elem_to_doc: FE, + separator_to_doc: FS1, + trailing_separator_to_doc: FS2, + ) -> RcDoc + where + FE: Fn(&E) -> RcDoc, + FS1: Fn(&S1) -> RcDoc, + FS2: Fn(&S2) -> RcDoc, + { + match self { + Separated::Empty(_) => RcDoc::nil(), + Separated::NonEmpty { + first_elem, + last_elems, + trailing, + span: _span, + } => elem_to_doc(first_elem) + .append(RcDoc::concat( + last_elems + .iter() + .map(|(s, e)| separator_to_doc(s).append(elem_to_doc(e))), + )) + .append( + trailing + .as_ref() + .map(trailing_separator_to_doc) + .unwrap_or_else(RcDoc::nil), + ), + } + } +} diff --git a/src/pretty/program.rs b/src/pretty/program.rs index 60a5ca0..6af1ac4 100644 --- a/src/pretty/program.rs +++ b/src/pretty/program.rs @@ -10,14 +10,21 @@ impl Program { expr, s1, span: _, - } => RcDoc::nil(), + } => RcDoc::text(""), Program::Module { s0, s1, elems, s2, span: _, - } => RcDoc::text("module"), + } => RcDoc::text("module") + .append(RcDoc::line()) + .append(RcDoc::line()) + .append(elems.to_doc( + |e| RcDoc::text(""), + |(s0, s1)| RcDoc::text(",").append(RcDoc::line()), + |s| RcDoc::text(","), + )), } } } From 1a3772e6f7a268c8b6239fea7a1dafcb21ca92bf Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 21:19:54 +0100 Subject: [PATCH 09/70] Pretty print expressions partially --- src/pretty.rs | 1 + src/pretty/expr.rs | 48 +++++++++++++++++++++++++++++++++++++++++++ src/pretty/program.rs | 2 +- 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/pretty/expr.rs diff --git a/src/pretty.rs b/src/pretty.rs index 4fe06c6..f29ec0e 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -1,2 +1,3 @@ mod basic; +mod expr; mod program; diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs new file mode 100644 index 0000000..57b186a --- /dev/null +++ b/src/pretty/expr.rs @@ -0,0 +1,48 @@ +use pretty::RcDoc; + +use crate::ast::Expr; + +impl Expr { + pub fn to_doc(&self) -> RcDoc { + match self { + Expr::Lit(lit) => RcDoc::text(""), + Expr::Call(call) => RcDoc::text(""), + Expr::Field(field) => RcDoc::text(""), + Expr::Var(var) => RcDoc::text(""), + Expr::TableConstr(constr) => RcDoc::text(""), + Expr::TableDestr(destr) => RcDoc::text(""), + Expr::FuncDef(def) => RcDoc::text(""), + Expr::Paren { + s0, + inner, + s1, + span: _, + } => RcDoc::text("(").append(inner.to_doc()).append(")"), + + // TODO Check whether parentheses are necessary + Expr::Neg { + minus: _, + s0, + expr, + span: _, + } => RcDoc::text("-").append(expr.to_doc()), + + // TODO Check whether parentheses are necessary + Expr::Not { + not: _, + s0, + expr, + span: _, + } => RcDoc::text("not ").append(expr.to_doc()), + + Expr::BinOp { + left, + s0, + op, + s1, + right, + span: _, + } => RcDoc::text(""), + } + } +} diff --git a/src/pretty/program.rs b/src/pretty/program.rs index 6af1ac4..9d34494 100644 --- a/src/pretty/program.rs +++ b/src/pretty/program.rs @@ -10,7 +10,7 @@ impl Program { expr, s1, span: _, - } => RcDoc::text(""), + } => expr.to_doc(), Program::Module { s0, s1, From 2ba56f0c92717ebb07ae29f29eb3919e405c4a0c Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 21:41:05 +0100 Subject: [PATCH 10/70] Make code generic over allocator This way, I can use the same code with any allocator I want. More importantly, I can also use the nice DocBuilder-exclusive helper functions! --- src/main.rs | 3 ++- src/pretty/basic.rs | 33 ++++++++++++++++----------------- src/pretty/expr.rs | 28 ++++++++++++++-------------- src/pretty/program.rs | 24 +++++++++++++----------- 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/main.rs b/src/main.rs index ee5f73a..2524a1f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use std::fs; use std::path::PathBuf; +use ::pretty::{Pretty, RcAllocator}; use chumsky::Parser as _; use clap::Parser; @@ -48,7 +49,7 @@ fn main() -> anyhow::Result<()> { match parser::parser().parse(stream) { Ok(program) => { let mut out = vec![]; - program.to_doc().render(100, &mut out)?; + program.pretty(&RcAllocator).render(100, &mut out)?; println!("{}", String::from_utf8(out)?); } Err(errs) => { diff --git a/src/pretty/basic.rs b/src/pretty/basic.rs index 2ee19db..293c9a1 100644 --- a/src/pretty/basic.rs +++ b/src/pretty/basic.rs @@ -1,37 +1,36 @@ -use pretty::RcDoc; +use pretty::{DocAllocator, DocBuilder}; use crate::ast::Separated; impl Separated { - pub fn to_doc( - &self, + pub fn pretty<'a, D, FE, FS1, FS2>( + self, + allocator: &'a D, elem_to_doc: FE, separator_to_doc: FS1, trailing_separator_to_doc: FS2, - ) -> RcDoc + ) -> DocBuilder<'a, D> where - FE: Fn(&E) -> RcDoc, - FS1: Fn(&S1) -> RcDoc, - FS2: Fn(&S2) -> RcDoc, + D: DocAllocator<'a>, + FE: Fn(&'a D, E) -> DocBuilder<'a, D>, + FS1: Fn(&'a D, S1) -> DocBuilder<'a, D>, + FS2: Fn(&'a D, S2) -> DocBuilder<'a, D>, { match self { - Separated::Empty(_) => RcDoc::nil(), + Separated::Empty(_) => allocator.nil(), Separated::NonEmpty { first_elem, last_elems, trailing, span: _span, - } => elem_to_doc(first_elem) - .append(RcDoc::concat( - last_elems - .iter() - .map(|(s, e)| separator_to_doc(s).append(elem_to_doc(e))), - )) + } => elem_to_doc(allocator, first_elem) + .append(allocator.concat(last_elems.into_iter().map(|(s, e)| { + separator_to_doc(allocator, s).append(elem_to_doc(allocator, e)) + }))) .append( trailing - .as_ref() - .map(trailing_separator_to_doc) - .unwrap_or_else(RcDoc::nil), + .map(|s| trailing_separator_to_doc(allocator, s)) + .unwrap_or_else(|| allocator.nil()), ), } } diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index 57b186a..eeef8db 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -1,23 +1,23 @@ -use pretty::RcDoc; +use pretty::{DocAllocator, DocBuilder, Pretty}; use crate::ast::Expr; -impl Expr { - pub fn to_doc(&self) -> RcDoc { +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { - Expr::Lit(lit) => RcDoc::text(""), - Expr::Call(call) => RcDoc::text(""), - Expr::Field(field) => RcDoc::text(""), - Expr::Var(var) => RcDoc::text(""), - Expr::TableConstr(constr) => RcDoc::text(""), - Expr::TableDestr(destr) => RcDoc::text(""), - Expr::FuncDef(def) => RcDoc::text(""), + Expr::Lit(lit) => allocator.text(""), + Expr::Call(call) => allocator.text(""), + Expr::Field(field) => allocator.text(""), + Expr::Var(var) => allocator.text(""), + Expr::TableConstr(constr) => allocator.text(""), + Expr::TableDestr(destr) => allocator.text(""), + Expr::FuncDef(def) => allocator.text(""), Expr::Paren { s0, inner, s1, span: _, - } => RcDoc::text("(").append(inner.to_doc()).append(")"), + } => inner.pretty(allocator).parens(), // TODO Check whether parentheses are necessary Expr::Neg { @@ -25,7 +25,7 @@ impl Expr { s0, expr, span: _, - } => RcDoc::text("-").append(expr.to_doc()), + } => allocator.text("-").append(expr.pretty(allocator)), // TODO Check whether parentheses are necessary Expr::Not { @@ -33,7 +33,7 @@ impl Expr { s0, expr, span: _, - } => RcDoc::text("not ").append(expr.to_doc()), + } => allocator.text("not ").append(expr.pretty(allocator)), Expr::BinOp { left, @@ -42,7 +42,7 @@ impl Expr { s1, right, span: _, - } => RcDoc::text(""), + } => allocator.text(""), } } } diff --git a/src/pretty/program.rs b/src/pretty/program.rs index 9d34494..22925af 100644 --- a/src/pretty/program.rs +++ b/src/pretty/program.rs @@ -1,29 +1,31 @@ -use pretty::RcDoc; +use pretty::{DocAllocator, DocBuilder, Pretty}; use crate::ast::Program; -impl Program { - pub fn to_doc(&self) -> RcDoc { +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Program { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Program::Expr { s0, expr, s1, span: _, - } => expr.to_doc(), + } => expr.pretty(allocator), Program::Module { s0, s1, elems, s2, span: _, - } => RcDoc::text("module") - .append(RcDoc::line()) - .append(RcDoc::line()) - .append(elems.to_doc( - |e| RcDoc::text(""), - |(s0, s1)| RcDoc::text(",").append(RcDoc::line()), - |s| RcDoc::text(","), + } => allocator + .text("module") + .append(allocator.line()) + .append(allocator.line()) + .append(elems.pretty( + allocator, + |a, e| a.text(""), + |a, (s0, s1)| a.text(",").append(a.line()), + |a, s| a.text(","), )), } } From 3ed3c4e8f884dbb8b84021485cc7f8968871cda2 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 22:15:43 +0100 Subject: [PATCH 11/70] Add warnings from cove --- src/main.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main.rs b/src/main.rs index 2524a1f..90cc696 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,19 @@ +#![deny(unsafe_code)] +// Rustc lint groups +#![warn(future_incompatible)] +#![warn(rust_2018_idioms)] +// Rustc lints +#![warn(noop_method_call)] +#![warn(single_use_lifetimes)] +#![warn(trivial_numeric_casts)] +#![warn(unused_crate_dependencies)] +#![warn(unused_extern_crates)] +#![warn(unused_import_braces)] +#![warn(unused_lifetimes)] +#![warn(unused_qualifications)] +// Clippy lints +#![warn(clippy::use_self)] + use std::fs; use std::path::PathBuf; From 03e7f107395602da075ba03fbd8fee24b2f0f946 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 22:15:56 +0100 Subject: [PATCH 12/70] Satisfy warnings --- src/ast/basic.rs | 4 ++-- src/ast/call.rs | 6 +++--- src/ast/expr.rs | 22 +++++++++++----------- src/ast/field.rs | 8 ++++---- src/ast/func_def.rs | 12 ++++++------ src/ast/lit.rs | 16 ++++++++-------- src/ast/program.rs | 4 ++-- src/ast/table_constr.rs | 4 ++-- src/ast/table_destr.rs | 4 ++-- src/ast/var.rs | 8 ++++---- src/parser/suffix.rs | 14 +++++++------- src/pretty/basic.rs | 4 ++-- src/pretty/expr.rs | 22 +++++++++++----------- src/pretty/program.rs | 4 ++-- 14 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index 1194111..33562f2 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -62,8 +62,8 @@ pub enum Separated { impl HasSpan for Separated { fn span(&self) -> Span { match self { - Separated::Empty(span) => *span, - Separated::NonEmpty { span, .. } => *span, + Self::Empty(span) => *span, + Self::NonEmpty { span, .. } => *span, } } } diff --git a/src/ast/call.rs b/src/ast/call.rs index 10f82e8..547e1f1 100644 --- a/src/ast/call.rs +++ b/src/ast/call.rs @@ -40,9 +40,9 @@ pub enum Call { impl HasSpan for Call { fn span(&self) -> Span { match self { - Call::Arg { span, .. } => *span, - Call::NoArg { span, .. } => *span, - Call::Constr { span, .. } => *span, + Self::Arg { span, .. } => *span, + Self::NoArg { span, .. } => *span, + Self::Constr { span, .. } => *span, } } } diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 522f2f1..50a25ee 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -186,17 +186,17 @@ impl fmt::Debug for Expr { impl HasSpan for Expr { fn span(&self) -> Span { match self { - Expr::Lit(lit) => lit.span(), - Expr::Call(call) => call.span(), - Expr::Field(field) => field.span(), - Expr::Var(var) => var.span(), - Expr::TableConstr(constr) => constr.span(), - Expr::TableDestr(destr) => destr.span(), - Expr::FuncDef(def) => def.span(), - Expr::Paren { span, .. } => *span, - Expr::Neg { span, .. } => *span, - Expr::Not { span, .. } => *span, - Expr::BinOp { span, .. } => *span, + Self::Lit(lit) => lit.span(), + Self::Call(call) => call.span(), + Self::Field(field) => field.span(), + Self::Var(var) => var.span(), + Self::TableConstr(constr) => constr.span(), + Self::TableDestr(destr) => destr.span(), + Self::FuncDef(def) => def.span(), + Self::Paren { span, .. } => *span, + Self::Neg { span, .. } => *span, + Self::Not { span, .. } => *span, + Self::BinOp { span, .. } => *span, } } } diff --git a/src/ast/field.rs b/src/ast/field.rs index c8c10b4..1972686 100644 --- a/src/ast/field.rs +++ b/src/ast/field.rs @@ -60,10 +60,10 @@ pub enum Field { impl HasSpan for Field { fn span(&self) -> Span { match self { - Field::Access { span, .. } => *span, - Field::Assign { span, .. } => *span, - Field::AccessIdent { span, .. } => *span, - Field::AssignIdent { span, .. } => *span, + Self::Access { span, .. } => *span, + Self::Assign { span, .. } => *span, + Self::AccessIdent { span, .. } => *span, + Self::AssignIdent { span, .. } => *span, } } } diff --git a/src/ast/func_def.rs b/src/ast/func_def.rs index 3ce0b34..e1e89ad 100644 --- a/src/ast/func_def.rs +++ b/src/ast/func_def.rs @@ -90,12 +90,12 @@ pub enum FuncDef { impl HasSpan for FuncDef { fn span(&self) -> Span { match self { - FuncDef::AnonNoArg { span, .. } => *span, - FuncDef::AnonArg { span, .. } => *span, - FuncDef::AnonDestr { span, .. } => *span, - FuncDef::NamedNoArg { span, .. } => *span, - FuncDef::NamedArg { span, .. } => *span, - FuncDef::NamedDestr { span, .. } => *span, + Self::AnonNoArg { span, .. } => *span, + Self::AnonArg { span, .. } => *span, + Self::AnonDestr { span, .. } => *span, + Self::NamedNoArg { span, .. } => *span, + Self::NamedArg { span, .. } => *span, + Self::NamedDestr { span, .. } => *span, } } } diff --git a/src/ast/lit.rs b/src/ast/lit.rs index c079955..63ced41 100644 --- a/src/ast/lit.rs +++ b/src/ast/lit.rs @@ -119,8 +119,8 @@ pub enum TableLitElem { impl HasSpan for TableLitElem { fn span(&self) -> Span { match self { - TableLitElem::Positional(value) => value.span(), - TableLitElem::Named { span, .. } => *span, + Self::Positional(value) => value.span(), + Self::Named { span, .. } => *span, } } } @@ -187,12 +187,12 @@ impl fmt::Debug for Lit { impl HasSpan for Lit { fn span(&self) -> Span { match self { - Lit::Nil(span) => *span, - Lit::Bool(_, span) => *span, - Lit::Builtin(_, span) => *span, - Lit::Num(n) => n.span(), - Lit::String(s) => s.span(), - Lit::Table(t) => t.span(), + Self::Nil(span) => *span, + Self::Bool(_, span) => *span, + Self::Builtin(_, span) => *span, + Self::Num(n) => n.span(), + Self::String(s) => s.span(), + Self::Table(t) => t.span(), } } } diff --git a/src/ast/program.rs b/src/ast/program.rs index 1a219f5..2020225 100644 --- a/src/ast/program.rs +++ b/src/ast/program.rs @@ -25,8 +25,8 @@ pub enum Program { impl HasSpan for Program { fn span(&self) -> Span { match self { - Program::Expr { span, .. } => *span, - Program::Module { span, .. } => *span, + Self::Expr { span, .. } => *span, + Self::Module { span, .. } => *span, } } } diff --git a/src/ast/table_constr.rs b/src/ast/table_constr.rs index bf6b517..d347ce1 100644 --- a/src/ast/table_constr.rs +++ b/src/ast/table_constr.rs @@ -24,8 +24,8 @@ pub enum TableConstrElem { impl HasSpan for TableConstrElem { fn span(&self) -> Span { match self { - TableConstrElem::Lit(lit) => lit.span(), - TableConstrElem::Indexed { span, .. } => *span, + Self::Lit(lit) => lit.span(), + Self::Indexed { span, .. } => *span, } } } diff --git a/src/ast/table_destr.rs b/src/ast/table_destr.rs index 3d90fb3..eb88dcb 100644 --- a/src/ast/table_destr.rs +++ b/src/ast/table_destr.rs @@ -24,8 +24,8 @@ pub enum TablePatternElem { impl HasSpan for TablePatternElem { fn span(&self) -> Span { match self { - TablePatternElem::Positional(ident) => ident.span(), - TablePatternElem::Named { span, .. } => *span, + Self::Positional(ident) => ident.span(), + Self::Named { span, .. } => *span, } } } diff --git a/src/ast/var.rs b/src/ast/var.rs index bc32e7a..6ec6026 100644 --- a/src/ast/var.rs +++ b/src/ast/var.rs @@ -49,10 +49,10 @@ pub enum Var { impl HasSpan for Var { fn span(&self) -> Span { match self { - Var::Access { span, .. } => *span, - Var::Assign { span, .. } => *span, - Var::AccessIdent(ident) => ident.span(), - Var::AssignIdent { span, .. } => *span, + Self::Access { span, .. } => *span, + Self::Assign { span, .. } => *span, + Self::AccessIdent(ident) => ident.span(), + Self::AssignIdent { span, .. } => *span, } } } diff --git a/src/parser/suffix.rs b/src/parser/suffix.rs index 6c10491..cb02008 100644 --- a/src/parser/suffix.rs +++ b/src/parser/suffix.rs @@ -59,7 +59,7 @@ impl Suffix { fn into_expr(self, span: Span, expr: Expr) -> Expr { let expr = Box::new(expr); match self { - Suffix::CallArg { s0, s1, arg, s2 } => Expr::Call(Call::Arg { + Self::CallArg { s0, s1, arg, s2 } => Expr::Call(Call::Arg { expr, s0, s1, @@ -67,14 +67,14 @@ impl Suffix { s2, span, }), - Suffix::CallNoArg { s0, s1 } => Expr::Call(Call::NoArg { expr, s0, s1, span }), - Suffix::CallConstr { s0, constr } => Expr::Call(Call::Constr { + Self::CallNoArg { s0, s1 } => Expr::Call(Call::NoArg { expr, s0, s1, span }), + Self::CallConstr { s0, constr } => Expr::Call(Call::Constr { expr, s0, constr, span, }), - Suffix::FieldAccess { s0, s1, index, s2 } => Expr::Field(Field::Access { + Self::FieldAccess { s0, s1, index, s2 } => Expr::Field(Field::Access { expr, s0, s1, @@ -82,7 +82,7 @@ impl Suffix { s2, span, }), - Suffix::FieldAssign { + Self::FieldAssign { s0, s1, index, @@ -101,14 +101,14 @@ impl Suffix { value, span, }), - Suffix::FieldAccessIdent { s0, s1, ident } => Expr::Field(Field::AccessIdent { + Self::FieldAccessIdent { s0, s1, ident } => Expr::Field(Field::AccessIdent { expr, s0, s1, ident, span, }), - Suffix::FieldAssignIdent { + Self::FieldAssignIdent { s0, s1, ident, diff --git a/src/pretty/basic.rs b/src/pretty/basic.rs index 293c9a1..a7171fa 100644 --- a/src/pretty/basic.rs +++ b/src/pretty/basic.rs @@ -17,8 +17,8 @@ impl Separated { FS2: Fn(&'a D, S2) -> DocBuilder<'a, D>, { match self { - Separated::Empty(_) => allocator.nil(), - Separated::NonEmpty { + Self::Empty(_) => allocator.nil(), + Self::NonEmpty { first_elem, last_elems, trailing, diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index eeef8db..21e424f 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -5,14 +5,14 @@ use crate::ast::Expr; impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { - Expr::Lit(lit) => allocator.text(""), - Expr::Call(call) => allocator.text(""), - Expr::Field(field) => allocator.text(""), - Expr::Var(var) => allocator.text(""), - Expr::TableConstr(constr) => allocator.text(""), - Expr::TableDestr(destr) => allocator.text(""), - Expr::FuncDef(def) => allocator.text(""), - Expr::Paren { + Self::Lit(lit) => allocator.text(""), + Self::Call(call) => allocator.text(""), + Self::Field(field) => allocator.text(""), + Self::Var(var) => allocator.text(""), + Self::TableConstr(constr) => allocator.text(""), + Self::TableDestr(destr) => allocator.text(""), + Self::FuncDef(def) => allocator.text(""), + Self::Paren { s0, inner, s1, @@ -20,7 +20,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { } => inner.pretty(allocator).parens(), // TODO Check whether parentheses are necessary - Expr::Neg { + Self::Neg { minus: _, s0, expr, @@ -28,14 +28,14 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { } => allocator.text("-").append(expr.pretty(allocator)), // TODO Check whether parentheses are necessary - Expr::Not { + Self::Not { not: _, s0, expr, span: _, } => allocator.text("not ").append(expr.pretty(allocator)), - Expr::BinOp { + Self::BinOp { left, s0, op, diff --git a/src/pretty/program.rs b/src/pretty/program.rs index 22925af..327059d 100644 --- a/src/pretty/program.rs +++ b/src/pretty/program.rs @@ -5,13 +5,13 @@ use crate::ast::Program; impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Program { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { - Program::Expr { + Self::Expr { s0, expr, s1, span: _, } => expr.pretty(allocator), - Program::Module { + Self::Module { s0, s1, elems, From 4156006adaac28743ae796552bf9fa70f074e1e7 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 22:22:32 +0100 Subject: [PATCH 13/70] Pretty print literals partially --- src/pretty.rs | 1 + src/pretty/expr.rs | 2 +- src/pretty/lit.rs | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/pretty/lit.rs diff --git a/src/pretty.rs b/src/pretty.rs index f29ec0e..4a900f3 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -1,3 +1,4 @@ mod basic; mod expr; +mod lit; mod program; diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index 21e424f..fe2ed8f 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -5,7 +5,7 @@ use crate::ast::Expr; impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { - Self::Lit(lit) => allocator.text(""), + Self::Lit(lit) => lit.pretty(allocator), Self::Call(call) => allocator.text(""), Self::Field(field) => allocator.text(""), Self::Var(var) => allocator.text(""), diff --git a/src/pretty/lit.rs b/src/pretty/lit.rs new file mode 100644 index 0000000..d58fd24 --- /dev/null +++ b/src/pretty/lit.rs @@ -0,0 +1,17 @@ +use pretty::{DocAllocator, DocBuilder, Pretty}; + +use crate::ast::Lit; + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Lit { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + match self { + Self::Nil(_) => allocator.text("nil"), + Self::Bool(false, _) => allocator.text("false"), + Self::Bool(true, _) => allocator.text("true"), + Self::Builtin(builtin, _) => allocator.text(format!("{builtin:?}")), + Self::Num(num) => allocator.text(""), + Self::String(string) => allocator.text(""), + Self::Table(table) => allocator.text(""), + } + } +} From 7833ef533db308b31a18f9aa1c4ac5ae7c5f7482 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 22:52:19 +0100 Subject: [PATCH 14/70] Place parentheses in expressions when necessary --- src/ast/expr.rs | 50 +++++++++++++++++++++++-- src/pretty/expr.rs | 91 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 131 insertions(+), 10 deletions(-) diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 50a25ee..9b10502 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -4,18 +4,30 @@ use crate::span::{HasSpan, Span}; use super::{Call, Field, FuncDef, Lit, Space, TableConstr, TableDestr, Var}; +// Warning: If you change these precedences and associativities, you need to +// update the parser and pretty-printer as well. + +// Warning: Operators at the same precedence must also have the same +// associativity. + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Assoc { + Left, + Right, +} + #[derive(Debug, Clone, Copy)] pub enum BinOp { - /// `+` - Add, - /// `-` - Sub, /// `*` Mul, /// `/` Div, /// `%` Mod, + /// `+` + Add, + /// `-` + Sub, /// `==` Eq, /// `!=` @@ -34,6 +46,36 @@ pub enum BinOp { Or, } +impl BinOp { + /// The higher the precedence, the more strongly the operator binds. + pub fn precedence(self) -> u8 { + match self { + Self::Mul | Self::Div | Self::Mod => 4, + Self::Add | Self::Sub => 3, + Self::Eq | Self::Neq | Self::Gt | Self::Ge | Self::Lt | Self::Le => 2, + Self::And => 1, + Self::Or => 0, + } + } + + pub fn assoc(self) -> Assoc { + match self { + Self::Mul + | Self::Div + | Self::Mod + | Self::Add + | Self::Sub + | Self::Eq + | Self::Neq + | Self::Gt + | Self::Ge + | Self::Lt + | Self::Le => Assoc::Left, + Self::And | Self::Or => Assoc::Right, + } + } +} + #[derive(Clone)] pub enum Expr { Lit(Lit), diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index fe2ed8f..e75b7e8 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -1,6 +1,26 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; -use crate::ast::Expr; +use crate::ast::{Assoc, BinOp, Expr, Field, Var}; + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for BinOp { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + allocator.text(match self { + Self::Mul => "*", + Self::Div => "/", + Self::Mod => "%", + Self::Add => "+", + Self::Sub => "-", + Self::Eq => "==", + Self::Neq => "!=", + Self::Gt => ">", + Self::Ge => ">=", + Self::Lt => "<", + Self::Le => "<=", + Self::And => "and", + Self::Or => "or", + }) + } +} impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { @@ -19,22 +39,33 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { span: _, } => inner.pretty(allocator).parens(), - // TODO Check whether parentheses are necessary Self::Neg { minus: _, s0, expr, span: _, - } => allocator.text("-").append(expr.pretty(allocator)), + } => { + let parenthesize = matches!(*expr, Self::BinOp { .. }); + let inner = expr.pretty(allocator); + allocator + .text("-") + .append(if parenthesize { inner.parens() } else { inner }) + } - // TODO Check whether parentheses are necessary Self::Not { not: _, s0, expr, span: _, - } => allocator.text("not ").append(expr.pretty(allocator)), + } => { + let parenthesize = matches!(*expr, Self::BinOp { .. }); + let inner = expr.pretty(allocator); + allocator + .text("not ") + .append(if parenthesize { inner.parens() } else { inner }) + } + // TODO Add newlines and group properly Self::BinOp { left, s0, @@ -42,7 +73,55 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { s1, right, span: _, - } => allocator.text(""), + } => { + // If we're left-associative, then the left subexpression can be + // at the same precedence and the right subexpression must be at + // a higher precedence. + + // If we're right-associative, then the left subexpression must + // be at a higher precedence and the right subexpression can be + // at the same precedence. + + // Minimum precedence that the left subexpression can be at + // without requiring parentheses. + let min_left_prec = match op.assoc() { + Assoc::Left => op.precedence(), + Assoc::Right => op.precedence() + 1, + }; + + // Minimum precedence that the right subexpression can be at + // without requiring parentheses. + let min_right_prec = match op.assoc() { + Assoc::Left => op.precedence() + 1, + Assoc::Right => op.precedence(), + }; + + let left_paren = match *left { + // These end with an arbitrary expression on the right. If + // we don't add parentheses, we'll be assimilated into that + // expression. + Self::Field(Field::Assign { .. } | Field::AssignIdent { .. }) => true, + Self::Var(Var::Assign { .. } | Var::AssignIdent { .. }) => true, + + Self::BinOp { op, .. } if op.precedence() < min_left_prec => true, + + _ => false, + }; + + let right_paren = + matches!(*right, Self::BinOp { op, .. } if op.precedence() < min_right_prec); + + let left = left.pretty(allocator); + let left = if left_paren { left.parens() } else { left }; + + let right = right.pretty(allocator); + let right = if right_paren { right.parens() } else { right }; + + left.append(allocator.space()) + .append(op.pretty(allocator)) + .append(allocator.space()) + .append(right) + } } } } From e6bbb373230b4729abaa468b43e8a57f0c7847c4 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 22:59:14 +0100 Subject: [PATCH 15/70] Pretty print numeric literals --- src/pretty/expr.rs | 2 +- src/pretty/lit.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index e75b7e8..d402480 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -29,7 +29,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { Self::Call(call) => allocator.text(""), Self::Field(field) => allocator.text(""), Self::Var(var) => allocator.text(""), - Self::TableConstr(constr) => allocator.text(""), + Self::TableConstr(constr) => allocator.text(""), Self::TableDestr(destr) => allocator.text(""), Self::FuncDef(def) => allocator.text(""), Self::Paren { diff --git a/src/pretty/lit.rs b/src/pretty/lit.rs index d58fd24..d4eebb3 100644 --- a/src/pretty/lit.rs +++ b/src/pretty/lit.rs @@ -1,6 +1,12 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; -use crate::ast::Lit; +use crate::ast::{Lit, NumLit}; + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for NumLit { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + allocator.text(format!("{self:?}")) + } +} impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Lit { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { @@ -9,7 +15,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Lit { Self::Bool(false, _) => allocator.text("false"), Self::Bool(true, _) => allocator.text("true"), Self::Builtin(builtin, _) => allocator.text(format!("{builtin:?}")), - Self::Num(num) => allocator.text(""), + Self::Num(num) => num.pretty(allocator), Self::String(string) => allocator.text(""), Self::Table(table) => allocator.text("
"), } From f91e8ac9a2d5f0ec89d7ce070452593847f5f187 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 23:06:04 +0100 Subject: [PATCH 16/70] Pretty print string literals --- src/pretty/lit.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/pretty/lit.rs b/src/pretty/lit.rs index d4eebb3..6c58f62 100644 --- a/src/pretty/lit.rs +++ b/src/pretty/lit.rs @@ -1,6 +1,6 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; -use crate::ast::{Lit, NumLit}; +use crate::ast::{Lit, NumLit, StringLit, StringLitElem}; impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for NumLit { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { @@ -8,6 +8,28 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for NumLit { } } +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for StringLitElem { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + match self { + Self::Plain(str) => allocator.text(str), + Self::Unicode(char) => allocator.text(format!("\\u{{{:x}}}", char as u32)), + Self::Backslash => allocator.text("\\\\"), + Self::DoubleQuote => allocator.text("\\\""), + Self::Tab => allocator.text("\\t"), + Self::CarriageReturn => allocator.text("\\r"), + Self::Newline => allocator.text("\\n"), + } + } +} + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for StringLit { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + allocator + .concat(self.elems.into_iter().map(|e| e.pretty(allocator))) + .enclose(allocator.text("\""), allocator.text("\"")) + } +} + impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Lit { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { @@ -16,7 +38,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Lit { Self::Bool(true, _) => allocator.text("true"), Self::Builtin(builtin, _) => allocator.text(format!("{builtin:?}")), Self::Num(num) => num.pretty(allocator), - Self::String(string) => allocator.text(""), + Self::String(string) => string.pretty(allocator), Self::Table(table) => allocator.text("
"), } } From 412eaffc07b3e8cfc834727965bf589167bc8b1c Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 23:33:39 +0100 Subject: [PATCH 17/70] Pretty print table literals --- src/pretty.rs | 2 ++ src/pretty/basic.rs | 10 ++++++++-- src/pretty/lit.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/pretty.rs b/src/pretty.rs index 4a900f3..c375167 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -2,3 +2,5 @@ mod basic; mod expr; mod lit; mod program; + +const NEST_DEPTH: isize = 4; diff --git a/src/pretty/basic.rs b/src/pretty/basic.rs index a7171fa..918539e 100644 --- a/src/pretty/basic.rs +++ b/src/pretty/basic.rs @@ -1,6 +1,12 @@ -use pretty::{DocAllocator, DocBuilder}; +use pretty::{DocAllocator, DocBuilder, Pretty}; -use crate::ast::Separated; +use crate::ast::{Ident, Separated}; + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Ident { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + allocator.text(self.name) + } +} impl Separated { pub fn pretty<'a, D, FE, FS1, FS2>( diff --git a/src/pretty/lit.rs b/src/pretty/lit.rs index 6c58f62..e7263b5 100644 --- a/src/pretty/lit.rs +++ b/src/pretty/lit.rs @@ -1,6 +1,8 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; -use crate::ast::{Lit, NumLit, StringLit, StringLitElem}; +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> { @@ -30,6 +32,40 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for StringLit { } } +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableLitElem { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + match self { + Self::Positional(expr) => expr.pretty(allocator), + Self::Named { + name, + s0, + s1, + value, + span: _, + } => name + .pretty(allocator) + .append(allocator.text(": ")) + .append(value.pretty(allocator)), + } + } +} + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableLit { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + self.elems + .pretty( + allocator, + |a, e| a.line().append(e.pretty(a)), + |a, (s0, s1)| a.text(","), + |a, s| a.text(","), + ) + .nest(NEST_DEPTH) + .append(allocator.line()) + .enclose(allocator.text("'{"), allocator.text("}")) + .group() + } +} + impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Lit { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { @@ -39,7 +75,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Lit { Self::Builtin(builtin, _) => allocator.text(format!("{builtin:?}")), Self::Num(num) => num.pretty(allocator), Self::String(string) => string.pretty(allocator), - Self::Table(table) => allocator.text("
"), + Self::Table(table) => table.pretty(allocator), } } } From fc139c31f483bcd09b36ec3e28eb0dc93042e4db Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 23:41:39 +0100 Subject: [PATCH 18/70] Pretty print table constructors --- src/pretty.rs | 1 + src/pretty/expr.rs | 2 +- src/pretty/table_constr.rs | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/pretty/table_constr.rs diff --git a/src/pretty.rs b/src/pretty.rs index c375167..3a21e41 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -2,5 +2,6 @@ mod basic; mod expr; mod lit; mod program; +mod table_constr; const NEST_DEPTH: isize = 4; diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index d402480..f366edd 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -29,7 +29,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { Self::Call(call) => allocator.text(""), Self::Field(field) => allocator.text(""), Self::Var(var) => allocator.text(""), - Self::TableConstr(constr) => allocator.text(""), + Self::TableConstr(constr) => constr.pretty(allocator), Self::TableDestr(destr) => allocator.text(""), Self::FuncDef(def) => allocator.text(""), Self::Paren { diff --git a/src/pretty/table_constr.rs b/src/pretty/table_constr.rs new file mode 100644 index 0000000..288bf84 --- /dev/null +++ b/src/pretty/table_constr.rs @@ -0,0 +1,42 @@ +use pretty::{DocAllocator, DocBuilder, Pretty}; + +use crate::ast::{TableConstr, TableConstrElem}; + +use super::NEST_DEPTH; + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableConstrElem { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + match self { + Self::Lit(lit) => lit.pretty(allocator), + Self::Indexed { + s0, + index, + s1, + s2, + s3, + value, + span: _, + } => index + .pretty(allocator) + .brackets() + .append(allocator.text(": ")) + .append(value.pretty(allocator)), + } + } +} + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableConstr { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + self.elems + .pretty( + allocator, + |a, e| a.line().append(e.pretty(a)), + |a, (s0, s1)| a.text(","), + |a, s| a.text(","), + ) + .nest(NEST_DEPTH) + .append(allocator.line()) + .braces() + .group() + } +} From 81e2a28b0643097868e2e762c9f3c2a008df3c90 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 23:45:28 +0100 Subject: [PATCH 19/70] Pretty print function calls --- src/pretty.rs | 1 + src/pretty/call.rs | 32 ++++++++++++++++++++++++++++++++ src/pretty/expr.rs | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/pretty/call.rs diff --git a/src/pretty.rs b/src/pretty.rs index 3a21e41..bede489 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -1,4 +1,5 @@ mod basic; +mod call; mod expr; mod lit; mod program; diff --git a/src/pretty/call.rs b/src/pretty/call.rs new file mode 100644 index 0000000..84d2b5b --- /dev/null +++ b/src/pretty/call.rs @@ -0,0 +1,32 @@ +use pretty::{DocAllocator, DocBuilder, Pretty}; + +use crate::ast::Call; + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Call { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + match self { + Self::Arg { + expr, + s0, + s1, + arg, + s2, + span: _, + } => expr + .pretty(allocator) + .append(arg.pretty(allocator).parens()), + Self::NoArg { + expr, + s0, + s1, + span: _, + } => expr.pretty(allocator).append(allocator.nil().parens()), + Self::Constr { + expr, + s0, + constr, + span: _, + } => expr.pretty(allocator).append(constr.pretty(allocator)), + } + } +} diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index f366edd..bc8b2a8 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -26,7 +26,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { Self::Lit(lit) => lit.pretty(allocator), - Self::Call(call) => allocator.text(""), + Self::Call(call) => call.pretty(allocator), Self::Field(field) => allocator.text(""), Self::Var(var) => allocator.text(""), Self::TableConstr(constr) => constr.pretty(allocator), From 5bd43ee37af2fd59376f2556808ce6e094d4e5f2 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 23:50:53 +0100 Subject: [PATCH 20/70] Pretty print field accesses and assignments --- src/pretty.rs | 1 + src/pretty/expr.rs | 2 +- src/pretty/field.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/pretty/field.rs diff --git a/src/pretty.rs b/src/pretty.rs index bede489..b291f7a 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -1,6 +1,7 @@ mod basic; mod call; mod expr; +mod field; mod lit; mod program; mod table_constr; diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index bc8b2a8..161a8c7 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -27,7 +27,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { match self { Self::Lit(lit) => lit.pretty(allocator), Self::Call(call) => call.pretty(allocator), - Self::Field(field) => allocator.text(""), + Self::Field(field) => field.pretty(allocator), Self::Var(var) => allocator.text(""), Self::TableConstr(constr) => constr.pretty(allocator), Self::TableDestr(destr) => allocator.text(""), diff --git a/src/pretty/field.rs b/src/pretty/field.rs new file mode 100644 index 0000000..ce5b28f --- /dev/null +++ b/src/pretty/field.rs @@ -0,0 +1,64 @@ +use pretty::{DocAllocator, DocBuilder, Pretty}; + +use crate::ast::Field; + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Field { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + match self { + Self::Access { + expr, + s0, + s1, + index, + s2, + span: _, + } => expr + .pretty(allocator) + .append(index.pretty(allocator).brackets()), + Self::Assign { + expr, + s0, + s1, + index, + s2, + s3, + s4, + value, + span: _, + } => expr + .pretty(allocator) + .append(index.pretty(allocator).brackets()) + .append(allocator.text(" = ")) + .append(value.pretty(allocator)), + Self::AccessIdent { + expr, + s0, + s1, + ident, + span: _, + } => expr + .pretty(allocator) + .append(allocator.line_()) + .append(allocator.text(".")) + .append(ident.pretty(allocator)) + .group(), + Self::AssignIdent { + expr, + s0, + s1, + ident, + s2, + s3, + value, + span: _, + } => expr + .pretty(allocator) + .append(allocator.line_()) + .append(allocator.text(".")) + .append(ident.pretty(allocator)) + .append(allocator.text(" = ")) + .append(value.pretty(allocator)) + .group(), + } + } +} From c7fc8584ffe0eb24b329573d2dd93d1cc4331a42 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 00:02:10 +0100 Subject: [PATCH 21/70] Pretty print variable accesses and assignments --- src/pretty.rs | 1 + src/pretty/expr.rs | 2 +- src/pretty/var.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/pretty/var.rs diff --git a/src/pretty.rs b/src/pretty.rs index b291f7a..01a0dbb 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -5,5 +5,6 @@ mod field; mod lit; mod program; mod table_constr; +mod var; const NEST_DEPTH: isize = 4; diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index 161a8c7..4869084 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -28,7 +28,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { Self::Lit(lit) => lit.pretty(allocator), Self::Call(call) => call.pretty(allocator), Self::Field(field) => field.pretty(allocator), - Self::Var(var) => allocator.text(""), + Self::Var(var) => var.pretty(allocator), Self::TableConstr(constr) => constr.pretty(allocator), Self::TableDestr(destr) => allocator.text(""), Self::FuncDef(def) => allocator.text(""), diff --git a/src/pretty/var.rs b/src/pretty/var.rs new file mode 100644 index 0000000..a3b5418 --- /dev/null +++ b/src/pretty/var.rs @@ -0,0 +1,45 @@ +use pretty::{DocAllocator, DocBuilder, Pretty}; + +use crate::ast::Var; + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Var { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + match self { + Self::Access { + s0, + index, + s1, + span: _, + } => index.pretty(allocator).brackets(), + Self::Assign { + local, + s0, + index, + s1, + s2, + s3, + value, + span: _, + } => local + .map(|s| allocator.text("local ")) + .unwrap_or_else(|| allocator.nil()) + .append(index.pretty(allocator).brackets()) + .append(allocator.text(" = ")) + .append(value.pretty(allocator)), + Self::AccessIdent(ident) => ident.pretty(allocator), + Self::AssignIdent { + local, + name, + s0, + s1, + value, + span: _, + } => local + .map(|s| allocator.text("local ")) + .unwrap_or_else(|| allocator.nil()) + .append(name.pretty(allocator)) + .append(allocator.text(" = ")) + .append(value.pretty(allocator)), + } + } +} From e7416fbc1e4cf1c07da912145957dc37aa35b0dc Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 00:07:57 +0100 Subject: [PATCH 22/70] Pretty print table destructors --- src/pretty.rs | 1 + src/pretty/expr.rs | 2 +- src/pretty/table_destr.rs | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/pretty/table_destr.rs diff --git a/src/pretty.rs b/src/pretty.rs index 01a0dbb..149eb1c 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -5,6 +5,7 @@ mod field; mod lit; mod program; mod table_constr; +mod table_destr; mod var; const NEST_DEPTH: isize = 4; diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index 4869084..454651e 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -30,7 +30,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { Self::Field(field) => field.pretty(allocator), Self::Var(var) => var.pretty(allocator), Self::TableConstr(constr) => constr.pretty(allocator), - Self::TableDestr(destr) => allocator.text(""), + Self::TableDestr(destr) => destr.pretty(allocator), Self::FuncDef(def) => allocator.text(""), Self::Paren { s0, diff --git a/src/pretty/table_destr.rs b/src/pretty/table_destr.rs new file mode 100644 index 0000000..9191121 --- /dev/null +++ b/src/pretty/table_destr.rs @@ -0,0 +1,51 @@ +use pretty::{DocAllocator, DocBuilder, Pretty}; + +use crate::ast::{TableDestr, TablePattern, TablePatternElem}; + +use super::NEST_DEPTH; + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePatternElem { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + match self { + Self::Positional(ident) => ident.pretty(allocator), + Self::Named { + name, + s0, + s1, + ident, + span: _, + } => name + .pretty(allocator) + .append(allocator.text(": ")) + .append(ident.pretty(allocator)), + } + } +} + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePattern { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + self.elems + .pretty( + allocator, + |a, e| a.line().append(e.pretty(a)), + |a, (s0, s1)| a.text(","), + |a, s| a.text(","), + ) + .nest(NEST_DEPTH) + .append(allocator.line()) + .braces() + .group() + } +} + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableDestr { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + // TODO Handle spaces + self.local + .map(|s| allocator.text("local ")) + .unwrap_or_else(|| allocator.nil()) + .append(self.pattern.pretty(allocator)) + .append(allocator.text(" = ")) + .append(self.value.pretty(allocator)) + } +} From c45a45f0b6f12daa1156a3aacabc4bc920f00d88 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 00:08:59 +0100 Subject: [PATCH 23/70] Rename parser::func_defs to parser::func_def --- src/parser.rs | 4 ++-- src/parser/{func_defs.rs => func_def.rs} | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) rename src/parser/{func_defs.rs => func_def.rs} (98%) diff --git a/src/parser.rs b/src/parser.rs index 1650d97..ea6fa99 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -18,7 +18,7 @@ mod basic; mod expr; -mod func_defs; +mod func_def; mod lit; mod prefix; mod program; @@ -52,7 +52,7 @@ pub fn parser() -> impl Parser { table_pattern.clone(), expr.clone(), ); - let func_def = func_defs::func_def( + let func_def = func_def::func_def( space.clone(), ident.clone(), local, diff --git a/src/parser/func_defs.rs b/src/parser/func_def.rs similarity index 98% rename from src/parser/func_defs.rs rename to src/parser/func_def.rs index e290b95..54765f1 100644 --- a/src/parser/func_defs.rs +++ b/src/parser/func_def.rs @@ -1,5 +1,3 @@ -// TODO Rename this module to func_def for consistency - use chumsky::prelude::*; use crate::ast::{Expr, FuncDef, Ident, Space, TablePattern}; From b3eaa409027187cb4f365a229c613ceefe0139bd Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 00:16:15 +0100 Subject: [PATCH 24/70] Pretty print function definitions --- src/pretty.rs | 1 + src/pretty/expr.rs | 2 +- src/pretty/func_def.rs | 98 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/pretty/func_def.rs diff --git a/src/pretty.rs b/src/pretty.rs index 149eb1c..e15aa53 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -2,6 +2,7 @@ mod basic; mod call; mod expr; mod field; +mod func_def; mod lit; mod program; mod table_constr; diff --git a/src/pretty/expr.rs b/src/pretty/expr.rs index 454651e..7919963 100644 --- a/src/pretty/expr.rs +++ b/src/pretty/expr.rs @@ -31,7 +31,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Expr { Self::Var(var) => var.pretty(allocator), Self::TableConstr(constr) => constr.pretty(allocator), Self::TableDestr(destr) => destr.pretty(allocator), - Self::FuncDef(def) => allocator.text(""), + Self::FuncDef(def) => def.pretty(allocator), Self::Paren { s0, inner, diff --git a/src/pretty/func_def.rs b/src/pretty/func_def.rs new file mode 100644 index 0000000..6fd8140 --- /dev/null +++ b/src/pretty/func_def.rs @@ -0,0 +1,98 @@ +use pretty::{DocAllocator, DocBuilder, Pretty}; + +use crate::ast::FuncDef; + +impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for FuncDef { + fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { + match self { + Self::AnonNoArg { + s0, + s1, + s2, + body, + span: _, + } => allocator.text("function() ").append(body.pretty(allocator)), + + Self::AnonArg { + s0, + s1, + arg, + s2, + s3, + body, + span: _, + } => allocator + .text("function") + .append(arg.pretty(allocator).parens()) + .append(allocator.space()) + .append(body.pretty(allocator)), + + Self::AnonDestr { + s0, + pattern, + s1, + body, + span: _, + } => allocator + .text("function") + .append(pattern.pretty(allocator)) + .append(allocator.space()) + .append(body.pretty(allocator)), + + Self::NamedNoArg { + local, + s0, + name, + s1, + s2, + s3, + body, + span: _, + } => local + .map(|s| allocator.text("local ")) + .unwrap_or_else(|| allocator.nil()) + .append(allocator.text("function ")) + .append(name) + .append(allocator.text("() ")) + .append(body.pretty(allocator)), + + Self::NamedArg { + local, + s0, + name, + s1, + s2, + arg, + s3, + s4, + body, + span: _, + } => local + .map(|s| allocator.text("local ")) + .unwrap_or_else(|| allocator.nil()) + .append(allocator.text("function ")) + .append(name) + .append(arg.pretty(allocator).parens()) + .append(allocator.space()) + .append(body.pretty(allocator)), + + Self::NamedDestr { + local, + s0, + name, + s1, + pattern, + s2, + body, + span: _, + } => local + .map(|s| allocator.text("local ")) + .unwrap_or_else(|| allocator.nil()) + .append(allocator.text("function ")) + .append(name) + .append(pattern.pretty(allocator)) + .append(allocator.space()) + .append(body.pretty(allocator)), + } + } +} From 9d6cd580d435d38bab400d874f5ff09b9b29b79e Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 00:17:51 +0100 Subject: [PATCH 25/70] Pretty print module elems --- src/pretty/program.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pretty/program.rs b/src/pretty/program.rs index 327059d..1259c84 100644 --- a/src/pretty/program.rs +++ b/src/pretty/program.rs @@ -23,7 +23,7 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Program { .append(allocator.line()) .append(elems.pretty( allocator, - |a, e| a.text(""), + |a, e| e.pretty(a), |a, (s0, s1)| a.text(",").append(a.line()), |a, s| a.text(","), )), From 6eee1ba930a018f19140aa6e98fe8f0f99369a12 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 00:20:33 +0100 Subject: [PATCH 26/70] Simplify pretty printing separated elements --- src/pretty/basic.rs | 20 ++++++++++++-------- src/pretty/lit.rs | 6 +++--- src/pretty/program.rs | 6 +++--- src/pretty/table_constr.rs | 6 +++--- src/pretty/table_destr.rs | 6 +++--- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/pretty/basic.rs b/src/pretty/basic.rs index 918539e..b6812b0 100644 --- a/src/pretty/basic.rs +++ b/src/pretty/basic.rs @@ -18,9 +18,9 @@ impl Separated { ) -> DocBuilder<'a, D> where D: DocAllocator<'a>, - FE: Fn(&'a D, E) -> DocBuilder<'a, D>, - FS1: Fn(&'a D, S1) -> DocBuilder<'a, D>, - FS2: Fn(&'a D, S2) -> DocBuilder<'a, D>, + FE: Fn(E) -> DocBuilder<'a, D>, + FS1: Fn(S1) -> DocBuilder<'a, D>, + FS2: Fn(S2) -> DocBuilder<'a, D>, { match self { Self::Empty(_) => allocator.nil(), @@ -29,13 +29,17 @@ impl Separated { last_elems, trailing, span: _span, - } => elem_to_doc(allocator, first_elem) - .append(allocator.concat(last_elems.into_iter().map(|(s, e)| { - separator_to_doc(allocator, s).append(elem_to_doc(allocator, e)) - }))) + } => elem_to_doc(first_elem) + .append( + allocator.concat( + last_elems + .into_iter() + .map(|(s, e)| separator_to_doc(s).append(elem_to_doc(e))), + ), + ) .append( trailing - .map(|s| trailing_separator_to_doc(allocator, s)) + .map(trailing_separator_to_doc) .unwrap_or_else(|| allocator.nil()), ), } diff --git a/src/pretty/lit.rs b/src/pretty/lit.rs index e7263b5..45dd034 100644 --- a/src/pretty/lit.rs +++ b/src/pretty/lit.rs @@ -55,9 +55,9 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableLit { self.elems .pretty( allocator, - |a, e| a.line().append(e.pretty(a)), - |a, (s0, s1)| a.text(","), - |a, s| a.text(","), + |e| allocator.line().append(e.pretty(allocator)), + |(s0, s1)| allocator.text(","), + |s| allocator.text(","), ) .nest(NEST_DEPTH) .append(allocator.line()) diff --git a/src/pretty/program.rs b/src/pretty/program.rs index 1259c84..20c5cb1 100644 --- a/src/pretty/program.rs +++ b/src/pretty/program.rs @@ -23,9 +23,9 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Program { .append(allocator.line()) .append(elems.pretty( allocator, - |a, e| e.pretty(a), - |a, (s0, s1)| a.text(",").append(a.line()), - |a, s| a.text(","), + |e| e.pretty(allocator), + |(s0, s1)| allocator.text(",").append(allocator.line()), + |s| allocator.text(","), )), } } diff --git a/src/pretty/table_constr.rs b/src/pretty/table_constr.rs index 288bf84..5c9a058 100644 --- a/src/pretty/table_constr.rs +++ b/src/pretty/table_constr.rs @@ -30,9 +30,9 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableConstr { self.elems .pretty( allocator, - |a, e| a.line().append(e.pretty(a)), - |a, (s0, s1)| a.text(","), - |a, s| a.text(","), + |e| allocator.line().append(e.pretty(allocator)), + |(s0, s1)| allocator.text(","), + |s| allocator.text(","), ) .nest(NEST_DEPTH) .append(allocator.line()) diff --git a/src/pretty/table_destr.rs b/src/pretty/table_destr.rs index 9191121..50fab7b 100644 --- a/src/pretty/table_destr.rs +++ b/src/pretty/table_destr.rs @@ -27,9 +27,9 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePattern { self.elems .pretty( allocator, - |a, e| a.line().append(e.pretty(a)), - |a, (s0, s1)| a.text(","), - |a, s| a.text(","), + |e| allocator.line().append(e.pretty(allocator)), + |(s0, s1)| allocator.text(","), + |s| allocator.text(","), ) .nest(NEST_DEPTH) .append(allocator.line()) From 8b21acac9e88c4eb3206afe9589c79b623fa949c Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 09:32:07 +0100 Subject: [PATCH 27/70] Add desugar command and desugar programs --- src/ast/basic.rs | 9 ++++++++ src/desugar.rs | 1 + src/desugar/program.rs | 48 ++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 42 +++++++++++++++++++++++++----------- src/pretty.rs | 10 +++++++++ src/span.rs | 8 +++++++ 6 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 src/desugar.rs create mode 100644 src/desugar/program.rs diff --git a/src/ast/basic.rs b/src/ast/basic.rs index 33562f2..49d867f 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -30,6 +30,15 @@ impl HasSpan for Space { } } +impl Space { + pub fn empty(span: Span) -> Self { + Self { + lines: vec![], + span, + } + } +} + #[derive(Clone)] pub struct Ident { pub name: String, diff --git a/src/desugar.rs b/src/desugar.rs new file mode 100644 index 0000000..3847c62 --- /dev/null +++ b/src/desugar.rs @@ -0,0 +1 @@ +mod program; diff --git a/src/desugar/program.rs b/src/desugar/program.rs new file mode 100644 index 0000000..d97a6e0 --- /dev/null +++ b/src/desugar/program.rs @@ -0,0 +1,48 @@ +use crate::ast::{Expr, Lit, Program, Space, TableLit}; +use crate::span::HasSpan; + +impl Program { + pub fn desugar(self) -> (Self, bool) { + match self { + Self::Expr { s0, expr, s1, span } => { + let (expr, desugared) = (expr, false); // TODO Implement + (Self::Expr { s0, expr, s1, span }, desugared) + } + + Self::Module { + s0, + s1, + elems, + s2, + span, + } => { + let (elems, desugared) = (elems, false); // TODO Implement + if desugared { + let new = Self::Module { + s0, + s1, + elems, + s2, + span, + }; + (new, true) + } else { + let elems_span = elems.span(); + let table = TableLit { + s0: s1, + elems, + s1: Space::empty(elems_span.at_end()), + span: elems_span, + }; + let new = Self::Expr { + s0, + expr: Expr::Lit(Lit::Table(table)), + s1: s2, + span, + }; + (new, true) + } + } + } + } +} diff --git a/src/main.rs b/src/main.rs index 90cc696..0192a59 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,12 +17,13 @@ use std::fs; use std::path::PathBuf; -use ::pretty::{Pretty, RcAllocator}; +use anyhow::anyhow; use chumsky::Parser as _; use clap::Parser; mod ast; mod builtin; +mod desugar; mod parser; mod pretty; mod span; @@ -33,6 +34,7 @@ mod value; enum Command { Parse { file: PathBuf }, Pretty { file: PathBuf }, + Desugar { file: PathBuf }, } #[derive(Parser)] @@ -59,21 +61,37 @@ fn main() -> anyhow::Result<()> { } } } + Command::Pretty { file } => { let content = fs::read_to_string(&file)?; let stream = span::stream_from_str(&content); - match parser::parser().parse(stream) { - Ok(program) => { - let mut out = vec![]; - program.pretty(&RcAllocator).render(100, &mut out)?; - println!("{}", String::from_utf8(out)?); - } - Err(errs) => { - eprintln!("Parsing failed"); - for err in errs { - eprintln!("{err:?}"); - } + let program = parser::parser() + .parse(stream) + .map_err(|e| anyhow!("{e:?}"))?; + + println!("{}", pretty::pretty_to_string(program, 100)); + } + + Command::Desugar { file } => { + let content = fs::read_to_string(&file)?; + let stream = span::stream_from_str(&content); + let mut program = parser::parser() + .parse(stream) + .map_err(|e| anyhow!("{e:?}"))?; + + println!("{}", pretty::pretty_to_string(program.clone(), 100)); + + loop { + let (new_program, desugared) = program.desugar(); + program = new_program; + if !desugared { + break; } + + println!(); + println!("================================================================================"); + println!(); + println!("{}", pretty::pretty_to_string(program.clone(), 100)); } } } diff --git a/src/pretty.rs b/src/pretty.rs index e15aa53..20844f6 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -1,3 +1,5 @@ +use pretty::{Pretty, RcAllocator}; + mod basic; mod call; mod expr; @@ -10,3 +12,11 @@ mod table_destr; mod var; const NEST_DEPTH: isize = 4; + +pub fn pretty_to_string>(p: P, width: usize) -> String { + let mut out = vec![]; + p.pretty(&RcAllocator) + .render(width, &mut out) + .expect("p could not be rendered"); + String::from_utf8(out).expect("p created non-utf8 string") +} diff --git a/src/span.rs b/src/span.rs index 296f992..42cf32c 100644 --- a/src/span.rs +++ b/src/span.rs @@ -24,6 +24,14 @@ impl Span { let end = self.end.max(other.end); Self::new(start, end) } + + pub fn at_start(self) -> Self { + Self::new(self.start, self.start) + } + + pub fn at_end(self) -> Self { + Self::new(self.end, self.end) + } } impl fmt::Debug for Span { From 13b7db79b04e34e9cf67a9708d566fd72dd6bc06 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 11:35:58 +0100 Subject: [PATCH 28/70] Desugar separated elements --- src/desugar.rs | 1 + src/desugar/basic.rs | 36 ++++++++++++++++++++++++++++++++++++ src/desugar/program.rs | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/desugar/basic.rs diff --git a/src/desugar.rs b/src/desugar.rs index 3847c62..4fe06c6 100644 --- a/src/desugar.rs +++ b/src/desugar.rs @@ -1 +1,2 @@ +mod basic; mod program; diff --git a/src/desugar/basic.rs b/src/desugar/basic.rs new file mode 100644 index 0000000..ba2fde0 --- /dev/null +++ b/src/desugar/basic.rs @@ -0,0 +1,36 @@ +use crate::ast::Separated; + +impl Separated { + pub fn desugar_elem(self, desugar_elem: impl Fn(E) -> (E, bool)) -> (Self, bool) { + match self { + Self::Empty(span) => (Self::Empty(span), false), + + 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 { + new_last_elems.push((separator, elem)); + } else { + let (elem, elem_desugared) = desugar_elem(elem); + desugared = desugared || elem_desugared; + new_last_elems.push((separator, elem)); + } + } + + let new = Self::NonEmpty { + first_elem: new_first_elem, + last_elems: new_last_elems, + trailing, + span, + }; + (new, desugared) + } + } + } +} diff --git a/src/desugar/program.rs b/src/desugar/program.rs index d97a6e0..a1ef50e 100644 --- a/src/desugar/program.rs +++ b/src/desugar/program.rs @@ -16,7 +16,7 @@ impl Program { s2, span, } => { - let (elems, desugared) = (elems, false); // TODO Implement + let (elems, desugared) = elems.desugar_elem(|e| (e, false)); // TODO Implement if desugared { let new = Self::Module { s0, From 8278442d3f726609d6d57c5e773cd01dd56b2dd2 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 11:43:31 +0100 Subject: [PATCH 29/70] Expand expression desugaring --- src/desugar.rs | 1 + src/desugar/expr.rs | 79 ++++++++++++++++++++++++++++++++++++++++++ src/desugar/program.rs | 2 +- 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/desugar/expr.rs diff --git a/src/desugar.rs b/src/desugar.rs index 4fe06c6..f29ec0e 100644 --- a/src/desugar.rs +++ b/src/desugar.rs @@ -1,2 +1,3 @@ mod basic; +mod expr; mod program; diff --git a/src/desugar/expr.rs b/src/desugar/expr.rs new file mode 100644 index 0000000..7390148 --- /dev/null +++ b/src/desugar/expr.rs @@ -0,0 +1,79 @@ +use crate::ast::Expr; + +impl Expr { + pub fn desugar(self) -> (Self, bool) { + match self { + Self::Lit(lit) => (Self::Lit(lit), false), // TODO Implement + Self::Call(call) => (Self::Call(call), false), // TODO Implement + Self::Field(field) => (Self::Field(field), false), // TODO Implement + Self::Var(var) => (Self::Var(var), false), // TODO Implement + Self::TableConstr(constr) => (Self::TableConstr(constr), false), // TODO Implement + Self::TableDestr(destr) => (Self::TableDestr(destr), false), // TODO Implement + Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement + + Self::Paren { + s0, + inner, + s1, + span, + } => ( + Self::Paren { + s0, + inner, + s1, + span, + }, + false, + ), // TODO Implement + + Self::Neg { + minus, + s0, + expr, + span, + } => ( + Self::Neg { + minus, + s0, + expr, + span, + }, + false, + ), // TODO Implement + + Self::Not { + not, + s0, + expr, + span, + } => ( + Self::Not { + not, + s0, + expr, + span, + }, + false, + ), // TODO Implement + + Self::BinOp { + left, + s0, + op, + s1, + right, + span, + } => ( + Self::BinOp { + left, + s0, + op, + s1, + right, + span, + }, + false, + ), // TODO Implement + } + } +} diff --git a/src/desugar/program.rs b/src/desugar/program.rs index a1ef50e..17f9d79 100644 --- a/src/desugar/program.rs +++ b/src/desugar/program.rs @@ -5,7 +5,7 @@ impl Program { pub fn desugar(self) -> (Self, bool) { match self { Self::Expr { s0, expr, s1, span } => { - let (expr, desugared) = (expr, false); // TODO Implement + let (expr, desugared) = expr.desugar(); (Self::Expr { s0, expr, s1, span }, desugared) } From 52c1aeba35959361f0d9ea47e978f163a66ebf66 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 12:05:24 +0100 Subject: [PATCH 30/70] Desugar literals --- src/desugar.rs | 1 + src/desugar/expr.rs | 8 +++++-- src/desugar/lit.rs | 54 ++++++++++++++++++++++++++++++++++++++++++ src/desugar/program.rs | 2 +- 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/desugar/lit.rs diff --git a/src/desugar.rs b/src/desugar.rs index f29ec0e..4a900f3 100644 --- a/src/desugar.rs +++ b/src/desugar.rs @@ -1,3 +1,4 @@ mod basic; mod expr; +mod lit; mod program; diff --git a/src/desugar/expr.rs b/src/desugar/expr.rs index 7390148..1ee7e06 100644 --- a/src/desugar/expr.rs +++ b/src/desugar/expr.rs @@ -3,10 +3,14 @@ use crate::ast::Expr; impl Expr { pub fn desugar(self) -> (Self, bool) { match self { - Self::Lit(lit) => (Self::Lit(lit), false), // TODO Implement + Self::Lit(lit) => { + let (lit, desugared) = lit.desugar(); + (Self::Lit(lit), desugared) + } + Self::Call(call) => (Self::Call(call), false), // TODO Implement Self::Field(field) => (Self::Field(field), false), // TODO Implement - Self::Var(var) => (Self::Var(var), false), // TODO Implement + Self::Var(var) => (Self::Var(var), false), // TODO Implement Self::TableConstr(constr) => (Self::TableConstr(constr), false), // TODO Implement Self::TableDestr(destr) => (Self::TableDestr(destr), false), // TODO Implement Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement diff --git a/src/desugar/lit.rs b/src/desugar/lit.rs new file mode 100644 index 0000000..56c9e0f --- /dev/null +++ b/src/desugar/lit.rs @@ -0,0 +1,54 @@ +use crate::ast::{Lit, TableLit, TableLitElem}; + +impl TableLitElem { + pub fn desugar(self) -> (Self, bool) { + match self { + Self::Positional(expr) => { + let (expr, desugared) = expr.desugar(); + (Self::Positional(Box::new(expr)), desugared) + } + Self::Named { + name, + s0, + s1, + value, + span, + } => { + let (value, desugared) = value.desugar(); + let new = Self::Named { + name, + s0, + s1, + value: Box::new(value), + span, + }; + (new, desugared) + } + } + } +} + +impl TableLit { + pub fn desugar(self) -> (Self, bool) { + let (elems, desugared) = self.elems.desugar_elem(|e| e.desugar()); + let new = Self { + s0: self.s0, + elems, + s1: self.s1, + span: self.span, + }; + (new, desugared) + } +} + +impl Lit { + pub fn desugar(self) -> (Self, bool) { + match self { + Self::Table(table) => { + let (table, desugared) = table.desugar(); + (Self::Table(table), desugared) + } + lit => (lit, false), + } + } +} diff --git a/src/desugar/program.rs b/src/desugar/program.rs index 17f9d79..6598fed 100644 --- a/src/desugar/program.rs +++ b/src/desugar/program.rs @@ -16,7 +16,7 @@ impl Program { s2, span, } => { - let (elems, desugared) = elems.desugar_elem(|e| (e, false)); // TODO Implement + let (elems, desugared) = elems.desugar_elem(|e| e.desugar()); if desugared { let new = Self::Module { s0, From a3d6efcaec9d2c7d1f544321c1df9a4e94c489fd Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 12:35:53 +0100 Subject: [PATCH 31/70] Desugar function calls without args --- src/desugar.rs | 1 + src/desugar/call.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++ src/desugar/expr.rs | 5 ++-- 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 src/desugar/call.rs diff --git a/src/desugar.rs b/src/desugar.rs index 4a900f3..f99da41 100644 --- a/src/desugar.rs +++ b/src/desugar.rs @@ -1,4 +1,5 @@ mod basic; +mod call; mod expr; mod lit; mod program; diff --git a/src/desugar/call.rs b/src/desugar/call.rs new file mode 100644 index 0000000..7dff8a8 --- /dev/null +++ b/src/desugar/call.rs @@ -0,0 +1,67 @@ +use crate::ast::{Call, Expr, Lit, Space}; +use crate::span::HasSpan; + +impl Call { + pub fn desugar(self) -> (Expr, bool) { + match self { + Self::Arg { + expr, + s0, + s1, + arg, + s2, + span, + } => { + let new = Expr::Call(Self::Arg { + expr, + s0, + s1, + arg, + s2, + span, + }); + (new, false) // TODO Implement + } + + Self::NoArg { expr, s0, s1, span } => { + let (expr, desugared) = expr.desugar(); + if desugared { + let new = Expr::Call(Self::NoArg { + expr: Box::new(expr), + s0, + s1, + span, + }); + return (new, true); + } + + let arg_span = s1.span().at_start(); + let arg = Expr::Lit(Lit::Nil(arg_span)); + let new = Expr::Call(Self::Arg { + expr: Box::new(expr), + s0, + s1, + arg: Box::new(arg), + s2: Space::empty(arg_span.at_end()), + span, + }); + (new, true) + } + + Self::Constr { + expr, + s0, + constr, + span, + } => { + let new = Expr::Call(Self::Constr { + expr, + s0, + constr, + span, + }); + (new, false) // TODO Implement + } + } + } +} diff --git a/src/desugar/expr.rs b/src/desugar/expr.rs index 1ee7e06..5877228 100644 --- a/src/desugar/expr.rs +++ b/src/desugar/expr.rs @@ -8,9 +8,10 @@ impl Expr { (Self::Lit(lit), desugared) } - Self::Call(call) => (Self::Call(call), false), // TODO Implement + Self::Call(call) => call.desugar(), + Self::Field(field) => (Self::Field(field), false), // TODO Implement - Self::Var(var) => (Self::Var(var), false), // TODO Implement + Self::Var(var) => (Self::Var(var), false), // TODO Implement Self::TableConstr(constr) => (Self::TableConstr(constr), false), // TODO Implement Self::TableDestr(destr) => (Self::TableDestr(destr), false), // TODO Implement Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement From 29aa474b6a6378b1bbcb9c2d140769f98b15d15a Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 13:01:15 +0100 Subject: [PATCH 32/70] Use diff tool to visualize desugaring changes --- Cargo.lock | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 48 ++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 90 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5cd11a..53d7c73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,6 +120,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + [[package]] name = "getrandom" version = "0.2.8" @@ -146,6 +155,15 @@ dependencies = [ "libc", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "libc" version = "0.2.137" @@ -233,6 +251,24 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "strsim" version = "0.10.0" @@ -258,6 +294,21 @@ dependencies = [ "chumsky", "clap", "pretty", + "tempfile", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3a7b52e..2e725f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ anyhow = "1.0.66" chumsky = "0.8.0" clap = { version = "4.0.26", features = ["derive", "deprecated"] } pretty = "0.11.3" +tempfile = "3.3.0" diff --git a/src/main.rs b/src/main.rs index 0192a59..a40fedc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,8 +14,9 @@ // Clippy lints #![warn(clippy::use_self)] -use std::fs; +use std::io::Write; use std::path::PathBuf; +use std::{fs, process}; use anyhow::anyhow; use chumsky::Parser as _; @@ -32,9 +33,19 @@ mod value; #[derive(Parser)] enum Command { - Parse { file: PathBuf }, - Pretty { file: PathBuf }, - Desugar { file: PathBuf }, + Parse { + file: PathBuf, + }, + Pretty { + file: PathBuf, + }, + Desugar { + file: PathBuf, + #[arg(long, short, default_value = "diff")] + difftool: String, + #[arg(long, short = 'a')] + diffarg: Vec, + }, } #[derive(Parser)] @@ -72,14 +83,23 @@ fn main() -> anyhow::Result<()> { println!("{}", pretty::pretty_to_string(program, 100)); } - Command::Desugar { file } => { + Command::Desugar { + file, + difftool, + diffarg, + } => { let content = fs::read_to_string(&file)?; let stream = span::stream_from_str(&content); let mut program = parser::parser() .parse(stream) .map_err(|e| anyhow!("{e:?}"))?; - println!("{}", pretty::pretty_to_string(program.clone(), 100)); + let mut builder = tempfile::Builder::new(); + builder.suffix(".tada"); + + let mut prev = builder.tempfile()?; + prev.write_all(pretty::pretty_to_string(program.clone(), 100).as_bytes())?; + prev.flush()?; loop { let (new_program, desugared) = program.desugar(); @@ -88,10 +108,18 @@ fn main() -> anyhow::Result<()> { break; } - println!(); - println!("================================================================================"); - println!(); - println!("{}", pretty::pretty_to_string(program.clone(), 100)); + let mut cur = builder.tempfile()?; + cur.write_all(pretty::pretty_to_string(program.clone(), 100).as_bytes())?; + cur.flush()?; + + process::Command::new(&difftool) + .args(&diffarg) + .arg(prev.path()) + .arg(cur.path()) + .spawn()? + .wait()?; + + prev = cur; } } } From 7bfaebc05f6a58d605c75e030da319f9e48f93e1 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 13:07:10 +0100 Subject: [PATCH 33/70] Desugar function calls with table constructor --- src/desugar/call.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/desugar/call.rs b/src/desugar/call.rs index 7dff8a8..b78c77f 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -1,3 +1,5 @@ +use chumsky::Span; + use crate::ast::{Call, Expr, Lit, Space}; use crate::span::HasSpan; @@ -54,13 +56,28 @@ impl Call { constr, span, } => { - let new = Expr::Call(Self::Constr { - expr, + let (expr, desugared) = expr.desugar(); + if desugared { + let new = Expr::Call(Self::Constr { + expr: Box::new(expr), + s0, + constr, + span, + }); + return (new, true); + } + + let arg = Expr::TableConstr(constr); + let arg_span = arg.span(); + let new = Expr::Call(Self::Arg { + expr: Box::new(expr), s0, - constr, + s1: Space::empty(arg_span.at_start()), + arg: Box::new(arg), + s2: Space::empty(arg_span.at_end()), span, }); - (new, false) // TODO Implement + (new, true) } } } From 5c8dd1969f640e82f439e190eef1c50ab9b1c8d2 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 13:27:07 +0100 Subject: [PATCH 34/70] Desugar function calls with argument --- src/ast/basic.rs | 9 +++++++ src/desugar/call.rs | 66 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index 49d867f..e78a9bf 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -45,6 +45,15 @@ pub struct Ident { pub span: Span, } +impl Ident { + pub fn new(name: S, span: Span) -> Self { + Self { + name: name.to_string(), + span, + } + } +} + impl fmt::Debug for Ident { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "i#{}", self.name) diff --git a/src/desugar/call.rs b/src/desugar/call.rs index b78c77f..52cd41f 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -1,8 +1,8 @@ -use chumsky::Span; - -use crate::ast::{Call, Expr, Lit, Space}; +use crate::ast::{Call, Expr, Ident, Lit, Separated, Space, TableLit, TableLitElem}; use crate::span::HasSpan; +// TODO Add span for just the parentheses to ast, or limit span to parentheses + impl Call { pub fn desugar(self) -> (Expr, bool) { match self { @@ -14,15 +14,59 @@ impl Call { s2, span, } => { - let new = Expr::Call(Self::Arg { - expr, - s0, - s1, - arg, - s2, + let (expr, desugared) = expr.desugar(); + if desugared { + let new = Expr::Call(Self::Arg { + expr: Box::new(expr), + s0, + s1, + arg, + s2, + span, + }); + return (new, true); + } + + let (arg, desugared) = arg.desugar(); + if desugared { + let new = Expr::Call(Self::Arg { + expr: Box::new(expr), + s0, + s1, + arg: Box::new(arg), + s2, + span, + }); + return (new, true); + } + + let call = TableLitElem::Named { + name: Ident::new("call", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: Box::new(expr), span, - }); - (new, false) // TODO Implement + }; + let arg = TableLitElem::Named { + name: Ident::new("arg", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: Box::new(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: Space::empty(span), + elems, + s1: Space::empty(span), + span, + })); + (new, true) } Self::NoArg { expr, s0, s1, span } => { From b84d5ae0c8a8ebedab1e6f8217e5384fd2723a6d Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 13:33:40 +0100 Subject: [PATCH 35/70] Create new objects with existing span I've decided that attempting to create smaller spans is more difficult and will also lead to worse error messages later on. It makes more sense to just tag every newly created syntax tree element with the span of the element it comes from. --- src/desugar/call.rs | 11 ++++------- src/desugar/program.rs | 32 +++++++++++++++----------------- src/span.rs | 8 -------- 3 files changed, 19 insertions(+), 32 deletions(-) diff --git a/src/desugar/call.rs b/src/desugar/call.rs index 52cd41f..339c956 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -1,5 +1,4 @@ use crate::ast::{Call, Expr, Ident, Lit, Separated, Space, TableLit, TableLitElem}; -use crate::span::HasSpan; // TODO Add span for just the parentheses to ast, or limit span to parentheses @@ -81,14 +80,13 @@ impl Call { return (new, true); } - let arg_span = s1.span().at_start(); - let arg = Expr::Lit(Lit::Nil(arg_span)); + let arg = Expr::Lit(Lit::Nil(span)); let new = Expr::Call(Self::Arg { expr: Box::new(expr), s0, s1, arg: Box::new(arg), - s2: Space::empty(arg_span.at_end()), + s2: Space::empty(span), span, }); (new, true) @@ -112,13 +110,12 @@ impl Call { } let arg = Expr::TableConstr(constr); - let arg_span = arg.span(); let new = Expr::Call(Self::Arg { expr: Box::new(expr), s0, - s1: Space::empty(arg_span.at_start()), + s1: Space::empty(span), arg: Box::new(arg), - s2: Space::empty(arg_span.at_end()), + s2: Space::empty(span), span, }); (new, true) diff --git a/src/desugar/program.rs b/src/desugar/program.rs index 6598fed..a529b07 100644 --- a/src/desugar/program.rs +++ b/src/desugar/program.rs @@ -1,5 +1,4 @@ use crate::ast::{Expr, Lit, Program, Space, TableLit}; -use crate::span::HasSpan; impl Program { pub fn desugar(self) -> (Self, bool) { @@ -25,23 +24,22 @@ impl Program { s2, span, }; - (new, true) - } else { - let elems_span = elems.span(); - let table = TableLit { - s0: s1, - elems, - s1: Space::empty(elems_span.at_end()), - span: elems_span, - }; - let new = Self::Expr { - s0, - expr: Expr::Lit(Lit::Table(table)), - s1: s2, - span, - }; - (new, true) + return (new, true); } + + let table = TableLit { + s0: s1, + elems, + s1: Space::empty(span), + span, + }; + let new = Self::Expr { + s0, + expr: Expr::Lit(Lit::Table(table)), + s1: s2, + span, + }; + (new, true) } } } diff --git a/src/span.rs b/src/span.rs index 42cf32c..296f992 100644 --- a/src/span.rs +++ b/src/span.rs @@ -24,14 +24,6 @@ impl Span { let end = self.end.max(other.end); Self::new(start, end) } - - pub fn at_start(self) -> Self { - Self::new(self.start, self.start) - } - - pub fn at_end(self) -> Self { - Self::new(self.end, self.end) - } } impl fmt::Debug for Span { From 3f8320941a8d0468d77bd258b0301e0b63e47f86 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 13:49:37 +0100 Subject: [PATCH 36/70] Desugar field access --- src/desugar.rs | 1 + src/desugar/expr.rs | 4 +- src/desugar/field.rs | 133 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 src/desugar/field.rs diff --git a/src/desugar.rs b/src/desugar.rs index f99da41..c1037be 100644 --- a/src/desugar.rs +++ b/src/desugar.rs @@ -1,5 +1,6 @@ mod basic; mod call; mod expr; +mod field; mod lit; mod program; diff --git a/src/desugar/expr.rs b/src/desugar/expr.rs index 5877228..022592a 100644 --- a/src/desugar/expr.rs +++ b/src/desugar/expr.rs @@ -9,9 +9,9 @@ impl Expr { } Self::Call(call) => call.desugar(), + Self::Field(field) => field.desugar(), - Self::Field(field) => (Self::Field(field), false), // TODO Implement - Self::Var(var) => (Self::Var(var), false), // TODO Implement + Self::Var(var) => (Self::Var(var), false), // TODO Implement Self::TableConstr(constr) => (Self::TableConstr(constr), false), // TODO Implement Self::TableDestr(destr) => (Self::TableDestr(destr), false), // TODO Implement Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement diff --git a/src/desugar/field.rs b/src/desugar/field.rs new file mode 100644 index 0000000..fb086f3 --- /dev/null +++ b/src/desugar/field.rs @@ -0,0 +1,133 @@ +use crate::ast::{ + Call, Expr, Field, Lit, Separated, Space, TableConstr, TableConstrElem, TableLitElem, +}; +use crate::builtin::Builtin; + +impl Field { + pub fn desugar(self) -> (Expr, bool) { + match self { + Self::Access { + expr, + s0, + s1, + index, + s2, + span, + } => { + let (expr, desugared) = expr.desugar(); + if desugared { + let new = Expr::Field(Self::Access { + expr: Box::new(expr), + s0, + s1, + index, + s2, + span, + }); + return (new, true); + } + + let (index, desugared) = index.desugar(); + if desugared { + let new = Expr::Field(Self::Access { + expr: Box::new(expr), + s0, + s1, + index: Box::new(index), + s2, + span, + }); + return (new, true); + } + + let elems = Separated::NonEmpty { + first_elem: TableConstrElem::Lit(TableLitElem::Positional(Box::new(expr))), + last_elems: vec![( + (Space::empty(span), Space::empty(span)), + TableConstrElem::Lit(TableLitElem::Positional(Box::new(index))), + )], + 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::Get, span))), + s0: Space::empty(span), + constr, + span, + }); + (new, true) + } + + Self::Assign { + expr, + s0, + s1, + index, + s2, + s3, + s4, + value, + span, + } => { + let new = Expr::Field(Self::Assign { + expr, + s0, + s1, + index, + s2, + s3, + s4, + value, + span, + }); + (new, true) // TODO Implement + } + + Self::AccessIdent { + expr, + s0, + s1, + ident, + span, + } => { + let new = Expr::Field(Self::AccessIdent { + expr, + s0, + s1, + ident, + span, + }); + (new, false) // TODO Implement + } + + Self::AssignIdent { + expr, + s0, + s1, + ident, + s2, + s3, + value, + span, + } => { + let new = Expr::Field(Self::AssignIdent { + expr, + s0, + s1, + ident, + s2, + s3, + value, + span, + }); + (new, false) // TODO Implement + } + } + } +} From ebc48fff5a85adbff2c6d01e3dbef7a15c9acf92 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 14:05:07 +0100 Subject: [PATCH 37/70] Desugar field assignment --- src/desugar/field.rs | 84 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/src/desugar/field.rs b/src/desugar/field.rs index fb086f3..31df828 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -75,18 +75,82 @@ impl Field { value, span, } => { - let new = Expr::Field(Self::Assign { - expr, - s0, - s1, - index, - s2, - s3, - s4, - value, + let (expr, desugared) = expr.desugar(); + if desugared { + let new = Expr::Field(Self::Assign { + expr: Box::new(expr), + s0, + s1, + index, + s2, + s3, + s4, + value, + span, + }); + return (new, true); + } + + let (index, desugared) = index.desugar(); + if desugared { + let new = Expr::Field(Self::Assign { + expr: Box::new(expr), + s0, + s1, + index: Box::new(index), + s2, + s3, + s4, + value, + span, + }); + return (new, true); + } + + let (value, desugared) = value.desugar(); + if desugared { + let new = Expr::Field(Self::Assign { + expr: Box::new(expr), + s0, + s1, + index: Box::new(index), + s2, + s3, + s4, + value: Box::new(value), + span, + }); + return (new, true); + } + + let elems = Separated::NonEmpty { + first_elem: TableConstrElem::Lit(TableLitElem::Positional(Box::new(expr))), + last_elems: vec![ + ( + (Space::empty(span), Space::empty(span)), + TableConstrElem::Lit(TableLitElem::Positional(Box::new(index))), + ), + ( + (Space::empty(span), Space::empty(span)), + TableConstrElem::Lit(TableLitElem::Positional(Box::new(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: Space::empty(span), + constr, span, }); - (new, true) // TODO Implement + (new, true) } Self::AccessIdent { From 290cef06cbe4ddace38b2b090edef4d4c8d9583c Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 14:35:10 +0100 Subject: [PATCH 38/70] Desugar from the outside in --- src/ast/basic.rs | 11 +++++ src/desugar/call.rs | 74 ++++++------------------------ src/desugar/field.rs | 102 +++++++---------------------------------- src/desugar/lit.rs | 19 ++++++-- src/desugar/program.rs | 21 +++------ 5 files changed, 62 insertions(+), 165 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index e78a9bf..b9e5df0 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -37,6 +37,17 @@ impl Space { 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)] diff --git a/src/desugar/call.rs b/src/desugar/call.rs index 339c956..690f99e 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -13,44 +13,20 @@ impl Call { s2, span, } => { - let (expr, desugared) = expr.desugar(); - if desugared { - let new = Expr::Call(Self::Arg { - expr: Box::new(expr), - s0, - s1, - arg, - s2, - span, - }); - return (new, true); - } - - let (arg, desugared) = arg.desugar(); - if desugared { - let new = Expr::Call(Self::Arg { - expr: Box::new(expr), - s0, - s1, - arg: Box::new(arg), - s2, - span, - }); - return (new, true); - } - + // `expr s0 ( s1 arg s2 )` + // -> `'{ s0 call: expr, arg: s1 arg s2 }` let call = TableLitElem::Named { name: Ident::new("call", span), s0: Space::empty(span), s1: Space::empty(span), - value: Box::new(expr), + value: expr, span, }; let arg = TableLitElem::Named { name: Ident::new("arg", span), s0: Space::empty(span), - s1: Space::empty(span), - value: Box::new(arg), + s1, + value: arg, span, }; let elems = Separated::NonEmpty { @@ -60,32 +36,22 @@ impl Call { span, }; let new = Expr::Lit(Lit::Table(TableLit { - s0: Space::empty(span), + s0, elems, - s1: Space::empty(span), + s1: s2, span, })); (new, true) } Self::NoArg { expr, s0, s1, span } => { - let (expr, desugared) = expr.desugar(); - if desugared { - let new = Expr::Call(Self::NoArg { - expr: Box::new(expr), - s0, - s1, - span, - }); - return (new, true); - } - - let arg = Expr::Lit(Lit::Nil(span)); + // `expr s0 ( s1 )` + // -> `expr s0 ( s1 nil )` let new = Expr::Call(Self::Arg { - expr: Box::new(expr), + expr, s0, s1, - arg: Box::new(arg), + arg: Box::new(Expr::Lit(Lit::Nil(span))), s2: Space::empty(span), span, }); @@ -98,23 +64,13 @@ impl Call { constr, span, } => { - let (expr, desugared) = expr.desugar(); - if desugared { - let new = Expr::Call(Self::Constr { - expr: Box::new(expr), - s0, - constr, - span, - }); - return (new, true); - } - - let arg = Expr::TableConstr(constr); + // `expr s0 {..}` + // -> `expr s0 ( {..} )` let new = Expr::Call(Self::Arg { - expr: Box::new(expr), + expr, s0, s1: Space::empty(span), - arg: Box::new(arg), + arg: Box::new(Expr::TableConstr(constr)), s2: Space::empty(span), span, }); diff --git a/src/desugar/field.rs b/src/desugar/field.rs index 31df828..8a8b9c2 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -1,5 +1,5 @@ use crate::ast::{ - Call, Expr, Field, Lit, Separated, Space, TableConstr, TableConstrElem, TableLitElem, + Call, Expr, Field, Line, Lit, Separated, Space, TableConstr, TableConstrElem, TableLitElem, }; use crate::builtin::Builtin; @@ -14,37 +14,13 @@ impl Field { s2, span, } => { - let (expr, desugared) = expr.desugar(); - if desugared { - let new = Expr::Field(Self::Access { - expr: Box::new(expr), - s0, - s1, - index, - s2, - span, - }); - return (new, true); - } - - let (index, desugared) = index.desugar(); - if desugared { - let new = Expr::Field(Self::Access { - expr: Box::new(expr), - s0, - s1, - index: Box::new(index), - s2, - span, - }); - return (new, true); - } - + // ` expr s0 [ s1 index s2 ]` + // -> `'get s0 { expr, s1 index s2 }` let elems = Separated::NonEmpty { - first_elem: TableConstrElem::Lit(TableLitElem::Positional(Box::new(expr))), + first_elem: TableConstrElem::Lit(TableLitElem::Positional(expr)), last_elems: vec![( - (Space::empty(span), Space::empty(span)), - TableConstrElem::Lit(TableLitElem::Positional(Box::new(index))), + (Space::empty(span), s1), + TableConstrElem::Lit(TableLitElem::Positional(index)), )], trailing: None, span, @@ -52,12 +28,12 @@ impl Field { let constr = TableConstr { s0: Space::empty(span), elems, - s1: Space::empty(span), + s1: s2, span, }; let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Get, span))), - s0: Space::empty(span), + s0, constr, span, }); @@ -75,64 +51,18 @@ impl Field { value, span, } => { - let (expr, desugared) = expr.desugar(); - if desugared { - let new = Expr::Field(Self::Assign { - expr: Box::new(expr), - s0, - s1, - index, - s2, - s3, - s4, - value, - span, - }); - return (new, true); - } - - let (index, desugared) = index.desugar(); - if desugared { - let new = Expr::Field(Self::Assign { - expr: Box::new(expr), - s0, - s1, - index: Box::new(index), - s2, - s3, - s4, - value, - span, - }); - return (new, true); - } - - let (value, desugared) = value.desugar(); - if desugared { - let new = Expr::Field(Self::Assign { - expr: Box::new(expr), - s0, - s1, - index: Box::new(index), - s2, - s3, - s4, - value: Box::new(value), - span, - }); - return (new, true); - } - + // `expr s0 [ s1 index s2 ] s3 = s4 value` + // -> `'set s0 { expr, s1 index s2, s3 s4 value }` let elems = Separated::NonEmpty { - first_elem: TableConstrElem::Lit(TableLitElem::Positional(Box::new(expr))), + first_elem: TableConstrElem::Lit(TableLitElem::Positional(expr)), last_elems: vec![ ( - (Space::empty(span), Space::empty(span)), - TableConstrElem::Lit(TableLitElem::Positional(Box::new(index))), + (Space::empty(span), s1), + TableConstrElem::Lit(TableLitElem::Positional(index)), ), ( - (Space::empty(span), Space::empty(span)), - TableConstrElem::Lit(TableLitElem::Positional(Box::new(value))), + (s2, s3.then_line(Line::Empty).then(s4)), + TableConstrElem::Lit(TableLitElem::Positional(value)), ), ], trailing: None, @@ -146,7 +76,7 @@ impl Field { }; let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Set, span))), - s0: Space::empty(span), + s0, constr, span, }); diff --git a/src/desugar/lit.rs b/src/desugar/lit.rs index 56c9e0f..348c3c7 100644 --- a/src/desugar/lit.rs +++ b/src/desugar/lit.rs @@ -7,6 +7,7 @@ impl TableLitElem { let (expr, desugared) = expr.desugar(); (Self::Positional(Box::new(expr)), desugared) } + Self::Named { name, s0, @@ -30,12 +31,19 @@ impl TableLitElem { impl TableLit { pub fn desugar(self) -> (Self, bool) { - let (elems, desugared) = self.elems.desugar_elem(|e| e.desugar()); - let new = Self { - s0: self.s0, + let Self { + s0, elems, - s1: self.s1, - span: self.span, + s1, + span, + } = self; + + let (elems, desugared) = elems.desugar_elem(|e| e.desugar()); + let new = Self { + s0, + elems, + s1, + span, }; (new, desugared) } @@ -48,6 +56,7 @@ impl Lit { let (table, desugared) = table.desugar(); (Self::Table(table), desugared) } + lit => (lit, false), } } diff --git a/src/desugar/program.rs b/src/desugar/program.rs index a529b07..7960cbc 100644 --- a/src/desugar/program.rs +++ b/src/desugar/program.rs @@ -5,7 +5,8 @@ impl Program { match self { Self::Expr { s0, expr, s1, span } => { let (expr, desugared) = expr.desugar(); - (Self::Expr { s0, expr, s1, span }, desugared) + let new = Self::Expr { s0, expr, s1, span }; + (new, desugared) } Self::Module { @@ -15,28 +16,18 @@ impl Program { s2, span, } => { - let (elems, desugared) = elems.desugar_elem(|e| e.desugar()); - if desugared { - let new = Self::Module { - s0, - s1, - elems, - s2, - span, - }; - return (new, true); - } - + // `s0 module s1 elems s2` + // -> `s0 '{ s1 elems s2 } empty` let table = TableLit { s0: s1, elems, - s1: Space::empty(span), + s1: s2, span, }; let new = Self::Expr { s0, expr: Expr::Lit(Lit::Table(table)), - s1: s2, + s1: Space::empty(span), span, }; (new, true) From 621ea8f1d418b4b48644c49c54c2e81f29d674ff Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 14:38:45 +0100 Subject: [PATCH 39/70] Desugar field access via ident --- src/desugar/field.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/desugar/field.rs b/src/desugar/field.rs index 8a8b9c2..be46da3 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -1,5 +1,6 @@ use crate::ast::{ - Call, Expr, Field, Line, Lit, Separated, Space, TableConstr, TableConstrElem, TableLitElem, + Call, Expr, Field, Line, Lit, Separated, Space, StringLit, StringLitElem, TableConstr, + TableConstrElem, TableLitElem, }; use crate::builtin::Builtin; @@ -90,14 +91,21 @@ impl Field { ident, span, } => { - let new = Expr::Field(Self::AccessIdent { + // `expr s0 . s1 ident´ + // -> `expr s0 [ s1 ident_str ]` + let ident_str = Expr::Lit(Lit::String(StringLit { + elems: vec![StringLitElem::Plain(ident.name)], + span, + })); + let new = Expr::Field(Self::Access { expr, s0, s1, - ident, + index: Box::new(ident_str), + s2: Space::empty(span), span, }); - (new, false) // TODO Implement + (new, true) } Self::AssignIdent { From 27ba13e8a2f8b42f616ab403234cc55ebab83c2b Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 14:44:15 +0100 Subject: [PATCH 40/70] Desugar field assignment via ident --- src/desugar/field.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/desugar/field.rs b/src/desugar/field.rs index be46da3..0c20ce0 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -118,17 +118,24 @@ impl Field { value, span, } => { - let new = Expr::Field(Self::AssignIdent { + // `expr s0 . s1 ident s2 = s3 value` + // -> `expr s0 [ s1 ident_str ] s2 = s3 value` + let ident_str = Expr::Lit(Lit::String(StringLit { + elems: vec![StringLitElem::Plain(ident.name)], + span, + })); + let new = Expr::Field(Self::Assign { expr, s0, s1, - ident, - s2, - s3, + index: Box::new(ident_str), + s2: Space::empty(span), + s3: s2, + s4: s3, value, span, }); - (new, false) // TODO Implement + (new, true) } } } From ca979edd7ca3f79ef844f6f0efc90a6d8dbc3773 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 15:14:18 +0100 Subject: [PATCH 41/70] Desugar variable access and assignment --- src/desugar.rs | 1 + src/desugar/expr.rs | 6 +- src/desugar/var.rs | 161 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 src/desugar/var.rs diff --git a/src/desugar.rs b/src/desugar.rs index c1037be..7402709 100644 --- a/src/desugar.rs +++ b/src/desugar.rs @@ -4,3 +4,4 @@ mod expr; mod field; mod lit; mod program; +mod var; diff --git a/src/desugar/expr.rs b/src/desugar/expr.rs index 022592a..0c8e569 100644 --- a/src/desugar/expr.rs +++ b/src/desugar/expr.rs @@ -10,11 +10,11 @@ impl Expr { Self::Call(call) => call.desugar(), Self::Field(field) => field.desugar(), + Self::Var(var) => var.desugar(), - Self::Var(var) => (Self::Var(var), false), // TODO Implement Self::TableConstr(constr) => (Self::TableConstr(constr), false), // TODO Implement - Self::TableDestr(destr) => (Self::TableDestr(destr), false), // TODO Implement - Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement + Self::TableDestr(destr) => (Self::TableDestr(destr), false), // TODO Implement + Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement Self::Paren { s0, diff --git a/src/desugar/var.rs b/src/desugar/var.rs new file mode 100644 index 0000000..887d115 --- /dev/null +++ b/src/desugar/var.rs @@ -0,0 +1,161 @@ +use crate::ast::{ + Call, Expr, Field, Line, Lit, Separated, Space, StringLit, StringLitElem, TableConstr, + TableConstrElem, TableLitElem, Var, +}; +use crate::builtin::Builtin; +use crate::span::HasSpan; + +impl Var { + pub fn desugar(self) -> (Expr, bool) { + match self { + Self::Access { + s0, + index, + s1, + span, + } => { + // `[ s0 index s1 ]` + // -> `'scope()[ s0 index s1 ]` + let scope = Expr::Call(Call::NoArg { + 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 { + local: None, + s0, + index, + s1, + s2, + s3, + value, + span, + } => { + // `[ s0 index s1 ] s2 = s3 value` + // -> `'scope()[ s0 index s1 ] s2 = s3 value` + let scope = Expr::Call(Call::NoArg { + 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 { + local: Some(local), + s0, + index, + s1, + s2, + s3, + value, + span, + } => { + // `local [ s0 index s1 ] s2 = s3 value` + // --> `'setraw { 'scope(), local s0 index s1, s2 s3 value }` + let scope = Expr::Call(Call::NoArg { + expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))), + s0: Space::empty(span), + s1: Space::empty(span), + span, + }); + 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, + span, + }); + (new, true) + } + + Self::AccessIdent(name) => { + // `name` + // -> `[ name_str ]` + let span = name.span(); + let name_str = Expr::Lit(Lit::String(StringLit { + elems: vec![StringLitElem::Plain(name.name)], + 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 { + local, + name, + s0, + s1, + value, + span, + } => { + // `local name s0 = s1 value` + // -> `local [ name_str ] s0 = s1 value` + let name_str = Expr::Lit(Lit::String(StringLit { + 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, + span, + }); + (new, true) + } + } + } +} From 9591b2308262a96ccc351725b5e37142f9119b86 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 15:14:28 +0100 Subject: [PATCH 42/70] Fix span of field ident string expression --- src/desugar/field.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/desugar/field.rs b/src/desugar/field.rs index 0c20ce0..7618326 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -95,7 +95,7 @@ impl Field { // -> `expr s0 [ s1 ident_str ]` let ident_str = Expr::Lit(Lit::String(StringLit { elems: vec![StringLitElem::Plain(ident.name)], - span, + span: ident.span, })); let new = Expr::Field(Self::Access { expr, @@ -122,7 +122,7 @@ impl Field { // -> `expr s0 [ s1 ident_str ] s2 = s3 value` let ident_str = Expr::Lit(Lit::String(StringLit { elems: vec![StringLitElem::Plain(ident.name)], - span, + span: ident.span, })); let new = Expr::Field(Self::Assign { expr, From a1867fdc4e43901fb733af216e7acdcbe3d20ff2 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 22:49:40 +0100 Subject: [PATCH 43/70] 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. --- src/ast/basic.rs | 13 +++++++++++++ src/parser/basic.rs | 42 +++++++++++++++++++++++++++++++++++++++++- src/pretty/basic.rs | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index b9e5df0..9790f8c 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -96,3 +96,16 @@ impl HasSpan for Separated { } } } + +#[derive(Debug, Clone)] +pub struct BoundedSeparated { + pub elems: Vec<(Space, E, Space)>, + pub trailing: Option, + pub span: Span, +} + +impl HasSpan for BoundedSeparated { + fn span(&self) -> Span { + self.span + } +} diff --git a/src/parser/basic.rs b/src/parser/basic.rs index 2a65c68..300e953 100644 --- a/src/parser/basic.rs +++ b/src/parser/basic.rs @@ -3,7 +3,7 @@ use chumsky::prelude::*; use chumsky::text::Character; -use crate::ast::{Ident, Line, Separated, Space}; +use crate::ast::{BoundedSeparated, Ident, Line, Separated, Space}; use crate::span::Span; pub type Error = Simple; @@ -82,3 +82,43 @@ pub fn separated_by( }) .boxed() } + +pub fn bounded_separated( + space: impl Parser + Clone + 'static, + start: impl Parser + 'static, + end: impl Parser + 'static, + separator: impl Parser + 'static, + elem: impl Parser + Clone + 'static, +) -> EParser> { + start + .ignore_then(space.clone()) + .then( + elem.clone() + .then(space.clone()) + .then_ignore(separator) + .then(space.clone()) + .repeated(), + ) + .then(elem.then(space).or_not()) + .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, + span, + } + }) + .boxed() +} diff --git a/src/pretty/basic.rs b/src/pretty/basic.rs index b6812b0..5d4ae8e 100644 --- a/src/pretty/basic.rs +++ b/src/pretty/basic.rs @@ -1,6 +1,8 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; -use crate::ast::{Ident, Separated}; +use crate::ast::{BoundedSeparated, Ident, Separated}; + +use super::NEST_DEPTH; impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Ident { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { @@ -45,3 +47,32 @@ impl Separated { } } } + +impl BoundedSeparated { + pub fn pretty<'a, D, FE>( + self, + allocator: &'a D, + start: DocBuilder<'a, D>, + end: DocBuilder<'a, D>, + separator: DocBuilder<'a, D>, + elem_pretty: FE, + ) -> DocBuilder<'a, D> + where + D: DocAllocator<'a>, + D::Doc: Clone, + FE: Fn(E) -> DocBuilder<'a, D>, + { + allocator + .intersperse( + self.elems + .into_iter() + .map(|(s0, elem, s1)| allocator.line().append(elem_pretty(elem))), + separator.clone(), + ) + .append(self.trailing.map(|s| separator)) + .nest(NEST_DEPTH) + .append(allocator.line()) + .enclose(start, end) + .group() + } +} From e3fa3500d4b4fb7638fda34477b26f32d58f14f7 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 23:37:36 +0100 Subject: [PATCH 44/70] Switch TableLit and Program to BoundedSeparated --- src/ast/lit.rs | 11 +++-------- src/ast/program.rs | 8 +++----- src/desugar/basic.rs | 25 ++++++++++++++++++++++++- src/desugar/call.rs | 19 ++++++++----------- src/desugar/lit.rs | 17 ++--------------- src/desugar/program.rs | 20 ++++---------------- src/parser/basic.rs | 8 ++++---- src/parser/lit.rs | 24 +++++++++--------------- src/parser/program.rs | 22 +++++++++------------- src/pretty/call.rs | 6 +++++- src/pretty/expr.rs | 6 +++++- src/pretty/field.rs | 6 +++++- src/pretty/func_def.rs | 6 +++++- src/pretty/lit.rs | 38 ++++++++++++++++++++++---------------- src/pretty/program.rs | 35 ++++++++++++++++++----------------- src/pretty/table_constr.rs | 12 ++++++++++-- src/pretty/table_destr.rs | 6 +++++- src/pretty/var.rs | 6 +++++- 18 files changed, 146 insertions(+), 129 deletions(-) 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 { From 0e9cfd67c2b7b8ba28d6a64083d2b360a0516435 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 23:54:40 +0100 Subject: [PATCH 45/70] Switch TablConstr to BoundedSeparated --- src/ast/lit.rs | 2 - src/ast/table_constr.rs | 13 ++----- src/desugar/field.rs | 77 +++++++++++++++++++------------------- src/desugar/var.rs | 46 +++++++++++------------ src/parser/table_constr.rs | 26 +++++-------- src/pretty/table_constr.rs | 20 ++++------ 6 files changed, 82 insertions(+), 102 deletions(-) diff --git a/src/ast/lit.rs b/src/ast/lit.rs index 61bb9e1..ee486ef 100644 --- a/src/ast/lit.rs +++ b/src/ast/lit.rs @@ -126,8 +126,6 @@ impl HasSpan for TableLitElem { } /// `'{ a, foo: b }` -/// -/// Structure: `'{ s0 elems s1 }` #[derive(Debug, Clone)] pub struct TableLit(pub BoundedSeparated); diff --git a/src/ast/table_constr.rs b/src/ast/table_constr.rs index d347ce1..0e16ae6 100644 --- a/src/ast/table_constr.rs +++ b/src/ast/table_constr.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 TableConstrElem { @@ -31,18 +31,11 @@ impl HasSpan for TableConstrElem { } /// `{ a, b, foo: c, [d]: e }` -/// -/// Structure: `{ s0 elems s1 }` #[derive(Debug, Clone)] -pub struct TableConstr { - pub s0: Space, - pub elems: Separated, - pub s1: Space, - pub span: Span, -} +pub struct TableConstr(pub BoundedSeparated); impl HasSpan for TableConstr { fn span(&self) -> Span { - self.span + self.0.span() } } diff --git a/src/desugar/field.rs b/src/desugar/field.rs index 7618326..496cd44 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -1,5 +1,5 @@ use crate::ast::{ - Call, Expr, Field, Line, Lit, Separated, Space, StringLit, StringLitElem, TableConstr, + BoundedSeparated, Call, Expr, Field, Line, Lit, Space, StringLit, StringLitElem, TableConstr, TableConstrElem, TableLitElem, }; use crate::builtin::Builtin; @@ -17,25 +17,26 @@ impl Field { } => { // ` expr s0 [ s1 index s2 ]` // -> `'get s0 { expr, s1 index s2 }` - let elems = Separated::NonEmpty { - first_elem: TableConstrElem::Lit(TableLitElem::Positional(expr)), - last_elems: vec![( - (Space::empty(span), s1), + let elems = vec![ + ( + Space::empty(span), + TableConstrElem::Lit(TableLitElem::Positional(expr)), + Space::empty(span), + ), + ( + s1, TableConstrElem::Lit(TableLitElem::Positional(index)), - )], - trailing: None, - span, - }; - let constr = TableConstr { - s0: Space::empty(span), - elems, - s1: s2, - span, - }; + s2, + ), + ]; let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Get, span))), s0, - constr, + constr: TableConstr(BoundedSeparated { + elems, + trailing: None, + span, + }), span, }); (new, true) @@ -54,31 +55,31 @@ impl Field { } => { // `expr s0 [ s1 index s2 ] s3 = s4 value` // -> `'set s0 { expr, s1 index s2, s3 s4 value }` - let elems = Separated::NonEmpty { - first_elem: TableConstrElem::Lit(TableLitElem::Positional(expr)), - last_elems: vec![ - ( - (Space::empty(span), s1), - 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 elems = vec![ + ( + Space::empty(span), + TableConstrElem::Lit(TableLitElem::Positional(expr)), + Space::empty(span), + ), + ( + s1, + TableConstrElem::Lit(TableLitElem::Positional(index)), + s2, + ), + ( + s3.then_line(Line::Empty).then(s4), + TableConstrElem::Lit(TableLitElem::Positional(value)), + Space::empty(span), + ), + ]; let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Set, span))), s0, - constr, + constr: TableConstr(BoundedSeparated { + elems, + trailing: None, + span, + }), span, }); (new, true) diff --git a/src/desugar/var.rs b/src/desugar/var.rs index 887d115..7cb5268 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -1,5 +1,5 @@ use crate::ast::{ - Call, Expr, Field, Line, Lit, Separated, Space, StringLit, StringLitElem, TableConstr, + BoundedSeparated, Call, Expr, Field, Line, Lit, Space, StringLit, StringLitElem, TableConstr, TableConstrElem, TableLitElem, Var, }; use crate::builtin::Builtin; @@ -83,31 +83,31 @@ impl Var { s1: Space::empty(span), span, }); - 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 elems = vec![ + ( + Space::empty(span), + TableConstrElem::Lit(TableLitElem::Positional(Box::new(scope))), + 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)), + Space::empty(span), + ), + ]; let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::SetRaw, span))), s0: Space::empty(span), - constr, + constr: TableConstr(BoundedSeparated { + elems, + trailing: None, + span, + }), span, }); (new, true) diff --git a/src/parser/table_constr.rs b/src/parser/table_constr.rs index fd6aefd..65abbcb 100644 --- a/src/parser/table_constr.rs +++ b/src/parser/table_constr.rs @@ -4,7 +4,7 @@ use chumsky::prelude::*; 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( space: EParser, @@ -43,19 +43,13 @@ pub fn table_constr( expr: EParser, ) -> EParser { let elem = table_constr_elem(space.clone(), table_lit_elem, expr); - let separator = space.clone().then_ignore(just(',')).then(space.clone()); - let trailing_separator = space.clone().then_ignore(just(',')); - - space - .clone() - .then(separated_by(elem, separator, trailing_separator)) - .then(space) - .delimited_by(just('{'), just('}')) - .map_with_span(|((s0, elems), s1), span| TableConstr { - s0, - elems, - s1, - span, - }) - .boxed() + bounded_separated( + space, + just('{').to(()), + just('}').to(()), + just(',').to(()), + elem, + ) + .map(TableConstr) + .boxed() } diff --git a/src/pretty/table_constr.rs b/src/pretty/table_constr.rs index 704ab3e..3b3fdb1 100644 --- a/src/pretty/table_constr.rs +++ b/src/pretty/table_constr.rs @@ -2,8 +2,6 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; use crate::ast::{TableConstr, TableConstrElem}; -use super::NEST_DEPTH; - impl<'a, D> Pretty<'a, D> for TableConstrElem where D: DocAllocator<'a>, @@ -35,16 +33,12 @@ where 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()) - .braces() - .group() + self.0.pretty( + allocator, + allocator.text("{"), + allocator.text("}"), + allocator.text(","), + |e| e.pretty(allocator), + ) } } From 198f56226eac52c1e7610831360add869f627921 Mon Sep 17 00:00:00 2001 From: Joscha Date: Mon, 21 Nov 2022 23:57:58 +0100 Subject: [PATCH 46/70] Switch TablePattern to BoundedSeparated --- src/ast/table_destr.rs | 11 +++-------- src/parser/table_destr.rs | 26 ++++++++++---------------- src/pretty/table_destr.rs | 26 ++++++++++++-------------- 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/src/ast/table_destr.rs b/src/ast/table_destr.rs index eb88dcb..6b24d8f 100644 --- a/src/ast/table_destr.rs +++ b/src/ast/table_destr.rs @@ -1,6 +1,6 @@ use crate::span::{HasSpan, Span}; -use super::{Expr, Ident, Separated, Space}; +use super::{BoundedSeparated, Expr, Ident, Space}; // TODO Make table patterns recursive @@ -34,16 +34,11 @@ impl HasSpan for TablePatternElem { /// /// Structure: `{ s0 elems s1 }` #[derive(Debug, Clone)] -pub struct TablePattern { - pub s0: Space, - pub elems: Separated, - pub s1: Space, - pub span: Span, -} +pub struct TablePattern(pub BoundedSeparated); impl HasSpan for TablePattern { fn span(&self) -> Span { - self.span + self.0.span() } } diff --git a/src/parser/table_destr.rs b/src/parser/table_destr.rs index 4fb5eda..0504513 100644 --- a/src/parser/table_destr.rs +++ b/src/parser/table_destr.rs @@ -4,7 +4,7 @@ use chumsky::prelude::*; 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( space: EParser, @@ -31,21 +31,15 @@ fn table_pattern_elem( pub fn table_pattern(space: EParser, ident: EParser) -> EParser { let elem = table_pattern_elem(space.clone(), ident); - let separator = space.clone().then_ignore(just(',')).then(space.clone()); - let trailing_separator = space.clone().then_ignore(just(',')); - - space - .clone() - .then(separated_by(elem, separator, trailing_separator)) - .then(space) - .delimited_by(just('{'), just('}')) - .map_with_span(|((s0, elems), s1), span| TablePattern { - s0, - elems, - s1, - span, - }) - .boxed() + bounded_separated( + space, + just('{').to(()), + just('}').to(()), + just(',').to(()), + elem, + ) + .map(TablePattern) + .boxed() } pub fn table_destr( diff --git a/src/pretty/table_destr.rs b/src/pretty/table_destr.rs index 795bfa2..777d0ae 100644 --- a/src/pretty/table_destr.rs +++ b/src/pretty/table_destr.rs @@ -2,8 +2,6 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; use crate::ast::{TableDestr, TablePattern, TablePatternElem}; -use super::NEST_DEPTH; - impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePatternElem { fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> { match self { @@ -22,19 +20,19 @@ 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> { - self.elems - .pretty( - allocator, - |e| allocator.line().append(e.pretty(allocator)), - |(s0, s1)| allocator.text(","), - |s| allocator.text(","), - ) - .nest(NEST_DEPTH) - .append(allocator.line()) - .braces() - .group() + self.0.pretty( + allocator, + allocator.text("{"), + allocator.text("}"), + allocator.text(","), + |e| e.pretty(allocator), + ) } } From 94ea1969336448bbd24f6f25e42c2d3a0655a11d Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 00:00:43 +0100 Subject: [PATCH 47/70] Remove Separated --- src/ast/basic.rs | 20 -------------------- src/desugar/basic.rs | 37 +------------------------------------ src/parser/basic.rs | 23 +---------------------- src/pretty/basic.rs | 40 +--------------------------------------- 4 files changed, 3 insertions(+), 117 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index 9790f8c..5056f21 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -77,26 +77,6 @@ impl HasSpan for Ident { } } -#[derive(Debug, Clone)] -pub enum Separated { - Empty(Span), - NonEmpty { - first_elem: E, - last_elems: Vec<(S1, E)>, - trailing: Option, - span: Span, - }, -} - -impl HasSpan for Separated { - fn span(&self) -> Span { - match self { - Self::Empty(span) => *span, - Self::NonEmpty { span, .. } => *span, - } - } -} - #[derive(Debug, Clone)] pub struct BoundedSeparated { pub elems: Vec<(Space, E, Space)>, diff --git a/src/desugar/basic.rs b/src/desugar/basic.rs index 1b0f4fc..156445f 100644 --- a/src/desugar/basic.rs +++ b/src/desugar/basic.rs @@ -1,39 +1,4 @@ -use crate::ast::{BoundedSeparated, Separated}; - -impl Separated { - pub fn desugar_elem(self, desugar_elem: impl Fn(E) -> (E, bool)) -> (Self, bool) { - match self { - Self::Empty(span) => (Self::Empty(span), false), - - 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 { - new_last_elems.push((separator, elem)); - } else { - let (elem, elem_desugared) = desugar_elem(elem); - desugared = desugared || elem_desugared; - new_last_elems.push((separator, elem)); - } - } - - let new = Self::NonEmpty { - first_elem: new_first_elem, - last_elems: new_last_elems, - trailing, - span, - }; - (new, desugared) - } - } - } -} +use crate::ast::BoundedSeparated; impl BoundedSeparated { pub fn desugar(self, desugar_elem: impl Fn(E) -> (E, bool)) -> (Self, bool) { diff --git a/src/parser/basic.rs b/src/parser/basic.rs index 2c8254d..9ca8d09 100644 --- a/src/parser/basic.rs +++ b/src/parser/basic.rs @@ -3,7 +3,7 @@ use chumsky::prelude::*; use chumsky::text::Character; -use crate::ast::{BoundedSeparated, Ident, Line, Separated, Space}; +use crate::ast::{BoundedSeparated, Ident, Line, Space}; use crate::span::Span; pub type Error = Simple; @@ -62,27 +62,6 @@ pub fn local(space: EParser) -> EParser> { // 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 // don't apply to it. -pub fn separated_by( - elem: impl Parser + Clone + 'static, - separator: impl Parser + 'static, - trailing_separator: impl Parser + 'static, -) -> EParser> { - elem.clone() - .then(separator.then(elem).repeated()) - .then(trailing_separator.or_not()) - .or_not() - .map_with_span(|s, span| match s { - Some(((first_elem, last_elems), trailing)) => Separated::NonEmpty { - first_elem, - last_elems, - trailing, - span, - }, - None => Separated::Empty(span), - }) - .boxed() -} - pub fn bounded_separated( space: impl Parser + Clone + 'static, start: impl Parser + 'static, diff --git a/src/pretty/basic.rs b/src/pretty/basic.rs index 5d4ae8e..632007c 100644 --- a/src/pretty/basic.rs +++ b/src/pretty/basic.rs @@ -1,6 +1,6 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; -use crate::ast::{BoundedSeparated, Ident, Separated}; +use crate::ast::{BoundedSeparated, Ident}; use super::NEST_DEPTH; @@ -10,44 +10,6 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Ident { } } -impl Separated { - pub fn pretty<'a, D, FE, FS1, FS2>( - self, - allocator: &'a D, - elem_to_doc: FE, - separator_to_doc: FS1, - trailing_separator_to_doc: FS2, - ) -> DocBuilder<'a, D> - where - D: DocAllocator<'a>, - FE: Fn(E) -> DocBuilder<'a, D>, - FS1: Fn(S1) -> DocBuilder<'a, D>, - FS2: Fn(S2) -> DocBuilder<'a, D>, - { - match self { - Self::Empty(_) => allocator.nil(), - Self::NonEmpty { - first_elem, - last_elems, - trailing, - span: _span, - } => elem_to_doc(first_elem) - .append( - allocator.concat( - last_elems - .into_iter() - .map(|(s, e)| separator_to_doc(s).append(elem_to_doc(e))), - ), - ) - .append( - trailing - .map(trailing_separator_to_doc) - .unwrap_or_else(|| allocator.nil()), - ), - } - } -} - impl BoundedSeparated { pub fn pretty<'a, D, FE>( self, From 74d1f640b5ab620d19062cf889dd839349166e47 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 09:21:44 +0100 Subject: [PATCH 48/70] Fix pretty printing of empty BoundedSeparated --- src/pretty/basic.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pretty/basic.rs b/src/pretty/basic.rs index 632007c..c8c8d8f 100644 --- a/src/pretty/basic.rs +++ b/src/pretty/basic.rs @@ -1,6 +1,6 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; -use crate::ast::{BoundedSeparated, Ident}; +use crate::ast::{BoundedSeparated, Ident, Space}; use super::NEST_DEPTH; @@ -24,6 +24,7 @@ impl BoundedSeparated { D::Doc: Clone, FE: Fn(E) -> DocBuilder<'a, D>, { + let elems_empty = self.elems.is_empty(); allocator .intersperse( self.elems @@ -31,7 +32,7 @@ impl BoundedSeparated { .map(|(s0, elem, s1)| allocator.line().append(elem_pretty(elem))), separator.clone(), ) - .append(self.trailing.map(|s| separator)) + .append(self.trailing.filter(|_| !elems_empty).map(|s| separator)) .nest(NEST_DEPTH) .append(allocator.line()) .enclose(start, end) From af6c171eb4afcdc02f66a01884572b5a55eba072 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 09:44:29 +0100 Subject: [PATCH 49/70] Desugar table constructors --- src/desugar.rs | 1 + src/desugar/basic.rs | 22 ++++++++++++++- src/desugar/expr.rs | 6 ++-- src/desugar/table_constr.rs | 55 +++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 src/desugar/table_constr.rs diff --git a/src/desugar.rs b/src/desugar.rs index 7402709..db66687 100644 --- a/src/desugar.rs +++ b/src/desugar.rs @@ -4,4 +4,5 @@ mod expr; mod field; mod lit; mod program; +mod table_constr; mod var; diff --git a/src/desugar/basic.rs b/src/desugar/basic.rs index 156445f..55526cf 100644 --- a/src/desugar/basic.rs +++ b/src/desugar/basic.rs @@ -1,4 +1,4 @@ -use crate::ast::BoundedSeparated; +use crate::ast::{BoundedSeparated, Space}; impl BoundedSeparated { pub fn desugar(self, desugar_elem: impl Fn(E) -> (E, bool)) -> (Self, bool) { @@ -21,4 +21,24 @@ impl BoundedSeparated { }; (new, desugared) } + + pub fn remove_map( + self, + f: impl Fn(E) -> Result, + ) -> (BoundedSeparated, 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) + } } diff --git a/src/desugar/expr.rs b/src/desugar/expr.rs index 0c8e569..5f7cb02 100644 --- a/src/desugar/expr.rs +++ b/src/desugar/expr.rs @@ -11,10 +11,10 @@ impl Expr { Self::Call(call) => call.desugar(), Self::Field(field) => field.desugar(), Self::Var(var) => var.desugar(), + Self::TableConstr(constr) => constr.desugar(), - Self::TableConstr(constr) => (Self::TableConstr(constr), false), // TODO Implement - Self::TableDestr(destr) => (Self::TableDestr(destr), false), // TODO Implement - Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement + Self::TableDestr(destr) => (Self::TableDestr(destr), false), // TODO Implement + Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement Self::Paren { s0, diff --git a/src/desugar/table_constr.rs b/src/desugar/table_constr.rs new file mode 100644 index 0000000..aa37214 --- /dev/null +++ b/src/desugar/table_constr.rs @@ -0,0 +1,55 @@ +use crate::ast::{ + BoundedSeparated, Expr, Field, Ident, Line, Lit, Space, TableConstr, TableConstrElem, TableLit, + 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((s0, index, s1, s2, s3, value, span)), + }); + + let raw_elem = TableLitElem::Named { + name: Ident::new("raw", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: Box::new(Expr::Lit(Lit::Table(TableLit(elems)))), + span, + }; + let mut expr = Expr::Lit(Lit::Table(TableLit(BoundedSeparated { + elems: vec![(Space::empty(span), raw_elem, Space::empty(span))], + trailing: None, + span, + }))); + + // `sl [ s0 index s1 ] s2 = s3 value sr` + // -> `expr s0 [ s1 index s2 ] s3 = s4 s5 value` + for (s0, (s1, index, s2, s3, s4, value, span), s5) in setters { + expr = Expr::Field(Field::Assign { + expr: Box::new(expr), + s0, + s1, + index, + s2, + s3, + s4: s4.then_line(Line::Empty).then(s5), + value, + span, + }); + } + + (expr, true) + } +} From d4797c5894f7f226d429e1a6c0031c115240c2ab Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 10:31:58 +0100 Subject: [PATCH 50/70] Simplify creating string literal from ident --- src/ast/lit.rs | 9 +++++++++ src/desugar/field.rs | 16 ++++------------ src/desugar/var.rs | 16 ++++------------ 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/ast/lit.rs b/src/ast/lit.rs index ee486ef..16c7263 100644 --- a/src/ast/lit.rs +++ b/src/ast/lit.rs @@ -93,6 +93,15 @@ pub struct StringLit { pub span: Span, } +impl StringLit { + pub fn from_ident(ident: Ident) -> Self { + Self { + elems: vec![StringLitElem::Plain(ident.name)], + span: ident.span, + } + } +} + impl HasSpan for StringLit { fn span(&self) -> Span { self.span diff --git a/src/desugar/field.rs b/src/desugar/field.rs index 496cd44..30dfc5b 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -1,6 +1,6 @@ use crate::ast::{ - BoundedSeparated, Call, Expr, Field, Line, Lit, Space, StringLit, StringLitElem, TableConstr, - TableConstrElem, TableLitElem, + BoundedSeparated, Call, Expr, Field, Line, Lit, Space, StringLit, TableConstr, TableConstrElem, + TableLitElem, }; use crate::builtin::Builtin; @@ -94,15 +94,11 @@ impl Field { } => { // `expr s0 . s1 ident´ // -> `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, s0, s1, - index: Box::new(ident_str), + index: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), s2: Space::empty(span), span, }); @@ -121,15 +117,11 @@ impl Field { } => { // `expr s0 . s1 ident s2 = s3 value` // -> `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, s0, s1, - index: Box::new(ident_str), + index: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), s2: Space::empty(span), s3: s2, s4: s3, diff --git a/src/desugar/var.rs b/src/desugar/var.rs index 7cb5268..2ea1997 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -1,6 +1,6 @@ use crate::ast::{ - BoundedSeparated, Call, Expr, Field, Line, Lit, Space, StringLit, StringLitElem, TableConstr, - TableConstrElem, TableLitElem, Var, + BoundedSeparated, Call, Expr, Field, Line, Lit, Space, StringLit, TableConstr, TableConstrElem, + TableLitElem, Var, }; use crate::builtin::Builtin; use crate::span::HasSpan; @@ -117,13 +117,9 @@ impl Var { // `name` // -> `[ name_str ]` let span = name.span(); - let name_str = Expr::Lit(Lit::String(StringLit { - elems: vec![StringLitElem::Plain(name.name)], - span, - })); let new = Expr::Var(Self::Access { s0: Space::empty(span), - index: Box::new(name_str), + index: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(name)))), s1: Space::empty(span), span, }); @@ -140,14 +136,10 @@ impl Var { } => { // `local name s0 = s1 value` // -> `local [ name_str ] s0 = s1 value` - let name_str = Expr::Lit(Lit::String(StringLit { - 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), + index: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(name)))), s1: Space::empty(span), s2: s0, s3: s1, From 830ffa92c49f58507bc5ca591d03a1e3bda325f8 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 10:32:27 +0100 Subject: [PATCH 51/70] Desugar table destructuring --- src/desugar.rs | 1 + src/desugar/basic.rs | 14 +++++++ src/desugar/expr.rs | 4 +- src/desugar/table_destr.rs | 81 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 src/desugar/table_destr.rs diff --git a/src/desugar.rs b/src/desugar.rs index db66687..e1d23c1 100644 --- a/src/desugar.rs +++ b/src/desugar.rs @@ -5,4 +5,5 @@ mod field; mod lit; mod program; mod table_constr; +mod table_destr; mod var; diff --git a/src/desugar/basic.rs b/src/desugar/basic.rs index 55526cf..6f9ec72 100644 --- a/src/desugar/basic.rs +++ b/src/desugar/basic.rs @@ -22,6 +22,20 @@ impl BoundedSeparated { (new, desugared) } + pub fn map(self, f: impl Fn(E) -> E2) -> BoundedSeparated { + let elems = self + .elems + .into_iter() + .map(|(s0, e, s1)| (s0, f(e), s1)) + .collect::>(); + + BoundedSeparated { + elems, + trailing: self.trailing, + span: self.span, + } + } + pub fn remove_map( self, f: impl Fn(E) -> Result, diff --git a/src/desugar/expr.rs b/src/desugar/expr.rs index 5f7cb02..7a8a197 100644 --- a/src/desugar/expr.rs +++ b/src/desugar/expr.rs @@ -12,9 +12,9 @@ impl Expr { Self::Field(field) => field.desugar(), Self::Var(var) => var.desugar(), Self::TableConstr(constr) => constr.desugar(), + Self::TableDestr(destr) => destr.desugar(), - Self::TableDestr(destr) => (Self::TableDestr(destr), false), // TODO Implement - Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement + Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement Self::Paren { s0, diff --git a/src/desugar/table_destr.rs b/src/desugar/table_destr.rs new file mode 100644 index 0000000..7152010 --- /dev/null +++ b/src/desugar/table_destr.rs @@ -0,0 +1,81 @@ +use crate::ast::{ + BoundedSeparated, Call, Expr, Ident, Lit, Space, StringLit, TableConstr, TableConstrElem, + TableDestr, TableLitElem, TablePattern, TablePatternElem, +}; +use crate::builtin::Builtin; + +fn pattern_to_constr(pattern: TablePattern) -> TableConstr { + TableConstr(pattern.0.map(|e| match e { + TablePatternElem::Positional(ident) => TableConstrElem::Lit(TableLitElem::Positional( + Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), + )), + + TablePatternElem::Named { + name, + s0, + s1, + ident, + span, + } => TableConstrElem::Lit(TableLitElem::Named { + name, + s0, + s1, + value: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), + span, + }), + })) +} + +impl TableDestr { + pub fn desugar(self) -> (Expr, bool) { + let Self { + local, + pattern, + s0, + s1, + value, + span, + } = self; + + let mut elems = vec![ + ( + Space::empty(span), + TableConstrElem::Lit(TableLitElem::Positional(Box::new(Expr::TableConstr( + pattern_to_constr(pattern), + )))), + s0, + ), + ( + s1, + TableConstrElem::Lit(TableLitElem::Positional(value)), + Space::empty(span), + ), + ]; + if let Some(local) = local { + elems.push(( + Space::empty(span), + TableConstrElem::Lit(TableLitElem::Named { + name: Ident::new("local", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: Box::new(Expr::Lit(Lit::Bool(true, span))), + span, + }), + local, + )) + } + + let constr = TableConstr(BoundedSeparated { + elems, + trailing: None, + span, + }); + let new = Expr::Call(Call::Constr { + expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Destructure, span))), + s0: Space::empty(span), + constr, + span, + }); + (new, true) + } +} From d6a0bbf2af77e2d521a88c1cd3603148e98d03e9 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 12:56:09 +0100 Subject: [PATCH 52/70] Desugar simple anonymous function definitions --- src/desugar.rs | 1 + src/desugar/expr.rs | 3 +- src/desugar/func_def.rs | 161 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 src/desugar/func_def.rs diff --git a/src/desugar.rs b/src/desugar.rs index e1d23c1..2be2a3f 100644 --- a/src/desugar.rs +++ b/src/desugar.rs @@ -2,6 +2,7 @@ mod basic; mod call; mod expr; mod field; +mod func_def; mod lit; mod program; mod table_constr; diff --git a/src/desugar/expr.rs b/src/desugar/expr.rs index 7a8a197..01c6862 100644 --- a/src/desugar/expr.rs +++ b/src/desugar/expr.rs @@ -13,8 +13,7 @@ impl Expr { Self::Var(var) => var.desugar(), Self::TableConstr(constr) => constr.desugar(), Self::TableDestr(destr) => destr.desugar(), - - Self::FuncDef(def) => (Self::FuncDef(def), false), // TODO Implement + Self::FuncDef(def) => def.desugar(), Self::Paren { s0, diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs new file mode 100644 index 0000000..7a6b362 --- /dev/null +++ b/src/desugar/func_def.rs @@ -0,0 +1,161 @@ +use crate::ast::{ + BoundedSeparated, Call, Expr, FuncDef, Ident, Lit, Space, TableConstr, TableConstrElem, + TableLit, TableLitElem, Var, +}; +use crate::builtin::Builtin; + +impl FuncDef { + pub fn desugar(self) -> (Expr, bool) { + match self { + Self::AnonNoArg { + s0, + s1, + s2, + body, + span, + } => { + // `function s0 ( s1 ) s2 body` + // -> `{ '{ quote: body }, scope: 'scope() }` + let quote = Expr::Lit(Lit::Table(TableLit(BoundedSeparated { + elems: vec![( + Space::empty(span), + TableLitElem::Named { + name: Ident::new("quote", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: body, + span, + }, + Space::empty(span), + )], + trailing: None, + span, + }))); + let scope = Expr::Call(Call::NoArg { + expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))), + s0: Space::empty(span), + s1: Space::empty(span), + span, + }); + let new = Expr::TableConstr(TableConstr(BoundedSeparated { + elems: vec![ + ( + Space::empty(span), + TableConstrElem::Lit(TableLitElem::Positional(Box::new(quote))), + Space::empty(span), + ), + ( + Space::empty(span), + TableConstrElem::Lit(TableLitElem::Named { + name: Ident::new("scope", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: Box::new(scope), + span, + }), + Space::empty(span), + ), + ], + trailing: None, + span, + })); + (new, true) + } + + Self::AnonArg { + s0, + s1, + arg, + s2, + s3, + body, + span, + } => { + // `function s0 ( s1 arg s2 ) s3 body` + // -> `function ( ) '{ local arg = 'arg(), body }` + let arg_call = Expr::Call(Call::NoArg { + expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Arg, span))), + s0: Space::empty(span), + s1: Space::empty(span), + span, + }); + let arg_assign = Expr::Var(Var::AssignIdent { + local: Some(Space::empty(span)), + name: arg, + s0: Space::empty(span), + s1: Space::empty(span), + value: Box::new(arg_call), + span, + }); + let body_elems = vec![ + ( + Space::empty(span), + TableLitElem::Positional(Box::new(arg_assign)), + Space::empty(span), + ), + ( + Space::empty(span), + TableLitElem::Positional(body), + Space::empty(span), + ), + ]; + let body = Expr::Lit(Lit::Table(TableLit(BoundedSeparated { + elems: body_elems, + trailing: None, + span, + }))); + let new = Expr::FuncDef(Self::AnonNoArg { + s0: Space::empty(span), + s1: Space::empty(span), + s2: Space::empty(span), + body: Box::new(body), + span, + }); + (new, true) + } + + Self::AnonDestr { + s0, + pattern, + s1, + body, + span, + } => todo!(), + + Self::NamedNoArg { + local, + s0, + name, + s1, + s2, + s3, + body, + span, + } => todo!(), + + Self::NamedArg { + local, + s0, + name, + s1, + s2, + arg, + s3, + s4, + body, + span, + } => todo!(), + + Self::NamedDestr { + local, + s0, + name, + s1, + pattern, + s2, + body, + span, + } => todo!(), + } + } +} From c769d9e16f6dd25409f7f8ac6833f465b57b33d7 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 14:44:15 +0100 Subject: [PATCH 53/70] 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. --- src/ast/basic.rs | 16 +++++++ src/desugar/call.rs | 26 +++-------- src/desugar/field.rs | 78 ++++++++++--------------------- src/desugar/func_def.rs | 92 ++++++++++++------------------------- src/desugar/table_constr.rs | 8 ++-- src/desugar/table_destr.rs | 50 +++++++------------- src/desugar/var.rs | 45 ++++++------------ 7 files changed, 110 insertions(+), 205 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index 5056f21..3528b7d 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -89,3 +89,19 @@ impl HasSpan for BoundedSeparated { self.span } } + +impl BoundedSeparated { + 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 + } +} diff --git a/src/desugar/call.rs b/src/desugar/call.rs index 70cd2c4..b09b7a3 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -7,14 +7,12 @@ impl Call { match self { Self::Arg { expr, - s0, - s1, + s0: _, + s1: _, arg, - s2, + s2: _, span, } => { - // `expr s0 ( s1 arg s2 )` - // -> `'{ s0 call: expr, arg: s1 arg s2 }` let call = TableLitElem::Named { name: Ident::new("call", span), s0: Space::empty(span), @@ -25,25 +23,17 @@ impl Call { let arg = TableLitElem::Named { name: Ident::new("arg", span), s0: Space::empty(span), - s1, + s1: Space::empty(span), value: arg, span, }; - 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( + BoundedSeparated::new(span).then(call).then(arg), + ))); (new, true) } Self::NoArg { expr, s0, s1, span } => { - // `expr s0 ( s1 )` - // -> `expr s0 ( s1 nil )` let new = Expr::Call(Self::Arg { expr, s0, @@ -61,8 +51,6 @@ impl Call { constr, span, } => { - // `expr s0 {..}` - // -> `expr s0 ( {..} )` let new = Expr::Call(Self::Arg { expr, s0, diff --git a/src/desugar/field.rs b/src/desugar/field.rs index 30dfc5b..84005b7 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -1,5 +1,5 @@ use crate::ast::{ - BoundedSeparated, Call, Expr, Field, Line, Lit, Space, StringLit, TableConstr, TableConstrElem, + BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstr, TableConstrElem, TableLitElem, }; use crate::builtin::Builtin; @@ -9,34 +9,21 @@ impl Field { match self { Self::Access { expr, - s0, - s1, + s0: _, + s1: _, index, - s2, + s2: _, span, } => { - // ` expr s0 [ s1 index s2 ]` - // -> `'get s0 { expr, s1 index s2 }` - let elems = vec![ - ( - Space::empty(span), - TableConstrElem::Lit(TableLitElem::Positional(expr)), - Space::empty(span), - ), - ( - s1, - TableConstrElem::Lit(TableLitElem::Positional(index)), - s2, - ), - ]; + let constr = TableConstr( + BoundedSeparated::new(span) + .then(TableConstrElem::Lit(TableLitElem::Positional(expr))) + .then(TableConstrElem::Lit(TableLitElem::Positional(index))), + ); let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Get, span))), - s0, - constr: TableConstr(BoundedSeparated { - elems, - trailing: None, - span, - }), + s0: Space::empty(span), + constr, span, }); (new, true) @@ -44,42 +31,25 @@ impl Field { Self::Assign { expr, - s0, - s1, + s0: _, + s1: _, index, - s2, - s3, - s4, + s2: _, + s3: _, + s4: _, value, span, } => { - // `expr s0 [ s1 index s2 ] s3 = s4 value` - // -> `'set s0 { expr, s1 index s2, s3 s4 value }` - let elems = vec![ - ( - Space::empty(span), - TableConstrElem::Lit(TableLitElem::Positional(expr)), - Space::empty(span), - ), - ( - s1, - TableConstrElem::Lit(TableLitElem::Positional(index)), - s2, - ), - ( - s3.then_line(Line::Empty).then(s4), - TableConstrElem::Lit(TableLitElem::Positional(value)), - Space::empty(span), - ), - ]; + let constr = TableConstr( + BoundedSeparated::new(span) + .then(TableConstrElem::Lit(TableLitElem::Positional(expr))) + .then(TableConstrElem::Lit(TableLitElem::Positional(index))) + .then(TableConstrElem::Lit(TableLitElem::Positional(value))), + ); let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Set, span))), - s0, - constr: TableConstr(BoundedSeparated { - elems, - trailing: None, - span, - }), + s0: Space::empty(span), + constr, span, }); (new, true) diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs index 7a6b362..4f3c396 100644 --- a/src/desugar/func_def.rs +++ b/src/desugar/func_def.rs @@ -8,66 +8,46 @@ impl FuncDef { pub fn desugar(self) -> (Expr, bool) { match self { Self::AnonNoArg { - s0, - s1, - s2, + s0: _, + s1: _, + s2: _, body, span, } => { - // `function s0 ( s1 ) s2 body` - // -> `{ '{ quote: body }, scope: 'scope() }` - let quote = Expr::Lit(Lit::Table(TableLit(BoundedSeparated { - elems: vec![( - Space::empty(span), - TableLitElem::Named { - name: Ident::new("quote", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: body, - span, - }, - Space::empty(span), - )], - trailing: None, + let quote = TableLit(BoundedSeparated::new(span).then(TableLitElem::Named { + name: Ident::new("quote", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: body, span, - }))); + })); + let quote = Box::new(Expr::Lit(Lit::Table(quote))); let scope = Expr::Call(Call::NoArg { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))), s0: Space::empty(span), s1: Space::empty(span), span, }); - let new = Expr::TableConstr(TableConstr(BoundedSeparated { - elems: vec![ - ( - Space::empty(span), - TableConstrElem::Lit(TableLitElem::Positional(Box::new(quote))), - Space::empty(span), - ), - ( - Space::empty(span), - TableConstrElem::Lit(TableLitElem::Named { - name: Ident::new("scope", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: Box::new(scope), - span, - }), - Space::empty(span), - ), - ], - trailing: None, - span, - })); + let new = Expr::TableConstr(TableConstr( + BoundedSeparated::new(span) + .then(TableConstrElem::Lit(TableLitElem::Positional(quote))) + .then(TableConstrElem::Lit(TableLitElem::Named { + name: Ident::new("scope", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: Box::new(scope), + span, + })), + )); (new, true) } Self::AnonArg { - s0, - s1, + s0: _, + s1: _, arg, - s2, - s3, + s2: _, + s3: _, body, span, } => { @@ -87,28 +67,14 @@ impl FuncDef { value: Box::new(arg_call), span, }); - let body_elems = vec![ - ( - Space::empty(span), - TableLitElem::Positional(Box::new(arg_assign)), - Space::empty(span), - ), - ( - Space::empty(span), - TableLitElem::Positional(body), - Space::empty(span), - ), - ]; - let body = Expr::Lit(Lit::Table(TableLit(BoundedSeparated { - elems: body_elems, - trailing: None, - span, - }))); + let body = BoundedSeparated::new(span) + .then(TableLitElem::Positional(Box::new(arg_assign))) + .then(TableLitElem::Positional(body)); let new = Expr::FuncDef(Self::AnonNoArg { s0: Space::empty(span), s1: Space::empty(span), s2: Space::empty(span), - body: Box::new(body), + body: Box::new(Expr::Lit(Lit::Table(TableLit(body)))), span, }); (new, true) diff --git a/src/desugar/table_constr.rs b/src/desugar/table_constr.rs index aa37214..2bb4eff 100644 --- a/src/desugar/table_constr.rs +++ b/src/desugar/table_constr.rs @@ -28,11 +28,9 @@ impl TableConstr { value: Box::new(Expr::Lit(Lit::Table(TableLit(elems)))), span, }; - let mut expr = Expr::Lit(Lit::Table(TableLit(BoundedSeparated { - elems: vec![(Space::empty(span), raw_elem, Space::empty(span))], - trailing: None, - span, - }))); + let mut expr = Expr::Lit(Lit::Table(TableLit( + BoundedSeparated::new(span).then(raw_elem), + ))); // `sl [ s0 index s1 ] s2 = s3 value sr` // -> `expr s0 [ s1 index s2 ] s3 = s4 s5 value` diff --git a/src/desugar/table_destr.rs b/src/desugar/table_destr.rs index 7152010..8d68a00 100644 --- a/src/desugar/table_destr.rs +++ b/src/desugar/table_destr.rs @@ -31,49 +31,31 @@ impl TableDestr { let Self { local, pattern, - s0, - s1, + s0: _, + s1: _, value, span, } = self; - let mut elems = vec![ - ( - Space::empty(span), - TableConstrElem::Lit(TableLitElem::Positional(Box::new(Expr::TableConstr( - pattern_to_constr(pattern), - )))), - s0, - ), - ( - s1, - TableConstrElem::Lit(TableLitElem::Positional(value)), - Space::empty(span), - ), - ]; - if let Some(local) = local { - elems.push(( - Space::empty(span), - TableConstrElem::Lit(TableLitElem::Named { - name: Ident::new("local", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: Box::new(Expr::Lit(Lit::Bool(true, span))), - span, - }), - local, - )) + let mut constr = BoundedSeparated::new(span) + .then(TableConstrElem::Lit(TableLitElem::Positional(Box::new( + Expr::TableConstr(pattern_to_constr(pattern)), + )))) + .then(TableConstrElem::Lit(TableLitElem::Positional(value))); + if local.is_some() { + constr = constr.then(TableConstrElem::Lit(TableLitElem::Named { + name: Ident::new("local", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: Box::new(Expr::Lit(Lit::Bool(true, span))), + span, + })); } - let constr = TableConstr(BoundedSeparated { - elems, - trailing: None, - span, - }); let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Destructure, span))), s0: Space::empty(span), - constr, + constr: TableConstr(constr), span, }); (new, true) diff --git a/src/desugar/var.rs b/src/desugar/var.rs index 2ea1997..7019702 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -1,5 +1,5 @@ use crate::ast::{ - BoundedSeparated, Call, Expr, Field, Line, Lit, Space, StringLit, TableConstr, TableConstrElem, + BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstr, TableConstrElem, TableLitElem, Var, }; use crate::builtin::Builtin; @@ -66,48 +66,33 @@ impl Var { } Self::Assign { - local: Some(local), - s0, + local: Some(_), + s0: _, index, - s1, - s2, - s3, + s1: _, + s2: _, + s3: _, value, span, } => { - // `local [ s0 index s1 ] s2 = s3 value` - // --> `'setraw { 'scope(), local s0 index s1, s2 s3 value }` let scope = Expr::Call(Call::NoArg { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))), s0: Space::empty(span), s1: Space::empty(span), span, }); - let elems = vec![ - ( - Space::empty(span), - TableConstrElem::Lit(TableLitElem::Positional(Box::new(scope))), - 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)), - Space::empty(span), - ), - ]; + let constr = TableConstr( + BoundedSeparated::new(span) + .then(TableConstrElem::Lit(TableLitElem::Positional(Box::new( + scope, + )))) + .then(TableConstrElem::Lit(TableLitElem::Positional(index))) + .then(TableConstrElem::Lit(TableLitElem::Positional(value))), + ); let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::SetRaw, span))), s0: Space::empty(span), - constr: TableConstr(BoundedSeparated { - elems, - trailing: None, - span, - }), + constr, span, }); (new, true) From 5a977e6dde78cf0d26347fa4bac35b17eb2682b2 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 15:21:29 +0100 Subject: [PATCH 54/70] Simplify creating TableLit and TableConstr --- src/ast/basic.rs | 14 +++++++++++++ src/desugar/call.rs | 8 ++++---- src/desugar/field.rs | 23 +++++++++------------ src/desugar/func_def.rs | 31 +++++++++++++++------------- src/desugar/lit.rs | 2 +- src/desugar/program.rs | 4 ++-- src/desugar/table_constr.rs | 10 ++++----- src/desugar/table_destr.rs | 41 ++++++++++++++++++++----------------- src/desugar/var.rs | 18 ++++++++-------- 9 files changed, 83 insertions(+), 68 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index 3528b7d..ee6428a 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -2,6 +2,8 @@ use std::fmt; use crate::span::{HasSpan, Span}; +use super::{TableConstr, TableConstrElem, TableLit, TableLitElem}; + #[derive(Clone)] pub enum Line { Empty, @@ -105,3 +107,15 @@ impl BoundedSeparated { self } } + +impl BoundedSeparated { + pub fn table_lit(self) -> TableLit { + TableLit(self) + } +} + +impl BoundedSeparated { + pub fn table_constr(self) -> TableConstr { + TableConstr(self) + } +} diff --git a/src/desugar/call.rs b/src/desugar/call.rs index b09b7a3..bef48b1 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -1,4 +1,4 @@ -use crate::ast::{BoundedSeparated, Call, Expr, Ident, Lit, Space, TableLit, TableLitElem}; +use crate::ast::{BoundedSeparated, Call, Expr, Ident, Lit, Space, TableLitElem}; // TODO Add span for just the parentheses to ast, or limit span to parentheses @@ -27,9 +27,9 @@ impl Call { value: arg, span, }; - let new = Expr::Lit(Lit::Table(TableLit( - BoundedSeparated::new(span).then(call).then(arg), - ))); + let new = Expr::Lit(Lit::Table( + BoundedSeparated::new(span).then(call).then(arg).table_lit(), + )); (new, true) } diff --git a/src/desugar/field.rs b/src/desugar/field.rs index 84005b7..c429f87 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -1,6 +1,5 @@ use crate::ast::{ - BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstr, TableConstrElem, - TableLitElem, + BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstrElem, TableLitElem, }; use crate::builtin::Builtin; @@ -15,11 +14,10 @@ impl Field { s2: _, span, } => { - let constr = TableConstr( - BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional(expr))) - .then(TableConstrElem::Lit(TableLitElem::Positional(index))), - ); + let constr = BoundedSeparated::new(span) + .then(TableConstrElem::Lit(TableLitElem::Positional(expr))) + .then(TableConstrElem::Lit(TableLitElem::Positional(index))) + .table_constr(); let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Get, span))), s0: Space::empty(span), @@ -40,12 +38,11 @@ impl Field { value, span, } => { - let constr = TableConstr( - BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional(expr))) - .then(TableConstrElem::Lit(TableLitElem::Positional(index))) - .then(TableConstrElem::Lit(TableLitElem::Positional(value))), - ); + let constr = BoundedSeparated::new(span) + .then(TableConstrElem::Lit(TableLitElem::Positional(expr))) + .then(TableConstrElem::Lit(TableLitElem::Positional(index))) + .then(TableConstrElem::Lit(TableLitElem::Positional(value))) + .table_constr(); let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Set, span))), s0: Space::empty(span), diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs index 4f3c396..1b370eb 100644 --- a/src/desugar/func_def.rs +++ b/src/desugar/func_def.rs @@ -1,6 +1,5 @@ use crate::ast::{ - BoundedSeparated, Call, Expr, FuncDef, Ident, Lit, Space, TableConstr, TableConstrElem, - TableLit, TableLitElem, Var, + BoundedSeparated, Call, Expr, FuncDef, Ident, Lit, Space, TableConstrElem, TableLitElem, Var, }; use crate::builtin::Builtin; @@ -14,13 +13,15 @@ impl FuncDef { body, span, } => { - let quote = TableLit(BoundedSeparated::new(span).then(TableLitElem::Named { - name: Ident::new("quote", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: body, - span, - })); + let quote = BoundedSeparated::new(span) + .then(TableLitElem::Named { + name: Ident::new("quote", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: body, + span, + }) + .table_lit(); let quote = Box::new(Expr::Lit(Lit::Table(quote))); let scope = Expr::Call(Call::NoArg { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))), @@ -28,7 +29,7 @@ impl FuncDef { s1: Space::empty(span), span, }); - let new = Expr::TableConstr(TableConstr( + let new = Expr::TableConstr( BoundedSeparated::new(span) .then(TableConstrElem::Lit(TableLitElem::Positional(quote))) .then(TableConstrElem::Lit(TableLitElem::Named { @@ -37,8 +38,9 @@ impl FuncDef { s1: Space::empty(span), value: Box::new(scope), span, - })), - )); + })) + .table_constr(), + ); (new, true) } @@ -69,12 +71,13 @@ impl FuncDef { }); let body = BoundedSeparated::new(span) .then(TableLitElem::Positional(Box::new(arg_assign))) - .then(TableLitElem::Positional(body)); + .then(TableLitElem::Positional(body)) + .table_lit(); let new = Expr::FuncDef(Self::AnonNoArg { s0: Space::empty(span), s1: Space::empty(span), s2: Space::empty(span), - body: Box::new(Expr::Lit(Lit::Table(TableLit(body)))), + body: Box::new(Expr::Lit(Lit::Table(body))), span, }); (new, true) diff --git a/src/desugar/lit.rs b/src/desugar/lit.rs index 4f32a38..f88efa6 100644 --- a/src/desugar/lit.rs +++ b/src/desugar/lit.rs @@ -32,7 +32,7 @@ impl TableLitElem { impl TableLit { pub fn desugar(self) -> (Self, bool) { let (elems, desugared) = self.0.desugar(|e| e.desugar()); - (Self(elems), desugared) + (elems.table_lit(), desugared) } } diff --git a/src/desugar/program.rs b/src/desugar/program.rs index 50b11eb..73a3bda 100644 --- a/src/desugar/program.rs +++ b/src/desugar/program.rs @@ -1,4 +1,4 @@ -use crate::ast::{Expr, Lit, Program, Space, TableLit}; +use crate::ast::{Expr, Lit, Program, Space}; impl Program { pub fn desugar(self) -> (Self, bool) { @@ -14,7 +14,7 @@ impl Program { // -> `s0 table` let new = Self::Expr { s0, - expr: Expr::Lit(Lit::Table(TableLit(elems))), + expr: Expr::Lit(Lit::Table(elems.table_lit())), s1: Space::empty(span), span, }; diff --git a/src/desugar/table_constr.rs b/src/desugar/table_constr.rs index 2bb4eff..42123b1 100644 --- a/src/desugar/table_constr.rs +++ b/src/desugar/table_constr.rs @@ -1,5 +1,5 @@ use crate::ast::{ - BoundedSeparated, Expr, Field, Ident, Line, Lit, Space, TableConstr, TableConstrElem, TableLit, + BoundedSeparated, Expr, Field, Ident, Line, Lit, Space, TableConstr, TableConstrElem, TableLitElem, }; use crate::span::HasSpan; @@ -25,12 +25,12 @@ impl TableConstr { name: Ident::new("raw", span), s0: Space::empty(span), s1: Space::empty(span), - value: Box::new(Expr::Lit(Lit::Table(TableLit(elems)))), + value: Box::new(Expr::Lit(Lit::Table(elems.table_lit()))), span, }; - let mut expr = Expr::Lit(Lit::Table(TableLit( - BoundedSeparated::new(span).then(raw_elem), - ))); + let mut expr = Expr::Lit(Lit::Table( + BoundedSeparated::new(span).then(raw_elem).table_lit(), + )); // `sl [ s0 index s1 ] s2 = s3 value sr` // -> `expr s0 [ s1 index s2 ] s3 = s4 s5 value` diff --git a/src/desugar/table_destr.rs b/src/desugar/table_destr.rs index 8d68a00..831464b 100644 --- a/src/desugar/table_destr.rs +++ b/src/desugar/table_destr.rs @@ -5,25 +5,28 @@ use crate::ast::{ use crate::builtin::Builtin; fn pattern_to_constr(pattern: TablePattern) -> TableConstr { - TableConstr(pattern.0.map(|e| match e { - TablePatternElem::Positional(ident) => TableConstrElem::Lit(TableLitElem::Positional( - Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), - )), + pattern + .0 + .map(|e| match e { + TablePatternElem::Positional(ident) => TableConstrElem::Lit(TableLitElem::Positional( + Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), + )), - TablePatternElem::Named { - name, - s0, - s1, - ident, - span, - } => TableConstrElem::Lit(TableLitElem::Named { - name, - s0, - s1, - value: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), - span, - }), - })) + TablePatternElem::Named { + name, + s0, + s1, + ident, + span, + } => TableConstrElem::Lit(TableLitElem::Named { + name, + s0, + s1, + value: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), + span, + }), + }) + .table_constr() } impl TableDestr { @@ -55,7 +58,7 @@ impl TableDestr { let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Destructure, span))), s0: Space::empty(span), - constr: TableConstr(constr), + constr: constr.table_constr(), span, }); (new, true) diff --git a/src/desugar/var.rs b/src/desugar/var.rs index 7019702..39af1e5 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -1,6 +1,5 @@ use crate::ast::{ - BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstr, TableConstrElem, - TableLitElem, Var, + BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstrElem, TableLitElem, Var, }; use crate::builtin::Builtin; use crate::span::HasSpan; @@ -81,14 +80,13 @@ impl Var { s1: Space::empty(span), span, }); - let constr = TableConstr( - BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional(Box::new( - scope, - )))) - .then(TableConstrElem::Lit(TableLitElem::Positional(index))) - .then(TableConstrElem::Lit(TableLitElem::Positional(value))), - ); + let constr = BoundedSeparated::new(span) + .then(TableConstrElem::Lit(TableLitElem::Positional(Box::new( + scope, + )))) + .then(TableConstrElem::Lit(TableLitElem::Positional(index))) + .then(TableConstrElem::Lit(TableLitElem::Positional(value))) + .table_constr(); let new = Expr::Call(Call::Constr { expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::SetRaw, span))), s0: Space::empty(span), From 42369628b69e8ef16df5631041a1a29bc10a27f3 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 15:26:51 +0100 Subject: [PATCH 55/70] Simplify boxing Expr --- src/ast/expr.rs | 6 ++++++ src/desugar/call.rs | 4 ++-- src/desugar/field.rs | 8 ++++---- src/desugar/func_def.rs | 14 +++++++------- src/desugar/lit.rs | 4 ++-- src/desugar/table_constr.rs | 4 ++-- src/desugar/table_destr.rs | 14 +++++++------- src/desugar/var.rs | 22 +++++++++++----------- src/parser/expr.rs | 10 +++++----- src/parser/func_def.rs | 12 ++++++------ src/parser/lit.rs | 4 ++-- src/parser/prefix.rs | 2 +- src/parser/suffix.rs | 12 ++++++------ src/parser/table_constr.rs | 4 ++-- src/parser/table_destr.rs | 2 +- src/parser/var.rs | 8 ++++---- 16 files changed, 68 insertions(+), 62 deletions(-) diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 9b10502..d0fa1ff 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -242,3 +242,9 @@ impl HasSpan for Expr { } } } + +impl Expr { + pub fn boxed(self) -> Box { + Box::new(self) + } +} diff --git a/src/desugar/call.rs b/src/desugar/call.rs index bef48b1..ec6ab89 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -38,7 +38,7 @@ impl Call { expr, s0, s1, - arg: Box::new(Expr::Lit(Lit::Nil(span))), + arg: Expr::Lit(Lit::Nil(span)).boxed(), s2: Space::empty(span), span, }); @@ -55,7 +55,7 @@ impl Call { expr, s0, s1: Space::empty(span), - arg: Box::new(Expr::TableConstr(constr)), + arg: Expr::TableConstr(constr).boxed(), s2: Space::empty(span), span, }); diff --git a/src/desugar/field.rs b/src/desugar/field.rs index c429f87..7bbba62 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -19,7 +19,7 @@ impl Field { .then(TableConstrElem::Lit(TableLitElem::Positional(index))) .table_constr(); let new = Expr::Call(Call::Constr { - expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Get, span))), + expr: Expr::Lit(Lit::Builtin(Builtin::Get, span)).boxed(), s0: Space::empty(span), constr, span, @@ -44,7 +44,7 @@ impl Field { .then(TableConstrElem::Lit(TableLitElem::Positional(value))) .table_constr(); let new = Expr::Call(Call::Constr { - expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Set, span))), + expr: Expr::Lit(Lit::Builtin(Builtin::Set, span)).boxed(), s0: Space::empty(span), constr, span, @@ -65,7 +65,7 @@ impl Field { expr, s0, s1, - index: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), + index: Expr::Lit(Lit::String(StringLit::from_ident(ident))).boxed(), s2: Space::empty(span), span, }); @@ -88,7 +88,7 @@ impl Field { expr, s0, s1, - index: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), + index: Expr::Lit(Lit::String(StringLit::from_ident(ident))).boxed(), s2: Space::empty(span), s3: s2, s4: s3, diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs index 1b370eb..a40c88d 100644 --- a/src/desugar/func_def.rs +++ b/src/desugar/func_def.rs @@ -22,9 +22,9 @@ impl FuncDef { span, }) .table_lit(); - let quote = Box::new(Expr::Lit(Lit::Table(quote))); + let quote = Expr::Lit(Lit::Table(quote)).boxed(); let scope = Expr::Call(Call::NoArg { - expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))), + expr: Expr::Lit(Lit::Builtin(Builtin::Scope, span)).boxed(), s0: Space::empty(span), s1: Space::empty(span), span, @@ -36,7 +36,7 @@ impl FuncDef { name: Ident::new("scope", span), s0: Space::empty(span), s1: Space::empty(span), - value: Box::new(scope), + value: scope.boxed(), span, })) .table_constr(), @@ -56,7 +56,7 @@ impl FuncDef { // `function s0 ( s1 arg s2 ) s3 body` // -> `function ( ) '{ local arg = 'arg(), body }` let arg_call = Expr::Call(Call::NoArg { - expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Arg, span))), + expr: Expr::Lit(Lit::Builtin(Builtin::Arg, span)).boxed(), s0: Space::empty(span), s1: Space::empty(span), span, @@ -66,18 +66,18 @@ impl FuncDef { name: arg, s0: Space::empty(span), s1: Space::empty(span), - value: Box::new(arg_call), + value: arg_call.boxed(), span, }); let body = BoundedSeparated::new(span) - .then(TableLitElem::Positional(Box::new(arg_assign))) + .then(TableLitElem::Positional(arg_assign.boxed())) .then(TableLitElem::Positional(body)) .table_lit(); let new = Expr::FuncDef(Self::AnonNoArg { s0: Space::empty(span), s1: Space::empty(span), s2: Space::empty(span), - body: Box::new(Expr::Lit(Lit::Table(body))), + body: Expr::Lit(Lit::Table(body)).boxed(), span, }); (new, true) diff --git a/src/desugar/lit.rs b/src/desugar/lit.rs index f88efa6..9a94278 100644 --- a/src/desugar/lit.rs +++ b/src/desugar/lit.rs @@ -5,7 +5,7 @@ impl TableLitElem { match self { Self::Positional(expr) => { let (expr, desugared) = expr.desugar(); - (Self::Positional(Box::new(expr)), desugared) + (Self::Positional(expr.boxed()), desugared) } Self::Named { @@ -20,7 +20,7 @@ impl TableLitElem { name, s0, s1, - value: Box::new(value), + value: value.boxed(), span, }; (new, desugared) diff --git a/src/desugar/table_constr.rs b/src/desugar/table_constr.rs index 42123b1..d4e3b68 100644 --- a/src/desugar/table_constr.rs +++ b/src/desugar/table_constr.rs @@ -25,7 +25,7 @@ impl TableConstr { name: Ident::new("raw", span), s0: Space::empty(span), s1: Space::empty(span), - value: Box::new(Expr::Lit(Lit::Table(elems.table_lit()))), + value: Expr::Lit(Lit::Table(elems.table_lit())).boxed(), span, }; let mut expr = Expr::Lit(Lit::Table( @@ -36,7 +36,7 @@ impl TableConstr { // -> `expr s0 [ s1 index s2 ] s3 = s4 s5 value` for (s0, (s1, index, s2, s3, s4, value, span), s5) in setters { expr = Expr::Field(Field::Assign { - expr: Box::new(expr), + expr: expr.boxed(), s0, s1, index, diff --git a/src/desugar/table_destr.rs b/src/desugar/table_destr.rs index 831464b..6428a3b 100644 --- a/src/desugar/table_destr.rs +++ b/src/desugar/table_destr.rs @@ -9,7 +9,7 @@ fn pattern_to_constr(pattern: TablePattern) -> TableConstr { .0 .map(|e| match e { TablePatternElem::Positional(ident) => TableConstrElem::Lit(TableLitElem::Positional( - Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), + Expr::Lit(Lit::String(StringLit::from_ident(ident))).boxed(), )), TablePatternElem::Named { @@ -22,7 +22,7 @@ fn pattern_to_constr(pattern: TablePattern) -> TableConstr { name, s0, s1, - value: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(ident)))), + value: Expr::Lit(Lit::String(StringLit::from_ident(ident))).boxed(), span, }), }) @@ -41,22 +41,22 @@ impl TableDestr { } = self; let mut constr = BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional(Box::new( - Expr::TableConstr(pattern_to_constr(pattern)), - )))) + .then(TableConstrElem::Lit(TableLitElem::Positional( + Expr::TableConstr(pattern_to_constr(pattern)).boxed(), + ))) .then(TableConstrElem::Lit(TableLitElem::Positional(value))); if local.is_some() { constr = constr.then(TableConstrElem::Lit(TableLitElem::Named { name: Ident::new("local", span), s0: Space::empty(span), s1: Space::empty(span), - value: Box::new(Expr::Lit(Lit::Bool(true, span))), + value: Expr::Lit(Lit::Bool(true, span)).boxed(), span, })); } let new = Expr::Call(Call::Constr { - expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Destructure, span))), + expr: Expr::Lit(Lit::Builtin(Builtin::Destructure, span)).boxed(), s0: Space::empty(span), constr: constr.table_constr(), span, diff --git a/src/desugar/var.rs b/src/desugar/var.rs index 39af1e5..821860d 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -16,13 +16,13 @@ impl Var { // `[ s0 index s1 ]` // -> `'scope()[ s0 index s1 ]` let scope = Expr::Call(Call::NoArg { - expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))), + expr: Expr::Lit(Lit::Builtin(Builtin::Scope, span)).boxed(), s0: Space::empty(span), s1: Space::empty(span), span, }); let new = Expr::Field(Field::Access { - expr: Box::new(scope), + expr: scope.boxed(), s0: Space::empty(span), s1: s0, index, @@ -45,13 +45,13 @@ impl Var { // `[ s0 index s1 ] s2 = s3 value` // -> `'scope()[ s0 index s1 ] s2 = s3 value` let scope = Expr::Call(Call::NoArg { - expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))), + expr: Expr::Lit(Lit::Builtin(Builtin::Scope, span)).boxed(), s0: Space::empty(span), s1: Space::empty(span), span, }); let new = Expr::Field(Field::Assign { - expr: Box::new(scope), + expr: scope.boxed(), s0: Space::empty(span), s1: s0, index, @@ -75,20 +75,20 @@ impl Var { span, } => { let scope = Expr::Call(Call::NoArg { - expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Scope, span))), + expr: Expr::Lit(Lit::Builtin(Builtin::Scope, span)).boxed(), s0: Space::empty(span), s1: Space::empty(span), span, }); let constr = BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional(Box::new( - scope, - )))) + .then(TableConstrElem::Lit(TableLitElem::Positional( + scope.boxed(), + ))) .then(TableConstrElem::Lit(TableLitElem::Positional(index))) .then(TableConstrElem::Lit(TableLitElem::Positional(value))) .table_constr(); let new = Expr::Call(Call::Constr { - expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::SetRaw, span))), + expr: Expr::Lit(Lit::Builtin(Builtin::SetRaw, span)).boxed(), s0: Space::empty(span), constr, span, @@ -102,7 +102,7 @@ impl Var { let span = name.span(); let new = Expr::Var(Self::Access { s0: Space::empty(span), - index: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(name)))), + index: Expr::Lit(Lit::String(StringLit::from_ident(name))).boxed(), s1: Space::empty(span), span, }); @@ -122,7 +122,7 @@ impl Var { let new = Expr::Var(Self::Assign { local, s0: Space::empty(span), - index: Box::new(Expr::Lit(Lit::String(StringLit::from_ident(name)))), + index: Expr::Lit(Lit::String(StringLit::from_ident(name))).boxed(), s1: Space::empty(span), s2: s0, s3: s1, diff --git a/src/parser/expr.rs b/src/parser/expr.rs index 3bae445..bd2b373 100644 --- a/src/parser/expr.rs +++ b/src/parser/expr.rs @@ -18,7 +18,7 @@ fn atom_paren( .then_ignore(just(')')) .map_with_span(|((s0, inner), s1), span| Expr::Paren { s0, - inner: Box::new(inner), + inner: inner.boxed(), s1, span, }) @@ -63,11 +63,11 @@ fn left_assoc( over.then(op_over.repeated()) .foldl(|left, (s0, op, s1, right)| Expr::BinOp { span: left.span().join(right.span()), - left: Box::new(left), + left: left.boxed(), s0, op, s1, - right: Box::new(right), + right: right.boxed(), }) .boxed() } @@ -89,11 +89,11 @@ fn right_assoc( .then(over) .foldr(|(left, s0, op, s1), right| Expr::BinOp { span: left.span().join(right.span()), - left: Box::new(left), + left: left.boxed(), s0, op, s1, - right: Box::new(right), + right: right.boxed(), }) .boxed() } diff --git a/src/parser/func_def.rs b/src/parser/func_def.rs index 54765f1..3bb273d 100644 --- a/src/parser/func_def.rs +++ b/src/parser/func_def.rs @@ -19,7 +19,7 @@ fn func_def_anon_no_arg( s0, s1, s2, - body: Box::new(body), + body: body.boxed(), span, }) } @@ -45,7 +45,7 @@ fn func_def_anon_arg( arg, s2, s3, - body: Box::new(body), + body: body.boxed(), span, }, ) @@ -65,7 +65,7 @@ fn func_def_anon_destr( s0, pattern, s1, - body: Box::new(body), + body: body.boxed(), span, }) } @@ -94,7 +94,7 @@ fn func_def_named_no_arg( s1, s2, s3, - body: Box::new(body), + body: body.boxed(), span, }, ) @@ -128,7 +128,7 @@ fn func_def_named_arg( arg, s3, s4, - body: Box::new(body), + body: body.boxed(), span, }, ) @@ -157,7 +157,7 @@ fn func_def_named_destr( s1, pattern, s2, - body: Box::new(body), + body: body.boxed(), span, } }) diff --git a/src/parser/lit.rs b/src/parser/lit.rs index 6b09982..e368684 100644 --- a/src/parser/lit.rs +++ b/src/parser/lit.rs @@ -132,7 +132,7 @@ pub fn table_lit_elem( ) -> EParser { let positional = expr .clone() - .map(|value| TableLitElem::Positional(Box::new(value))); + .map(|value| TableLitElem::Positional(value.boxed())); let named = ident .then(space.clone()) @@ -143,7 +143,7 @@ pub fn table_lit_elem( name, s0, s1, - value: Box::new(value), + value: value.boxed(), span, }); diff --git a/src/parser/prefix.rs b/src/parser/prefix.rs index ddae0bd..f53c78f 100644 --- a/src/parser/prefix.rs +++ b/src/parser/prefix.rs @@ -17,7 +17,7 @@ enum Prefix { impl Prefix { fn into_expr(self, span: Span, expr: Expr) -> Expr { - let expr = Box::new(expr); + let expr = expr.boxed(); match self { Self::Neg { minus, s0 } => Expr::Neg { minus, diff --git a/src/parser/suffix.rs b/src/parser/suffix.rs index cb02008..d519c13 100644 --- a/src/parser/suffix.rs +++ b/src/parser/suffix.rs @@ -57,7 +57,7 @@ enum Suffix { impl Suffix { fn into_expr(self, span: Span, expr: Expr) -> Expr { - let expr = Box::new(expr); + let expr = expr.boxed(); match self { Self::CallArg { s0, s1, arg, s2 } => Expr::Call(Call::Arg { expr, @@ -143,7 +143,7 @@ fn suffix_call_arg( .map(|(((s0, s1), arg), s2)| Suffix::CallArg { s0, s1, - arg: Box::new(arg), + arg: arg.boxed(), s2, }) } @@ -180,7 +180,7 @@ fn suffix_field_access( .map(|(((s0, s1), index), s2)| Suffix::FieldAccess { s0, s1, - index: Box::new(index), + index: index.boxed(), s2, }) } @@ -204,11 +204,11 @@ fn suffix_field_assign( |((((((s0, s1), index), s2), s3), s4), value)| Suffix::FieldAssign { s0, s1, - index: Box::new(index), + index: index.boxed(), s2, s3, s4, - value: Box::new(value), + value: value.boxed(), }, ) } @@ -246,7 +246,7 @@ fn suffix_field_assign_ident( ident, s2, s3, - value: Box::new(value), + value: value.boxed(), }, ) } diff --git a/src/parser/table_constr.rs b/src/parser/table_constr.rs index 65abbcb..b294329 100644 --- a/src/parser/table_constr.rs +++ b/src/parser/table_constr.rs @@ -25,11 +25,11 @@ fn table_constr_elem( .map_with_span( |(((((s0, index), s1), s2), s3), value), span| TableConstrElem::Indexed { s0, - index: Box::new(index), + index: index.boxed(), s1, s2, s3, - value: Box::new(value), + value: value.boxed(), span, }, ); diff --git a/src/parser/table_destr.rs b/src/parser/table_destr.rs index 0504513..c215a19 100644 --- a/src/parser/table_destr.rs +++ b/src/parser/table_destr.rs @@ -59,7 +59,7 @@ pub fn table_destr( pattern, s0, s1, - value: Box::new(value), + value: value.boxed(), span, }) .boxed() diff --git a/src/parser/var.rs b/src/parser/var.rs index 80722e1..c5806dc 100644 --- a/src/parser/var.rs +++ b/src/parser/var.rs @@ -14,7 +14,7 @@ fn var_access(space: EParser, expr: EParser) -> impl Parser Date: Tue, 22 Nov 2022 15:48:47 +0100 Subject: [PATCH 56/70] Simplify creating Expr --- src/ast/call.rs | 6 ++++ src/ast/field.rs | 6 ++++ src/ast/func_def.rs | 6 ++++ src/ast/lit.rs | 6 ++++ src/ast/table_constr.rs | 6 ++++ src/ast/table_destr.rs | 6 ++++ src/ast/var.rs | 6 ++++ src/desugar/call.rs | 21 +++++++------ src/desugar/field.rs | 32 ++++++++++---------- src/desugar/func_def.rs | 53 ++++++++++++++++---------------- src/desugar/program.rs | 2 +- src/desugar/table_constr.rs | 11 ++++--- src/desugar/table_destr.rs | 16 +++++----- src/desugar/var.rs | 60 ++++++++++++++++++------------------- src/parser/suffix.rs | 38 +++++++++++++++-------- 15 files changed, 163 insertions(+), 112 deletions(-) diff --git a/src/ast/call.rs b/src/ast/call.rs index 547e1f1..adbbf68 100644 --- a/src/ast/call.rs +++ b/src/ast/call.rs @@ -46,3 +46,9 @@ impl HasSpan for Call { } } } + +impl Call { + pub fn expr(self) -> Expr { + Expr::Call(self) + } +} diff --git a/src/ast/field.rs b/src/ast/field.rs index 1972686..44561b4 100644 --- a/src/ast/field.rs +++ b/src/ast/field.rs @@ -67,3 +67,9 @@ impl HasSpan for Field { } } } + +impl Field { + pub fn expr(self) -> Expr { + Expr::Field(self) + } +} diff --git a/src/ast/func_def.rs b/src/ast/func_def.rs index e1e89ad..373fa4d 100644 --- a/src/ast/func_def.rs +++ b/src/ast/func_def.rs @@ -99,3 +99,9 @@ impl HasSpan for FuncDef { } } } + +impl FuncDef { + pub fn expr(self) -> Expr { + Expr::FuncDef(self) + } +} diff --git a/src/ast/lit.rs b/src/ast/lit.rs index 16c7263..091c82a 100644 --- a/src/ast/lit.rs +++ b/src/ast/lit.rs @@ -198,3 +198,9 @@ impl HasSpan for Lit { } } } + +impl Lit { + pub fn expr(self) -> Expr { + Expr::Lit(self) + } +} diff --git a/src/ast/table_constr.rs b/src/ast/table_constr.rs index 0e16ae6..679dd74 100644 --- a/src/ast/table_constr.rs +++ b/src/ast/table_constr.rs @@ -39,3 +39,9 @@ impl HasSpan for TableConstr { self.0.span() } } + +impl TableConstr { + pub fn expr(self) -> Expr { + Expr::TableConstr(self) + } +} diff --git a/src/ast/table_destr.rs b/src/ast/table_destr.rs index 6b24d8f..0aa4b5e 100644 --- a/src/ast/table_destr.rs +++ b/src/ast/table_destr.rs @@ -61,3 +61,9 @@ impl HasSpan for TableDestr { self.span } } + +impl TableDestr { + pub fn expr(self) -> Expr { + Expr::TableDestr(self) + } +} diff --git a/src/ast/var.rs b/src/ast/var.rs index 6ec6026..ce53d63 100644 --- a/src/ast/var.rs +++ b/src/ast/var.rs @@ -56,3 +56,9 @@ impl HasSpan for Var { } } } + +impl Var { + pub fn expr(self) -> Expr { + Expr::Var(self) + } +} diff --git a/src/desugar/call.rs b/src/desugar/call.rs index ec6ab89..162036b 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -27,22 +27,21 @@ impl Call { value: arg, span, }; - let new = Expr::Lit(Lit::Table( - BoundedSeparated::new(span).then(call).then(arg).table_lit(), - )); + let new = + Lit::Table(BoundedSeparated::new(span).then(call).then(arg).table_lit()).expr(); (new, true) } Self::NoArg { expr, s0, s1, span } => { - let new = Expr::Call(Self::Arg { + let new = Self::Arg { expr, s0, s1, - arg: Expr::Lit(Lit::Nil(span)).boxed(), + arg: Lit::Nil(span).expr().boxed(), s2: Space::empty(span), span, - }); - (new, true) + }; + (new.expr(), true) } Self::Constr { @@ -51,15 +50,15 @@ impl Call { constr, span, } => { - let new = Expr::Call(Self::Arg { + let new = Self::Arg { expr, s0, s1: Space::empty(span), - arg: Expr::TableConstr(constr).boxed(), + arg: constr.expr().boxed(), s2: Space::empty(span), span, - }); - (new, true) + }; + (new.expr(), true) } } } diff --git a/src/desugar/field.rs b/src/desugar/field.rs index 7bbba62..cc7f601 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -18,13 +18,13 @@ impl Field { .then(TableConstrElem::Lit(TableLitElem::Positional(expr))) .then(TableConstrElem::Lit(TableLitElem::Positional(index))) .table_constr(); - let new = Expr::Call(Call::Constr { - expr: Expr::Lit(Lit::Builtin(Builtin::Get, span)).boxed(), + let new = Call::Constr { + expr: Lit::Builtin(Builtin::Get, span).expr().boxed(), s0: Space::empty(span), constr, span, - }); - (new, true) + }; + (new.expr(), true) } Self::Assign { @@ -43,13 +43,13 @@ impl Field { .then(TableConstrElem::Lit(TableLitElem::Positional(index))) .then(TableConstrElem::Lit(TableLitElem::Positional(value))) .table_constr(); - let new = Expr::Call(Call::Constr { - expr: Expr::Lit(Lit::Builtin(Builtin::Set, span)).boxed(), + let new = Call::Constr { + expr: Lit::Builtin(Builtin::Set, span).expr().boxed(), s0: Space::empty(span), constr, span, - }); - (new, true) + }; + (new.expr(), true) } Self::AccessIdent { @@ -61,15 +61,15 @@ impl Field { } => { // `expr s0 . s1 ident´ // -> `expr s0 [ s1 ident_str ]` - let new = Expr::Field(Self::Access { + let new = Self::Access { expr, s0, s1, - index: Expr::Lit(Lit::String(StringLit::from_ident(ident))).boxed(), + index: Lit::String(StringLit::from_ident(ident)).expr().boxed(), s2: Space::empty(span), span, - }); - (new, true) + }; + (new.expr(), true) } Self::AssignIdent { @@ -84,18 +84,18 @@ impl Field { } => { // `expr s0 . s1 ident s2 = s3 value` // -> `expr s0 [ s1 ident_str ] s2 = s3 value` - let new = Expr::Field(Self::Assign { + let new = Self::Assign { expr, s0, s1, - index: Expr::Lit(Lit::String(StringLit::from_ident(ident))).boxed(), + index: Lit::String(StringLit::from_ident(ident)).expr().boxed(), s2: Space::empty(span), s3: s2, s4: s3, value, span, - }); - (new, true) + }; + (new.expr(), true) } } } diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs index a40c88d..fd2a6bc 100644 --- a/src/desugar/func_def.rs +++ b/src/desugar/func_def.rs @@ -22,25 +22,24 @@ impl FuncDef { span, }) .table_lit(); - let quote = Expr::Lit(Lit::Table(quote)).boxed(); - let scope = Expr::Call(Call::NoArg { - expr: Expr::Lit(Lit::Builtin(Builtin::Scope, span)).boxed(), + let quote = Lit::Table(quote).expr().boxed(); + let scope = Call::NoArg { + expr: Lit::Builtin(Builtin::Scope, span).expr().boxed(), s0: Space::empty(span), s1: Space::empty(span), span, - }); - let new = Expr::TableConstr( - BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional(quote))) - .then(TableConstrElem::Lit(TableLitElem::Named { - name: Ident::new("scope", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: scope.boxed(), - span, - })) - .table_constr(), - ); + }; + let new = BoundedSeparated::new(span) + .then(TableConstrElem::Lit(TableLitElem::Positional(quote))) + .then(TableConstrElem::Lit(TableLitElem::Named { + name: Ident::new("scope", span), + s0: Space::empty(span), + s1: Space::empty(span), + value: scope.expr().boxed(), + span, + })) + .table_constr() + .expr(); (new, true) } @@ -55,32 +54,32 @@ impl FuncDef { } => { // `function s0 ( s1 arg s2 ) s3 body` // -> `function ( ) '{ local arg = 'arg(), body }` - let arg_call = Expr::Call(Call::NoArg { - expr: Expr::Lit(Lit::Builtin(Builtin::Arg, span)).boxed(), + let arg_call = Call::NoArg { + expr: Lit::Builtin(Builtin::Arg, span).expr().boxed(), s0: Space::empty(span), s1: Space::empty(span), span, - }); - let arg_assign = Expr::Var(Var::AssignIdent { + }; + let arg_assign = Var::AssignIdent { local: Some(Space::empty(span)), name: arg, s0: Space::empty(span), s1: Space::empty(span), - value: arg_call.boxed(), + value: arg_call.expr().boxed(), span, - }); + }; let body = BoundedSeparated::new(span) - .then(TableLitElem::Positional(arg_assign.boxed())) + .then(TableLitElem::Positional(arg_assign.expr().boxed())) .then(TableLitElem::Positional(body)) .table_lit(); - let new = Expr::FuncDef(Self::AnonNoArg { + let new = Self::AnonNoArg { s0: Space::empty(span), s1: Space::empty(span), s2: Space::empty(span), - body: Expr::Lit(Lit::Table(body)).boxed(), + body: Lit::Table(body).expr().boxed(), span, - }); - (new, true) + }; + (new.expr(), true) } Self::AnonDestr { diff --git a/src/desugar/program.rs b/src/desugar/program.rs index 73a3bda..d972273 100644 --- a/src/desugar/program.rs +++ b/src/desugar/program.rs @@ -14,7 +14,7 @@ impl Program { // -> `s0 table` let new = Self::Expr { s0, - expr: Expr::Lit(Lit::Table(elems.table_lit())), + expr: Lit::Table(elems.table_lit()).expr(), s1: Space::empty(span), span, }; diff --git a/src/desugar/table_constr.rs b/src/desugar/table_constr.rs index d4e3b68..f74c432 100644 --- a/src/desugar/table_constr.rs +++ b/src/desugar/table_constr.rs @@ -25,17 +25,15 @@ impl TableConstr { name: Ident::new("raw", span), s0: Space::empty(span), s1: Space::empty(span), - value: Expr::Lit(Lit::Table(elems.table_lit())).boxed(), + value: Lit::Table(elems.table_lit()).expr().boxed(), span, }; - let mut expr = Expr::Lit(Lit::Table( - BoundedSeparated::new(span).then(raw_elem).table_lit(), - )); + let mut expr = Lit::Table(BoundedSeparated::new(span).then(raw_elem).table_lit()).expr(); // `sl [ s0 index s1 ] s2 = s3 value sr` // -> `expr s0 [ s1 index s2 ] s3 = s4 s5 value` for (s0, (s1, index, s2, s3, s4, value, span), s5) in setters { - expr = Expr::Field(Field::Assign { + expr = Field::Assign { expr: expr.boxed(), s0, s1, @@ -45,7 +43,8 @@ impl TableConstr { s4: s4.then_line(Line::Empty).then(s5), value, span, - }); + } + .expr(); } (expr, true) diff --git a/src/desugar/table_destr.rs b/src/desugar/table_destr.rs index 6428a3b..c07c400 100644 --- a/src/desugar/table_destr.rs +++ b/src/desugar/table_destr.rs @@ -9,7 +9,7 @@ fn pattern_to_constr(pattern: TablePattern) -> TableConstr { .0 .map(|e| match e { TablePatternElem::Positional(ident) => TableConstrElem::Lit(TableLitElem::Positional( - Expr::Lit(Lit::String(StringLit::from_ident(ident))).boxed(), + Lit::String(StringLit::from_ident(ident)).expr().boxed(), )), TablePatternElem::Named { @@ -22,7 +22,7 @@ fn pattern_to_constr(pattern: TablePattern) -> TableConstr { name, s0, s1, - value: Expr::Lit(Lit::String(StringLit::from_ident(ident))).boxed(), + value: Lit::String(StringLit::from_ident(ident)).expr().boxed(), span, }), }) @@ -42,7 +42,7 @@ impl TableDestr { let mut constr = BoundedSeparated::new(span) .then(TableConstrElem::Lit(TableLitElem::Positional( - Expr::TableConstr(pattern_to_constr(pattern)).boxed(), + pattern_to_constr(pattern).expr().boxed(), ))) .then(TableConstrElem::Lit(TableLitElem::Positional(value))); if local.is_some() { @@ -50,17 +50,17 @@ impl TableDestr { name: Ident::new("local", span), s0: Space::empty(span), s1: Space::empty(span), - value: Expr::Lit(Lit::Bool(true, span)).boxed(), + value: Lit::Bool(true, span).expr().boxed(), span, })); } - let new = Expr::Call(Call::Constr { - expr: Expr::Lit(Lit::Builtin(Builtin::Destructure, span)).boxed(), + let new = Call::Constr { + expr: Lit::Builtin(Builtin::Destructure, span).expr().boxed(), s0: Space::empty(span), constr: constr.table_constr(), span, - }); - (new, true) + }; + (new.expr(), true) } } diff --git a/src/desugar/var.rs b/src/desugar/var.rs index 821860d..b77aa34 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -15,21 +15,21 @@ impl Var { } => { // `[ s0 index s1 ]` // -> `'scope()[ s0 index s1 ]` - let scope = Expr::Call(Call::NoArg { - expr: Expr::Lit(Lit::Builtin(Builtin::Scope, span)).boxed(), + let scope = Call::NoArg { + expr: Lit::Builtin(Builtin::Scope, span).expr().boxed(), s0: Space::empty(span), s1: Space::empty(span), span, - }); - let new = Expr::Field(Field::Access { - expr: scope.boxed(), + }; + let new = Field::Access { + expr: scope.expr().boxed(), s0: Space::empty(span), s1: s0, index, s2: s1, span, - }); - (new, true) + }; + (new.expr(), true) } Self::Assign { @@ -44,14 +44,14 @@ impl Var { } => { // `[ s0 index s1 ] s2 = s3 value` // -> `'scope()[ s0 index s1 ] s2 = s3 value` - let scope = Expr::Call(Call::NoArg { - expr: Expr::Lit(Lit::Builtin(Builtin::Scope, span)).boxed(), + let scope = Call::NoArg { + expr: Lit::Builtin(Builtin::Scope, span).expr().boxed(), s0: Space::empty(span), s1: Space::empty(span), span, - }); - let new = Expr::Field(Field::Assign { - expr: scope.boxed(), + }; + let new = Field::Assign { + expr: scope.expr().boxed(), s0: Space::empty(span), s1: s0, index, @@ -60,8 +60,8 @@ impl Var { s4: s3, value, span, - }); - (new, true) + }; + (new.expr(), true) } Self::Assign { @@ -74,39 +74,39 @@ impl Var { value, span, } => { - let scope = Expr::Call(Call::NoArg { - expr: Expr::Lit(Lit::Builtin(Builtin::Scope, span)).boxed(), + let scope = Call::NoArg { + expr: Lit::Builtin(Builtin::Scope, span).expr().boxed(), s0: Space::empty(span), s1: Space::empty(span), span, - }); + }; let constr = BoundedSeparated::new(span) .then(TableConstrElem::Lit(TableLitElem::Positional( - scope.boxed(), + scope.expr().boxed(), ))) .then(TableConstrElem::Lit(TableLitElem::Positional(index))) .then(TableConstrElem::Lit(TableLitElem::Positional(value))) .table_constr(); - let new = Expr::Call(Call::Constr { - expr: Expr::Lit(Lit::Builtin(Builtin::SetRaw, span)).boxed(), + let new = Call::Constr { + expr: Lit::Builtin(Builtin::SetRaw, span).expr().boxed(), s0: Space::empty(span), constr, span, - }); - (new, true) + }; + (new.expr(), true) } Self::AccessIdent(name) => { // `name` // -> `[ name_str ]` let span = name.span(); - let new = Expr::Var(Self::Access { + let new = Self::Access { s0: Space::empty(span), - index: Expr::Lit(Lit::String(StringLit::from_ident(name))).boxed(), + index: Lit::String(StringLit::from_ident(name)).expr().boxed(), s1: Space::empty(span), span, - }); - (new, true) + }; + (new.expr(), true) } Self::AssignIdent { @@ -119,17 +119,17 @@ impl Var { } => { // `local name s0 = s1 value` // -> `local [ name_str ] s0 = s1 value` - let new = Expr::Var(Self::Assign { + let new = Self::Assign { local, s0: Space::empty(span), - index: Expr::Lit(Lit::String(StringLit::from_ident(name))).boxed(), + index: Lit::String(StringLit::from_ident(name)).expr().boxed(), s1: Space::empty(span), s2: s0, s3: s1, value, span, - }); - (new, true) + }; + (new.expr(), true) } } } diff --git a/src/parser/suffix.rs b/src/parser/suffix.rs index d519c13..ca25830 100644 --- a/src/parser/suffix.rs +++ b/src/parser/suffix.rs @@ -59,29 +59,36 @@ impl Suffix { fn into_expr(self, span: Span, expr: Expr) -> Expr { let expr = expr.boxed(); match self { - Self::CallArg { s0, s1, arg, s2 } => Expr::Call(Call::Arg { + Self::CallArg { s0, s1, arg, s2 } => Call::Arg { expr, s0, s1, arg, s2, span, - }), - Self::CallNoArg { s0, s1 } => Expr::Call(Call::NoArg { expr, s0, s1, span }), - Self::CallConstr { s0, constr } => Expr::Call(Call::Constr { + } + .expr(), + + Self::CallNoArg { s0, s1 } => Call::NoArg { expr, s0, s1, span }.expr(), + + Self::CallConstr { s0, constr } => Call::Constr { expr, s0, constr, span, - }), - Self::FieldAccess { s0, s1, index, s2 } => Expr::Field(Field::Access { + } + .expr(), + + Self::FieldAccess { s0, s1, index, s2 } => Field::Access { expr, s0, s1, index, s2, span, - }), + } + .expr(), + Self::FieldAssign { s0, s1, @@ -90,7 +97,7 @@ impl Suffix { s3, s4, value, - } => Expr::Field(Field::Assign { + } => Field::Assign { expr, s0, s1, @@ -100,14 +107,18 @@ impl Suffix { s4, value, span, - }), - Self::FieldAccessIdent { s0, s1, ident } => Expr::Field(Field::AccessIdent { + } + .expr(), + + Self::FieldAccessIdent { s0, s1, ident } => Field::AccessIdent { expr, s0, s1, ident, span, - }), + } + .expr(), + Self::FieldAssignIdent { s0, s1, @@ -115,7 +126,7 @@ impl Suffix { s2, s3, value, - } => Expr::Field(Field::AssignIdent { + } => Field::AssignIdent { expr, s0, s1, @@ -124,7 +135,8 @@ impl Suffix { s3, value, span, - }), + } + .expr(), } } } From 45caafdc382c82d882a20316c412ffabfed7cc2f Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 16:29:31 +0100 Subject: [PATCH 57/70] Simplify creating Lit --- src/ast/lit.rs | 16 ++++++++++++++++ src/desugar/call.rs | 8 ++++++-- src/desugar/field.rs | 4 ++-- src/desugar/func_def.rs | 4 ++-- src/desugar/program.rs | 4 ++-- src/desugar/table_constr.rs | 8 ++++++-- src/desugar/table_destr.rs | 4 ++-- src/desugar/var.rs | 4 ++-- 8 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/ast/lit.rs b/src/ast/lit.rs index 091c82a..d3c69cd 100644 --- a/src/ast/lit.rs +++ b/src/ast/lit.rs @@ -53,6 +53,12 @@ impl HasSpan for NumLit { } } +impl NumLit { + pub fn lit(self) -> Lit { + Lit::Num(self) + } +} + #[derive(Clone)] pub enum StringLitElem { /// Normal unescaped characters @@ -100,6 +106,10 @@ impl StringLit { span: ident.span, } } + + pub fn lit(self) -> Lit { + Lit::String(self) + } } impl HasSpan for StringLit { @@ -144,6 +154,12 @@ impl HasSpan for TableLit { } } +impl TableLit { + pub fn lit(self) -> Lit { + Lit::Table(self) + } +} + #[derive(Clone)] pub enum Lit { /// `nil` diff --git a/src/desugar/call.rs b/src/desugar/call.rs index 162036b..4a84fcf 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -27,8 +27,12 @@ impl Call { value: arg, span, }; - let new = - Lit::Table(BoundedSeparated::new(span).then(call).then(arg).table_lit()).expr(); + let new = BoundedSeparated::new(span) + .then(call) + .then(arg) + .table_lit() + .lit() + .expr(); (new, true) } diff --git a/src/desugar/field.rs b/src/desugar/field.rs index cc7f601..f66a482 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -65,7 +65,7 @@ impl Field { expr, s0, s1, - index: Lit::String(StringLit::from_ident(ident)).expr().boxed(), + index: StringLit::from_ident(ident).lit().expr().boxed(), s2: Space::empty(span), span, }; @@ -88,7 +88,7 @@ impl Field { expr, s0, s1, - index: Lit::String(StringLit::from_ident(ident)).expr().boxed(), + index: StringLit::from_ident(ident).lit().expr().boxed(), s2: Space::empty(span), s3: s2, s4: s3, diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs index fd2a6bc..ecbb1b4 100644 --- a/src/desugar/func_def.rs +++ b/src/desugar/func_def.rs @@ -22,7 +22,7 @@ impl FuncDef { span, }) .table_lit(); - let quote = Lit::Table(quote).expr().boxed(); + let quote = quote.lit().expr().boxed(); let scope = Call::NoArg { expr: Lit::Builtin(Builtin::Scope, span).expr().boxed(), s0: Space::empty(span), @@ -76,7 +76,7 @@ impl FuncDef { s0: Space::empty(span), s1: Space::empty(span), s2: Space::empty(span), - body: Lit::Table(body).expr().boxed(), + body: body.lit().expr().boxed(), span, }; (new.expr(), true) diff --git a/src/desugar/program.rs b/src/desugar/program.rs index d972273..615998b 100644 --- a/src/desugar/program.rs +++ b/src/desugar/program.rs @@ -1,4 +1,4 @@ -use crate::ast::{Expr, Lit, Program, Space}; +use crate::ast::{Program, Space}; impl Program { pub fn desugar(self) -> (Self, bool) { @@ -14,7 +14,7 @@ impl Program { // -> `s0 table` let new = Self::Expr { s0, - expr: Lit::Table(elems.table_lit()).expr(), + expr: elems.table_lit().lit().expr(), s1: Space::empty(span), span, }; diff --git a/src/desugar/table_constr.rs b/src/desugar/table_constr.rs index f74c432..8fa183d 100644 --- a/src/desugar/table_constr.rs +++ b/src/desugar/table_constr.rs @@ -25,10 +25,14 @@ impl TableConstr { name: Ident::new("raw", span), s0: Space::empty(span), s1: Space::empty(span), - value: Lit::Table(elems.table_lit()).expr().boxed(), + value: elems.table_lit().lit().expr().boxed(), span, }; - let mut expr = Lit::Table(BoundedSeparated::new(span).then(raw_elem).table_lit()).expr(); + let mut expr = BoundedSeparated::new(span) + .then(raw_elem) + .table_lit() + .lit() + .expr(); // `sl [ s0 index s1 ] s2 = s3 value sr` // -> `expr s0 [ s1 index s2 ] s3 = s4 s5 value` diff --git a/src/desugar/table_destr.rs b/src/desugar/table_destr.rs index c07c400..cbd053b 100644 --- a/src/desugar/table_destr.rs +++ b/src/desugar/table_destr.rs @@ -9,7 +9,7 @@ fn pattern_to_constr(pattern: TablePattern) -> TableConstr { .0 .map(|e| match e { TablePatternElem::Positional(ident) => TableConstrElem::Lit(TableLitElem::Positional( - Lit::String(StringLit::from_ident(ident)).expr().boxed(), + StringLit::from_ident(ident).lit().expr().boxed(), )), TablePatternElem::Named { @@ -22,7 +22,7 @@ fn pattern_to_constr(pattern: TablePattern) -> TableConstr { name, s0, s1, - value: Lit::String(StringLit::from_ident(ident)).expr().boxed(), + value: StringLit::from_ident(ident).lit().expr().boxed(), span, }), }) diff --git a/src/desugar/var.rs b/src/desugar/var.rs index b77aa34..ffad828 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -102,7 +102,7 @@ impl Var { let span = name.span(); let new = Self::Access { s0: Space::empty(span), - index: Lit::String(StringLit::from_ident(name)).expr().boxed(), + index: StringLit::from_ident(name).lit().expr().boxed(), s1: Space::empty(span), span, }; @@ -122,7 +122,7 @@ impl Var { let new = Self::Assign { local, s0: Space::empty(span), - index: Lit::String(StringLit::from_ident(name)).expr().boxed(), + index: StringLit::from_ident(name).lit().expr().boxed(), s1: Space::empty(span), s2: s0, s3: s1, From c191486864add7a349db221c7a433a67b1b35637 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 16:35:16 +0100 Subject: [PATCH 58/70] Simplify creating TableLitElem --- src/ast/lit.rs | 12 ++++++++++++ src/desugar/call.rs | 18 ++---------------- src/desugar/func_def.rs | 18 +++++------------- src/desugar/table_constr.rs | 16 ++++++---------- src/desugar/table_destr.rs | 10 ++++------ 5 files changed, 29 insertions(+), 45 deletions(-) diff --git a/src/ast/lit.rs b/src/ast/lit.rs index d3c69cd..44df7ac 100644 --- a/src/ast/lit.rs +++ b/src/ast/lit.rs @@ -144,6 +144,18 @@ impl HasSpan for TableLitElem { } } +impl TableLitElem { + pub fn named(name: Ident, value: Box, span: Span) -> Self { + Self::Named { + name, + s0: Space::empty(span), + s1: Space::empty(span), + value, + span, + } + } +} + /// `'{ a, foo: b }` #[derive(Debug, Clone)] pub struct TableLit(pub BoundedSeparated); diff --git a/src/desugar/call.rs b/src/desugar/call.rs index 4a84fcf..b5155d1 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -13,23 +13,9 @@ impl Call { s2: _, span, } => { - let call = TableLitElem::Named { - name: Ident::new("call", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: expr, - span, - }; - let arg = TableLitElem::Named { - name: Ident::new("arg", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: arg, - span, - }; let new = BoundedSeparated::new(span) - .then(call) - .then(arg) + .then(TableLitElem::named(Ident::new("call", span), expr, span)) + .then(TableLitElem::named(Ident::new("arg", span), arg, span)) .table_lit() .lit() .expr(); diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs index ecbb1b4..86e3ad8 100644 --- a/src/desugar/func_def.rs +++ b/src/desugar/func_def.rs @@ -14,13 +14,7 @@ impl FuncDef { span, } => { let quote = BoundedSeparated::new(span) - .then(TableLitElem::Named { - name: Ident::new("quote", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: body, - span, - }) + .then(TableLitElem::named(Ident::new("quote", span), body, span)) .table_lit(); let quote = quote.lit().expr().boxed(); let scope = Call::NoArg { @@ -31,13 +25,11 @@ impl FuncDef { }; let new = BoundedSeparated::new(span) .then(TableConstrElem::Lit(TableLitElem::Positional(quote))) - .then(TableConstrElem::Lit(TableLitElem::Named { - name: Ident::new("scope", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: scope.expr().boxed(), + .then(TableConstrElem::Lit(TableLitElem::named( + Ident::new("scope", span), + scope.expr().boxed(), span, - })) + ))) .table_constr() .expr(); (new, true) diff --git a/src/desugar/table_constr.rs b/src/desugar/table_constr.rs index 8fa183d..cfa1c04 100644 --- a/src/desugar/table_constr.rs +++ b/src/desugar/table_constr.rs @@ -1,6 +1,5 @@ use crate::ast::{ - BoundedSeparated, Expr, Field, Ident, Line, Lit, Space, TableConstr, TableConstrElem, - TableLitElem, + BoundedSeparated, Expr, Field, Ident, Line, TableConstr, TableConstrElem, TableLitElem, }; use crate::span::HasSpan; @@ -21,15 +20,12 @@ impl TableConstr { } => Err((s0, index, s1, s2, s3, value, span)), }); - let raw_elem = TableLitElem::Named { - name: Ident::new("raw", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: elems.table_lit().lit().expr().boxed(), - span, - }; let mut expr = BoundedSeparated::new(span) - .then(raw_elem) + .then(TableLitElem::named( + Ident::new("raw", span), + elems.table_lit().lit().expr().boxed(), + span, + )) .table_lit() .lit() .expr(); diff --git a/src/desugar/table_destr.rs b/src/desugar/table_destr.rs index cbd053b..fb1e070 100644 --- a/src/desugar/table_destr.rs +++ b/src/desugar/table_destr.rs @@ -46,13 +46,11 @@ impl TableDestr { ))) .then(TableConstrElem::Lit(TableLitElem::Positional(value))); if local.is_some() { - constr = constr.then(TableConstrElem::Lit(TableLitElem::Named { - name: Ident::new("local", span), - s0: Space::empty(span), - s1: Space::empty(span), - value: Lit::Bool(true, span).expr().boxed(), + constr = constr.then(TableConstrElem::Lit(TableLitElem::named( + Ident::new("local", span), + Lit::Bool(true, span).expr().boxed(), span, - })); + ))); } let new = Call::Constr { From 58106c4c5a5c5fdc030defe5fe79d4a5903b377e Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 16:43:24 +0100 Subject: [PATCH 59/70] Simplify creating TableConstrElem --- src/ast/table_constr.rs | 24 +++++++++++++++++++++++- src/desugar/field.rs | 14 ++++++-------- src/desugar/func_def.rs | 12 +++++++----- src/desugar/lit.rs | 2 +- src/desugar/table_destr.rs | 16 ++++++++-------- src/desugar/var.rs | 10 ++++------ src/pretty/basic.rs | 2 +- 7 files changed, 50 insertions(+), 30 deletions(-) diff --git a/src/ast/table_constr.rs b/src/ast/table_constr.rs index 679dd74..52696a4 100644 --- a/src/ast/table_constr.rs +++ b/src/ast/table_constr.rs @@ -1,6 +1,6 @@ use crate::span::{HasSpan, Span}; -use super::{BoundedSeparated, Expr, Space, TableLitElem}; +use super::{BoundedSeparated, Expr, Ident, Space, TableLitElem}; #[derive(Debug, Clone)] pub enum TableConstrElem { @@ -30,6 +30,28 @@ impl HasSpan for TableConstrElem { } } +impl TableConstrElem { + pub fn positional(value: Box) -> Self { + Self::Lit(TableLitElem::Positional(value)) + } + + pub fn named(name: Ident, value: Box, span: Span) -> Self { + Self::Lit(TableLitElem::named(name, value, span)) + } + + pub fn indexed(index: Box, value: Box, span: Span) -> Self { + Self::Indexed { + s0: Space::empty(span), + index, + s1: Space::empty(span), + s2: Space::empty(span), + s3: Space::empty(span), + value, + span, + } + } +} + /// `{ a, b, foo: c, [d]: e }` #[derive(Debug, Clone)] pub struct TableConstr(pub BoundedSeparated); diff --git a/src/desugar/field.rs b/src/desugar/field.rs index f66a482..caf1cdc 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -1,6 +1,4 @@ -use crate::ast::{ - BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstrElem, TableLitElem, -}; +use crate::ast::{BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstrElem}; use crate::builtin::Builtin; impl Field { @@ -15,8 +13,8 @@ impl Field { span, } => { let constr = BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional(expr))) - .then(TableConstrElem::Lit(TableLitElem::Positional(index))) + .then(TableConstrElem::positional(expr)) + .then(TableConstrElem::positional(index)) .table_constr(); let new = Call::Constr { expr: Lit::Builtin(Builtin::Get, span).expr().boxed(), @@ -39,9 +37,9 @@ impl Field { span, } => { let constr = BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional(expr))) - .then(TableConstrElem::Lit(TableLitElem::Positional(index))) - .then(TableConstrElem::Lit(TableLitElem::Positional(value))) + .then(TableConstrElem::positional(expr)) + .then(TableConstrElem::positional(index)) + .then(TableConstrElem::positional(value)) .table_constr(); let new = Call::Constr { expr: Lit::Builtin(Builtin::Set, span).expr().boxed(), diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs index 86e3ad8..5ac4eb2 100644 --- a/src/desugar/func_def.rs +++ b/src/desugar/func_def.rs @@ -15,8 +15,10 @@ impl FuncDef { } => { let quote = BoundedSeparated::new(span) .then(TableLitElem::named(Ident::new("quote", span), body, span)) - .table_lit(); - let quote = quote.lit().expr().boxed(); + .table_lit() + .lit() + .expr() + .boxed(); let scope = Call::NoArg { expr: Lit::Builtin(Builtin::Scope, span).expr().boxed(), s0: Space::empty(span), @@ -24,12 +26,12 @@ impl FuncDef { span, }; let new = BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional(quote))) - .then(TableConstrElem::Lit(TableLitElem::named( + .then(TableConstrElem::positional(quote)) + .then(TableConstrElem::named( Ident::new("scope", span), scope.expr().boxed(), span, - ))) + )) .table_constr() .expr(); (new, true) diff --git a/src/desugar/lit.rs b/src/desugar/lit.rs index 9a94278..a514ef9 100644 --- a/src/desugar/lit.rs +++ b/src/desugar/lit.rs @@ -41,7 +41,7 @@ impl Lit { match self { Self::Table(table) => { let (table, desugared) = table.desugar(); - (Self::Table(table), desugared) + (table.lit(), desugared) } lit => (lit, false), diff --git a/src/desugar/table_destr.rs b/src/desugar/table_destr.rs index fb1e070..5981dfa 100644 --- a/src/desugar/table_destr.rs +++ b/src/desugar/table_destr.rs @@ -8,9 +8,9 @@ fn pattern_to_constr(pattern: TablePattern) -> TableConstr { pattern .0 .map(|e| match e { - TablePatternElem::Positional(ident) => TableConstrElem::Lit(TableLitElem::Positional( - StringLit::from_ident(ident).lit().expr().boxed(), - )), + TablePatternElem::Positional(ident) => { + TableConstrElem::positional(StringLit::from_ident(ident).lit().expr().boxed()) + } TablePatternElem::Named { name, @@ -41,16 +41,16 @@ impl TableDestr { } = self; let mut constr = BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional( + .then(TableConstrElem::positional( pattern_to_constr(pattern).expr().boxed(), - ))) - .then(TableConstrElem::Lit(TableLitElem::Positional(value))); + )) + .then(TableConstrElem::positional(value)); if local.is_some() { - constr = constr.then(TableConstrElem::Lit(TableLitElem::named( + constr = constr.then(TableConstrElem::named( Ident::new("local", span), Lit::Bool(true, span).expr().boxed(), span, - ))); + )); } let new = Call::Constr { diff --git a/src/desugar/var.rs b/src/desugar/var.rs index ffad828..053e5d1 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -1,5 +1,5 @@ use crate::ast::{ - BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstrElem, TableLitElem, Var, + BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstrElem, Var, }; use crate::builtin::Builtin; use crate::span::HasSpan; @@ -81,11 +81,9 @@ impl Var { span, }; let constr = BoundedSeparated::new(span) - .then(TableConstrElem::Lit(TableLitElem::Positional( - scope.expr().boxed(), - ))) - .then(TableConstrElem::Lit(TableLitElem::Positional(index))) - .then(TableConstrElem::Lit(TableLitElem::Positional(value))) + .then(TableConstrElem::positional(scope.expr().boxed())) + .then(TableConstrElem::positional(index)) + .then(TableConstrElem::positional(value)) .table_constr(); let new = Call::Constr { expr: Lit::Builtin(Builtin::SetRaw, span).expr().boxed(), diff --git a/src/pretty/basic.rs b/src/pretty/basic.rs index c8c8d8f..abc55ee 100644 --- a/src/pretty/basic.rs +++ b/src/pretty/basic.rs @@ -1,6 +1,6 @@ use pretty::{DocAllocator, DocBuilder, Pretty}; -use crate::ast::{BoundedSeparated, Ident, Space}; +use crate::ast::{BoundedSeparated, Ident}; use super::NEST_DEPTH; From 78d08968eb84a459be9536399d9372e563bb5532 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 16:45:29 +0100 Subject: [PATCH 60/70] Move BoundedSeparated helper functions into ast --- src/ast/basic.rs | 34 ++++++++++++++++++++++++++++++++++ src/desugar/basic.rs | 36 +----------------------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index ee6428a..867bcf1 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -106,6 +106,40 @@ impl BoundedSeparated { .push((Space::empty(self.span), elem, Space::empty(self.span))); self } + + pub fn map(self, f: impl Fn(E) -> E2) -> BoundedSeparated { + let elems = self + .elems + .into_iter() + .map(|(s0, e, s1)| (s0, f(e), s1)) + .collect::>(); + + BoundedSeparated { + elems, + trailing: self.trailing, + span: self.span, + } + } + + pub fn remove_map( + self, + f: impl Fn(E) -> Result, + ) -> (BoundedSeparated, 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 { diff --git a/src/desugar/basic.rs b/src/desugar/basic.rs index 6f9ec72..156445f 100644 --- a/src/desugar/basic.rs +++ b/src/desugar/basic.rs @@ -1,4 +1,4 @@ -use crate::ast::{BoundedSeparated, Space}; +use crate::ast::BoundedSeparated; impl BoundedSeparated { pub fn desugar(self, desugar_elem: impl Fn(E) -> (E, bool)) -> (Self, bool) { @@ -21,38 +21,4 @@ impl BoundedSeparated { }; (new, desugared) } - - pub fn map(self, f: impl Fn(E) -> E2) -> BoundedSeparated { - let elems = self - .elems - .into_iter() - .map(|(s0, e, s1)| (s0, f(e), s1)) - .collect::>(); - - BoundedSeparated { - elems, - trailing: self.trailing, - span: self.span, - } - } - - pub fn remove_map( - self, - f: impl Fn(E) -> Result, - ) -> (BoundedSeparated, 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) - } } From 009be99aaa84038b02665f06f0398623ca03e828 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 16:55:27 +0100 Subject: [PATCH 61/70] Simplify creating Call --- src/ast/call.rs | 29 +++++++++++++++++++++++++++++ src/desugar/call.rs | 29 ++++++++++------------------- src/desugar/field.rs | 14 ++++++-------- src/desugar/func_def.rs | 26 ++++++-------------------- src/desugar/table_destr.rs | 13 ++++++------- src/desugar/var.rs | 32 ++++++-------------------------- 6 files changed, 63 insertions(+), 80 deletions(-) diff --git a/src/ast/call.rs b/src/ast/call.rs index adbbf68..6a9d13e 100644 --- a/src/ast/call.rs +++ b/src/ast/call.rs @@ -48,6 +48,35 @@ impl HasSpan for Call { } impl Call { + pub fn arg(base: Box, arg: Box, 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, span: Span) -> Self { + Self::NoArg { + expr: base, + s0: Space::empty(span), + s1: Space::empty(span), + span, + } + } + + pub fn constr(base: Box, constr: TableConstr, span: Span) -> Self { + Self::Constr { + expr: base, + s0: Space::empty(span), + constr, + span, + } + } + pub fn expr(self) -> Expr { Expr::Call(self) } diff --git a/src/desugar/call.rs b/src/desugar/call.rs index b5155d1..361bbf5 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -1,4 +1,4 @@ -use crate::ast::{BoundedSeparated, Call, Expr, Ident, Lit, Space, TableLitElem}; +use crate::ast::{BoundedSeparated, Call, Expr, Ident, Lit, TableLitElem}; // TODO Add span for just the parentheses to ast, or limit span to parentheses @@ -22,32 +22,23 @@ impl Call { (new, true) } - Self::NoArg { expr, s0, s1, span } => { - let new = Self::Arg { - expr, - s0, - s1, - arg: Lit::Nil(span).expr().boxed(), - s2: Space::empty(span), - span, - }; + Self::NoArg { + expr, + s0: _, + s1: _, + span, + } => { + let new = Self::arg(expr, Lit::Nil(span).expr().boxed(), span); (new.expr(), true) } Self::Constr { expr, - s0, + s0: _, constr, span, } => { - let new = Self::Arg { - expr, - s0, - s1: Space::empty(span), - arg: constr.expr().boxed(), - s2: Space::empty(span), - span, - }; + let new = Self::arg(expr, constr.expr().boxed(), span); (new.expr(), true) } } diff --git a/src/desugar/field.rs b/src/desugar/field.rs index caf1cdc..1c8f948 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -16,12 +16,11 @@ impl Field { .then(TableConstrElem::positional(expr)) .then(TableConstrElem::positional(index)) .table_constr(); - let new = Call::Constr { - expr: Lit::Builtin(Builtin::Get, span).expr().boxed(), - s0: Space::empty(span), + let new = Call::constr( + Lit::Builtin(Builtin::Get, span).expr().boxed(), constr, span, - }; + ); (new.expr(), true) } @@ -41,12 +40,11 @@ impl Field { .then(TableConstrElem::positional(index)) .then(TableConstrElem::positional(value)) .table_constr(); - let new = Call::Constr { - expr: Lit::Builtin(Builtin::Set, span).expr().boxed(), - s0: Space::empty(span), + let new = Call::constr( + Lit::Builtin(Builtin::Set, span).expr().boxed(), constr, span, - }; + ); (new.expr(), true) } diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs index 5ac4eb2..93bdb04 100644 --- a/src/desugar/func_def.rs +++ b/src/desugar/func_def.rs @@ -15,26 +15,17 @@ impl FuncDef { } => { let quote = BoundedSeparated::new(span) .then(TableLitElem::named(Ident::new("quote", span), body, span)) - .table_lit() - .lit() - .expr() - .boxed(); - let scope = Call::NoArg { - expr: Lit::Builtin(Builtin::Scope, span).expr().boxed(), - s0: Space::empty(span), - s1: Space::empty(span), - span, - }; + .table_lit(); + let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span); let new = BoundedSeparated::new(span) - .then(TableConstrElem::positional(quote)) + .then(TableConstrElem::positional(Box::new(quote.lit().expr()))) .then(TableConstrElem::named( Ident::new("scope", span), scope.expr().boxed(), span, )) - .table_constr() - .expr(); - (new, true) + .table_constr(); + (new.expr(), true) } Self::AnonArg { @@ -48,12 +39,7 @@ impl FuncDef { } => { // `function s0 ( s1 arg s2 ) s3 body` // -> `function ( ) '{ local arg = 'arg(), body }` - let arg_call = Call::NoArg { - expr: Lit::Builtin(Builtin::Arg, span).expr().boxed(), - s0: Space::empty(span), - s1: Space::empty(span), - span, - }; + let arg_call = Call::no_arg(Lit::Builtin(Builtin::Arg, span).expr().boxed(), span); let arg_assign = Var::AssignIdent { local: Some(Space::empty(span)), name: arg, diff --git a/src/desugar/table_destr.rs b/src/desugar/table_destr.rs index 5981dfa..2216977 100644 --- a/src/desugar/table_destr.rs +++ b/src/desugar/table_destr.rs @@ -1,6 +1,6 @@ use crate::ast::{ - BoundedSeparated, Call, Expr, Ident, Lit, Space, StringLit, TableConstr, TableConstrElem, - TableDestr, TableLitElem, TablePattern, TablePatternElem, + BoundedSeparated, Call, Expr, Ident, Lit, StringLit, TableConstr, TableConstrElem, TableDestr, + TableLitElem, TablePattern, TablePatternElem, }; use crate::builtin::Builtin; @@ -53,12 +53,11 @@ impl TableDestr { )); } - let new = Call::Constr { - expr: Lit::Builtin(Builtin::Destructure, span).expr().boxed(), - s0: Space::empty(span), - constr: constr.table_constr(), + let new = Call::constr( + Lit::Builtin(Builtin::Destructure, span).expr().boxed(), + constr.table_constr(), span, - }; + ); (new.expr(), true) } } diff --git a/src/desugar/var.rs b/src/desugar/var.rs index 053e5d1..fc1b221 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -13,14 +13,7 @@ impl Var { s1, span, } => { - // `[ s0 index s1 ]` - // -> `'scope()[ s0 index s1 ]` - let scope = Call::NoArg { - expr: Lit::Builtin(Builtin::Scope, span).expr().boxed(), - s0: Space::empty(span), - s1: Space::empty(span), - span, - }; + let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span); let new = Field::Access { expr: scope.expr().boxed(), s0: Space::empty(span), @@ -42,14 +35,7 @@ impl Var { value, span, } => { - // `[ s0 index s1 ] s2 = s3 value` - // -> `'scope()[ s0 index s1 ] s2 = s3 value` - let scope = Call::NoArg { - expr: Lit::Builtin(Builtin::Scope, span).expr().boxed(), - s0: Space::empty(span), - s1: Space::empty(span), - span, - }; + let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span); let new = Field::Assign { expr: scope.expr().boxed(), s0: Space::empty(span), @@ -74,23 +60,17 @@ impl Var { value, span, } => { - let scope = Call::NoArg { - expr: Lit::Builtin(Builtin::Scope, span).expr().boxed(), - s0: Space::empty(span), - s1: Space::empty(span), - span, - }; + let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span); let constr = BoundedSeparated::new(span) .then(TableConstrElem::positional(scope.expr().boxed())) .then(TableConstrElem::positional(index)) .then(TableConstrElem::positional(value)) .table_constr(); - let new = Call::Constr { - expr: Lit::Builtin(Builtin::SetRaw, span).expr().boxed(), - s0: Space::empty(span), + let new = Call::constr( + Lit::Builtin(Builtin::SetRaw, span).expr().boxed(), constr, span, - }; + ); (new.expr(), true) } From 6f7683ad1e7b594bc4107411b71abcd840451302 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 17:06:56 +0100 Subject: [PATCH 62/70] Simplify creating Field --- src/ast/field.rs | 48 +++++++++++++++++++++++++++++++++++++ src/desugar/call.rs | 6 ++--- src/desugar/field.rs | 38 ++++++++++------------------- src/desugar/table_constr.rs | 29 +++++++--------------- src/desugar/var.rs | 33 +++++++------------------ 5 files changed, 79 insertions(+), 75 deletions(-) diff --git a/src/ast/field.rs b/src/ast/field.rs index 44561b4..09beccd 100644 --- a/src/ast/field.rs +++ b/src/ast/field.rs @@ -69,6 +69,54 @@ impl HasSpan for Field { } impl Field { + pub fn access(base: Box, index: Box, 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, index: Box, value: Box, 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 access_ident(base: Box, ident: Ident, span: Span) -> Self { + Self::AccessIdent { + expr: base, + s0: Space::empty(span), + s1: Space::empty(span), + ident, + span, + } + } + + pub fn assign_ident(base: Box, ident: Ident, value: Box, span: Span) -> Self { + Self::AssignIdent { + expr: base, + s0: Space::empty(span), + s1: Space::empty(span), + ident, + s2: Space::empty(span), + s3: Space::empty(span), + value, + span, + } + } + pub fn expr(self) -> Expr { Expr::Field(self) } diff --git a/src/desugar/call.rs b/src/desugar/call.rs index 361bbf5..c231875 100644 --- a/src/desugar/call.rs +++ b/src/desugar/call.rs @@ -16,10 +16,8 @@ impl Call { let new = BoundedSeparated::new(span) .then(TableLitElem::named(Ident::new("call", span), expr, span)) .then(TableLitElem::named(Ident::new("arg", span), arg, span)) - .table_lit() - .lit() - .expr(); - (new, true) + .table_lit(); + (new.lit().expr(), true) } Self::NoArg { diff --git a/src/desugar/field.rs b/src/desugar/field.rs index 1c8f948..3c269e2 100644 --- a/src/desugar/field.rs +++ b/src/desugar/field.rs @@ -1,4 +1,4 @@ -use crate::ast::{BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstrElem}; +use crate::ast::{BoundedSeparated, Call, Expr, Field, Lit, StringLit, TableConstrElem}; use crate::builtin::Builtin; impl Field { @@ -50,47 +50,35 @@ impl Field { Self::AccessIdent { expr, - s0, - s1, + s0: _, + s1: _, ident, span, } => { - // `expr s0 . s1 ident´ - // -> `expr s0 [ s1 ident_str ]` - let new = Self::Access { + let new = Self::access( expr, - s0, - s1, - index: StringLit::from_ident(ident).lit().expr().boxed(), - s2: Space::empty(span), + StringLit::from_ident(ident).lit().expr().boxed(), span, - }; + ); (new.expr(), true) } Self::AssignIdent { expr, - s0, - s1, + s0: _, + s1: _, ident, - s2, - s3, + s2: _, + s3: _, value, span, } => { - // `expr s0 . s1 ident s2 = s3 value` - // -> `expr s0 [ s1 ident_str ] s2 = s3 value` - let new = Self::Assign { + let new = Self::assign( expr, - s0, - s1, - index: StringLit::from_ident(ident).lit().expr().boxed(), - s2: Space::empty(span), - s3: s2, - s4: s3, + StringLit::from_ident(ident).lit().expr().boxed(), value, span, - }; + ); (new.expr(), true) } } diff --git a/src/desugar/table_constr.rs b/src/desugar/table_constr.rs index cfa1c04..263d9d4 100644 --- a/src/desugar/table_constr.rs +++ b/src/desugar/table_constr.rs @@ -1,5 +1,5 @@ use crate::ast::{ - BoundedSeparated, Expr, Field, Ident, Line, TableConstr, TableConstrElem, TableLitElem, + BoundedSeparated, Expr, Field, Ident, TableConstr, TableConstrElem, TableLitElem, }; use crate::span::HasSpan; @@ -10,14 +10,14 @@ impl TableConstr { let (elems, setters) = self.0.remove_map(|e| match e { TableConstrElem::Lit(lit) => Ok(lit), TableConstrElem::Indexed { - s0, + s0: _, index, - s1, - s2, - s3, + s1: _, + s2: _, + s3: _, value, span, - } => Err((s0, index, s1, s2, s3, value, span)), + } => Err((index, value, span)), }); let mut expr = BoundedSeparated::new(span) @@ -30,21 +30,8 @@ impl TableConstr { .lit() .expr(); - // `sl [ s0 index s1 ] s2 = s3 value sr` - // -> `expr s0 [ s1 index s2 ] s3 = s4 s5 value` - for (s0, (s1, index, s2, s3, s4, value, span), s5) in setters { - expr = Field::Assign { - expr: expr.boxed(), - s0, - s1, - index, - s2, - s3, - s4: s4.then_line(Line::Empty).then(s5), - value, - span, - } - .expr(); + for (_, (index, value, span), _) in setters { + expr = Field::assign(expr.boxed(), index, value, span).expr(); } (expr, true) diff --git a/src/desugar/var.rs b/src/desugar/var.rs index fc1b221..9062ee6 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -8,45 +8,28 @@ impl Var { pub fn desugar(self) -> (Expr, bool) { match self { Self::Access { - s0, + s0: _, index, - s1, + s1: _, span, } => { let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span); - let new = Field::Access { - expr: scope.expr().boxed(), - s0: Space::empty(span), - s1: s0, - index, - s2: s1, - span, - }; + let new = Field::access(scope.expr().boxed(), index, span); (new.expr(), true) } Self::Assign { local: None, - s0, + s0: _, index, - s1, - s2, - s3, + s1: _, + s2: _, + s3: _, value, span, } => { let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span); - let new = Field::Assign { - expr: scope.expr().boxed(), - s0: Space::empty(span), - s1: s0, - index, - s2: s1, - s3: s2, - s4: s3, - value, - span, - }; + let new = Field::assign(scope.expr().boxed(), index, value, span); (new.expr(), true) } From 40c28d9496e3b70571c9ece9698a1b2c1f5e8211 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 17:14:52 +0100 Subject: [PATCH 63/70] Simplify creating Var --- src/ast/var.rs | 45 +++++++++++++++++++++++++++++++++++++++++ src/desugar/expr.rs | 2 +- src/desugar/func_def.rs | 11 +--------- src/desugar/var.rs | 31 ++++++++-------------------- 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/ast/var.rs b/src/ast/var.rs index ce53d63..d5f0eab 100644 --- a/src/ast/var.rs +++ b/src/ast/var.rs @@ -58,6 +58,51 @@ impl HasSpan for Var { } impl Var { + pub fn access(index: Box, span: Span) -> Self { + Self::Access { + s0: Space::empty(span), + index, + s1: Space::empty(span), + span, + } + } + + pub fn assign(local: bool, index: Box, value: Box, 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, 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) } diff --git a/src/desugar/expr.rs b/src/desugar/expr.rs index 01c6862..7b3cc26 100644 --- a/src/desugar/expr.rs +++ b/src/desugar/expr.rs @@ -5,7 +5,7 @@ impl Expr { match self { Self::Lit(lit) => { let (lit, desugared) = lit.desugar(); - (Self::Lit(lit), desugared) + (lit.expr(), desugared) } Self::Call(call) => call.desugar(), diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs index 93bdb04..2eb5586 100644 --- a/src/desugar/func_def.rs +++ b/src/desugar/func_def.rs @@ -37,17 +37,8 @@ impl FuncDef { body, span, } => { - // `function s0 ( s1 arg s2 ) s3 body` - // -> `function ( ) '{ local arg = 'arg(), body }` let arg_call = Call::no_arg(Lit::Builtin(Builtin::Arg, span).expr().boxed(), span); - let arg_assign = Var::AssignIdent { - local: Some(Space::empty(span)), - name: arg, - s0: Space::empty(span), - s1: Space::empty(span), - value: arg_call.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)) diff --git a/src/desugar/var.rs b/src/desugar/var.rs index 9062ee6..0ab0a76 100644 --- a/src/desugar/var.rs +++ b/src/desugar/var.rs @@ -1,6 +1,4 @@ -use crate::ast::{ - BoundedSeparated, Call, Expr, Field, Lit, Space, StringLit, TableConstrElem, Var, -}; +use crate::ast::{BoundedSeparated, Call, Expr, Field, Lit, StringLit, TableConstrElem, Var}; use crate::builtin::Builtin; use crate::span::HasSpan; @@ -58,38 +56,25 @@ impl Var { } Self::AccessIdent(name) => { - // `name` - // -> `[ name_str ]` let span = name.span(); - let new = Self::Access { - s0: Space::empty(span), - index: StringLit::from_ident(name).lit().expr().boxed(), - s1: Space::empty(span), - span, - }; + let new = Self::access(StringLit::from_ident(name).lit().expr().boxed(), span); (new.expr(), true) } Self::AssignIdent { local, name, - s0, - s1, + s0: _, + s1: _, value, span, } => { - // `local name s0 = s1 value` - // -> `local [ name_str ] s0 = s1 value` - let new = Self::Assign { - local, - s0: Space::empty(span), - index: StringLit::from_ident(name).lit().expr().boxed(), - s1: Space::empty(span), - s2: s0, - s3: s1, + let new = Self::assign( + local.is_some(), + StringLit::from_ident(name).lit().expr().boxed(), value, span, - }; + ); (new.expr(), true) } } From 26dc3c3469d3fde0a6088f3fe3496d160340bd80 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 17:27:06 +0100 Subject: [PATCH 64/70] Desugar all function definitions --- src/ast/func_def.rs | 32 ++++++++++++++++++++ src/ast/table_destr.rs | 17 +++++++++++ src/desugar/func_def.rs | 66 +++++++++++++++++++++++++++++------------ 3 files changed, 96 insertions(+), 19 deletions(-) diff --git a/src/ast/func_def.rs b/src/ast/func_def.rs index 373fa4d..5cdd210 100644 --- a/src/ast/func_def.rs +++ b/src/ast/func_def.rs @@ -101,6 +101,38 @@ impl HasSpan for FuncDef { } impl FuncDef { + pub fn anon_no_arg(body: Box, 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, 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, span: Span) -> Self { + Self::AnonDestr { + s0: Space::empty(span), + pattern, + s1: Space::empty(span), + body, + span, + } + } + pub fn expr(self) -> Expr { Expr::FuncDef(self) } diff --git a/src/ast/table_destr.rs b/src/ast/table_destr.rs index 0aa4b5e..d94b4eb 100644 --- a/src/ast/table_destr.rs +++ b/src/ast/table_destr.rs @@ -63,6 +63,23 @@ impl HasSpan for TableDestr { } impl TableDestr { + pub fn new(local: bool, pattern: TablePattern, value: Box, 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) } diff --git a/src/desugar/func_def.rs b/src/desugar/func_def.rs index 2eb5586..2a549d1 100644 --- a/src/desugar/func_def.rs +++ b/src/desugar/func_def.rs @@ -1,5 +1,6 @@ use crate::ast::{ - BoundedSeparated, Call, Expr, FuncDef, Ident, Lit, Space, TableConstrElem, TableLitElem, Var, + BoundedSeparated, Call, Expr, FuncDef, Ident, Lit, Space, TableConstrElem, TableDestr, + TableLitElem, Var, }; use crate::builtin::Builtin; @@ -54,47 +55,74 @@ impl FuncDef { } Self::AnonDestr { - s0, + s0: _, pattern, - s1, + s1: _, body, span, - } => todo!(), + } => { + 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, + s0: _, name, - s1, - s2, - s3, + s1: _, + s2: _, + s3: _, body, span, - } => todo!(), + } => { + 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, + s0: _, name, - s1, - s2, + s1: _, + s2: _, arg, - s3, - s4, + s3: _, + s4: _, body, span, - } => todo!(), + } => { + 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, + s0: _, name, - s1, + s1: _, pattern, - s2, + s2: _, body, span, - } => todo!(), + } => { + let anon = Self::anon_destr(pattern, body, span); + let new = Var::assign_ident(local.is_some(), name, anon.expr().boxed(), span); + (new.expr(), true) + } } } } From f8fa04425913b1523b5c6ce4ef18235f260ef324 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 17:39:02 +0100 Subject: [PATCH 65/70] Desugar all expressions --- src/builtin.rs | 30 ++++++++++++++++ src/desugar/expr.rs | 87 +++++++++++++++++++++------------------------ 2 files changed, 71 insertions(+), 46 deletions(-) diff --git a/src/builtin.rs b/src/builtin.rs index f0e504d..6ef18c8 100644 --- a/src/builtin.rs +++ b/src/builtin.rs @@ -12,6 +12,21 @@ pub enum Builtin { Scope, Arg, Destructure, + Neg, + Not, + Mul, + Div, + Mod, + Add, + Sub, + Eq, + Ne, + Gt, + Ge, + Lt, + Le, + And, + Or, } impl fmt::Debug for Builtin { @@ -26,6 +41,21 @@ impl fmt::Debug for Builtin { Self::Scope => write!(f, "'scope"), Self::Arg => write!(f, "'arg"), 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"), } } } diff --git a/src/desugar/expr.rs b/src/desugar/expr.rs index 7b3cc26..b7f4b08 100644 --- a/src/desugar/expr.rs +++ b/src/desugar/expr.rs @@ -1,4 +1,5 @@ -use crate::ast::Expr; +use crate::ast::{BinOp, BoundedSeparated, Call, Expr, Lit, TableConstrElem}; +use crate::builtin::Builtin; impl Expr { pub fn desugar(self) -> (Self, bool) { @@ -16,68 +17,62 @@ impl Expr { Self::FuncDef(def) => def.desugar(), Self::Paren { - s0, + s0: _, inner, - s1, - span, - } => ( - Self::Paren { - s0, - inner, - s1, - span, - }, - false, - ), // TODO Implement + s1: _, + span: _, + } => (*inner, true), Self::Neg { minus, - s0, + s0: _, expr, span, - } => ( - Self::Neg { - minus, - s0, - expr, - span, - }, - false, - ), // TODO Implement + } => { + let new = Call::arg(Lit::Builtin(Builtin::Neg, minus).expr().boxed(), expr, span); + (new.expr(), true) + } Self::Not { not, - s0, + s0: _, expr, span, - } => ( - Self::Not { - not, - s0, - expr, - span, - }, - false, - ), // TODO Implement + } => { + let new = Call::arg(Lit::Builtin(Builtin::Not, not).expr().boxed(), expr, span); + (new.expr(), true) + } Self::BinOp { left, - s0, + s0: _, op, - s1, + s1: _, right, span, - } => ( - Self::BinOp { - left, - s0, - op, - s1, - right, - span, - }, - false, - ), // TODO Implement + } => { + let builtin = match op { + BinOp::Mul => Builtin::Mul, + BinOp::Div => Builtin::Div, + BinOp::Mod => Builtin::Mod, + BinOp::Add => Builtin::Add, + BinOp::Sub => Builtin::Sub, + BinOp::Eq => Builtin::Eq, + BinOp::Neq => Builtin::Ne, + BinOp::Gt => Builtin::Gt, + 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) + } } } } From 39099037a5763cebbce47dbee963df6510200c51 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 17:39:56 +0100 Subject: [PATCH 66/70] Remove unused functions --- src/ast/basic.rs | 11 ----------- src/ast/field.rs | 23 ----------------------- src/ast/lit.rs | 6 ------ src/ast/table_constr.rs | 12 ------------ 4 files changed, 52 deletions(-) diff --git a/src/ast/basic.rs b/src/ast/basic.rs index 867bcf1..8a722c3 100644 --- a/src/ast/basic.rs +++ b/src/ast/basic.rs @@ -39,17 +39,6 @@ impl Space { 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)] diff --git a/src/ast/field.rs b/src/ast/field.rs index 09beccd..5afd98f 100644 --- a/src/ast/field.rs +++ b/src/ast/field.rs @@ -94,29 +94,6 @@ impl Field { } } - pub fn access_ident(base: Box, ident: Ident, span: Span) -> Self { - Self::AccessIdent { - expr: base, - s0: Space::empty(span), - s1: Space::empty(span), - ident, - span, - } - } - - pub fn assign_ident(base: Box, ident: Ident, value: Box, span: Span) -> Self { - Self::AssignIdent { - expr: base, - s0: Space::empty(span), - s1: Space::empty(span), - ident, - s2: Space::empty(span), - s3: Space::empty(span), - value, - span, - } - } - pub fn expr(self) -> Expr { Expr::Field(self) } diff --git a/src/ast/lit.rs b/src/ast/lit.rs index 44df7ac..ecd166c 100644 --- a/src/ast/lit.rs +++ b/src/ast/lit.rs @@ -53,12 +53,6 @@ impl HasSpan for NumLit { } } -impl NumLit { - pub fn lit(self) -> Lit { - Lit::Num(self) - } -} - #[derive(Clone)] pub enum StringLitElem { /// Normal unescaped characters diff --git a/src/ast/table_constr.rs b/src/ast/table_constr.rs index 52696a4..38c409d 100644 --- a/src/ast/table_constr.rs +++ b/src/ast/table_constr.rs @@ -38,18 +38,6 @@ impl TableConstrElem { pub fn named(name: Ident, value: Box, span: Span) -> Self { Self::Lit(TableLitElem::named(name, value, span)) } - - pub fn indexed(index: Box, value: Box, span: Span) -> Self { - Self::Indexed { - s0: Space::empty(span), - index, - s1: Space::empty(span), - s2: Space::empty(span), - s3: Space::empty(span), - value, - span, - } - } } /// `{ a, b, foo: c, [d]: e }` From 736174d470e188899d5c1911049c3fb7eee154dc Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 17:49:12 +0100 Subject: [PATCH 67/70] Desugar away named nil in table literals --- src/desugar/lit.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/desugar/lit.rs b/src/desugar/lit.rs index a514ef9..f5942b5 100644 --- a/src/desugar/lit.rs +++ b/src/desugar/lit.rs @@ -1,4 +1,4 @@ -use crate::ast::{Lit, TableLit, TableLitElem}; +use crate::ast::{Expr, Lit, TableLit, TableLitElem}; impl TableLitElem { pub fn desugar(self) -> (Self, bool) { @@ -32,7 +32,17 @@ impl TableLitElem { impl TableLit { pub fn desugar(self) -> (Self, bool) { let (elems, desugared) = self.0.desugar(|e| e.desugar()); - (elems.table_lit(), desugared) + if desugared { + (elems.table_lit(), true) + } else { + let (elems, removed) = elems.remove_map(|e| match e { + TableLitElem::Named { value, .. } if matches!(*value, Expr::Lit(Lit::Nil(_))) => { + Err(()) + } + e => Ok(e), + }); + (elems.table_lit(), !removed.is_empty()) + } } } From f6c9835e29896e03b65e49eda97d3dd660d737af Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 21:50:20 +0100 Subject: [PATCH 68/70] Hide warnings in pretty module for now --- src/pretty.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pretty.rs b/src/pretty.rs index 20844f6..cb1d34f 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -1,3 +1,6 @@ +// TODO Remove this and print whitespace and comments properly +#![allow(unused_variables)] + use pretty::{Pretty, RcAllocator}; mod basic; From af4311ba98d40d7bdbabfbcd5d51784b2909bc17 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 21:56:50 +0100 Subject: [PATCH 69/70] Remove named nils as early as possible --- src/desugar/lit.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/desugar/lit.rs b/src/desugar/lit.rs index f5942b5..3b6fd80 100644 --- a/src/desugar/lit.rs +++ b/src/desugar/lit.rs @@ -31,17 +31,17 @@ impl TableLitElem { impl TableLit { pub fn desugar(self) -> (Self, bool) { - let (elems, desugared) = self.0.desugar(|e| e.desugar()); - if desugared { - (elems.table_lit(), true) + let (elems, removed) = self.0.remove_map(|e| match e { + TableLitElem::Named { value, .. } if matches!(*value, Expr::Lit(Lit::Nil(_))) => { + Err(()) + } + e => Ok(e), + }); + if removed.is_empty() { + let (elems, desugared) = elems.desugar(|e| e.desugar()); + (elems.table_lit(), desugared) } else { - let (elems, removed) = elems.remove_map(|e| match e { - TableLitElem::Named { value, .. } if matches!(*value, Expr::Lit(Lit::Nil(_))) => { - Err(()) - } - e => Ok(e), - }); - (elems.table_lit(), !removed.is_empty()) + (elems.table_lit(), true) } } } From 802d776f2959e8c4eb72ce78fc1a99b7e7a8be60 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 22 Nov 2022 23:13:08 +0100 Subject: [PATCH 70/70] Include trailing newline in pretty print output --- src/main.rs | 2 +- src/pretty.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index a40fedc..0ac0aed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -80,7 +80,7 @@ fn main() -> anyhow::Result<()> { .parse(stream) .map_err(|e| anyhow!("{e:?}"))?; - println!("{}", pretty::pretty_to_string(program, 100)); + print!("{}", pretty::pretty_to_string(program, 100)); } Command::Desugar { diff --git a/src/pretty.rs b/src/pretty.rs index cb1d34f..0c91c87 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -21,5 +21,7 @@ pub fn pretty_to_string>(p: P, width: usize) -> p.pretty(&RcAllocator) .render(width, &mut out) .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 }