Compare commits
28 commits
separated2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 802d776f29 | |||
| af4311ba98 | |||
| f6c9835e29 | |||
| 736174d470 | |||
| 39099037a5 | |||
| f8fa044259 | |||
| 26dc3c3469 | |||
| 40c28d9496 | |||
| 6f7683ad1e | |||
| 009be99aaa | |||
| 78d08968eb | |||
| 58106c4c5a | |||
| c191486864 | |||
| 45caafdc38 | |||
| fafc567447 | |||
| 42369628b6 | |||
| 5a977e6dde | |||
| c769d9e16f | |||
| d6a0bbf2af | |||
| 830ffa92c4 | |||
| d4797c5894 | |||
| af6c171eb4 | |||
| 74d1f640b5 | |||
| 94ea196933 | |||
| 198f56226e | |||
| 0e9cfd67c2 | |||
| e3fa3500d4 | |||
| a1867fdc4e |
44 changed files with 1019 additions and 660 deletions
|
|
@ -2,6 +2,8 @@ use std::fmt;
|
|||
|
||||
use crate::span::{HasSpan, Span};
|
||||
|
||||
use super::{TableConstr, TableConstrElem, TableLit, TableLitElem};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Line {
|
||||
Empty,
|
||||
|
|
@ -37,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)]
|
||||
|
|
@ -78,21 +69,76 @@ impl HasSpan for Ident {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Separated<E, S1, S2> {
|
||||
Empty(Span),
|
||||
NonEmpty {
|
||||
first_elem: E,
|
||||
last_elems: Vec<(S1, E)>,
|
||||
trailing: Option<S2>,
|
||||
span: Span,
|
||||
},
|
||||
pub struct BoundedSeparated<E> {
|
||||
pub elems: Vec<(Space, E, Space)>,
|
||||
pub trailing: Option<Space>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<E, S1, S2> HasSpan for Separated<E, S1, S2> {
|
||||
impl<E> HasSpan for BoundedSeparated<E> {
|
||||
fn span(&self) -> Span {
|
||||
match self {
|
||||
Self::Empty(span) => *span,
|
||||
Self::NonEmpty { span, .. } => *span,
|
||||
self.span
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> BoundedSeparated<E> {
|
||||
pub fn new(span: Span) -> Self {
|
||||
Self {
|
||||
elems: vec![],
|
||||
trailing: None,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn then(mut self, elem: E) -> Self {
|
||||
self.elems
|
||||
.push((Space::empty(self.span), elem, Space::empty(self.span)));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn map<E2>(self, f: impl Fn(E) -> E2) -> BoundedSeparated<E2> {
|
||||
let elems = self
|
||||
.elems
|
||||
.into_iter()
|
||||
.map(|(s0, e, s1)| (s0, f(e), s1))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
BoundedSeparated {
|
||||
elems,
|
||||
trailing: self.trailing,
|
||||
span: self.span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_map<E1, E2>(
|
||||
self,
|
||||
f: impl Fn(E) -> Result<E1, E2>,
|
||||
) -> (BoundedSeparated<E1>, Vec<(Space, E2, Space)>) {
|
||||
let mut kept = vec![];
|
||||
let mut removed = vec![];
|
||||
for (s0, elem, s1) in self.elems {
|
||||
match f(elem) {
|
||||
Ok(elem) => kept.push((s0, elem, s1)),
|
||||
Err(elem) => removed.push((s0, elem, s1)),
|
||||
}
|
||||
}
|
||||
let new = BoundedSeparated {
|
||||
elems: kept,
|
||||
trailing: self.trailing,
|
||||
span: self.span,
|
||||
};
|
||||
(new, removed)
|
||||
}
|
||||
}
|
||||
|
||||
impl BoundedSeparated<TableLitElem> {
|
||||
pub fn table_lit(self) -> TableLit {
|
||||
TableLit(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl BoundedSeparated<TableConstrElem> {
|
||||
pub fn table_constr(self) -> TableConstr {
|
||||
TableConstr(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,3 +46,38 @@ impl HasSpan for Call {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Call {
|
||||
pub fn arg(base: Box<Expr>, arg: Box<Expr>, span: Span) -> Self {
|
||||
Self::Arg {
|
||||
expr: base,
|
||||
s0: Space::empty(span),
|
||||
s1: Space::empty(span),
|
||||
arg,
|
||||
s2: Space::empty(span),
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn no_arg(base: Box<Expr>, span: Span) -> Self {
|
||||
Self::NoArg {
|
||||
expr: base,
|
||||
s0: Space::empty(span),
|
||||
s1: Space::empty(span),
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn constr(base: Box<Expr>, constr: TableConstr, span: Span) -> Self {
|
||||
Self::Constr {
|
||||
expr: base,
|
||||
s0: Space::empty(span),
|
||||
constr,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr(self) -> Expr {
|
||||
Expr::Call(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,3 +242,9 @@ impl HasSpan for Expr {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
pub fn boxed(self) -> Box<Self> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,3 +67,34 @@ impl HasSpan for Field {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Field {
|
||||
pub fn access(base: Box<Expr>, index: Box<Expr>, span: Span) -> Self {
|
||||
Self::Access {
|
||||
expr: base,
|
||||
s0: Space::empty(span),
|
||||
s1: Space::empty(span),
|
||||
index,
|
||||
s2: Space::empty(span),
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assign(base: Box<Expr>, index: Box<Expr>, value: Box<Expr>, span: Span) -> Self {
|
||||
Self::Assign {
|
||||
expr: base,
|
||||
s0: Space::empty(span),
|
||||
s1: Space::empty(span),
|
||||
index,
|
||||
s2: Space::empty(span),
|
||||
s3: Space::empty(span),
|
||||
s4: Space::empty(span),
|
||||
value,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr(self) -> Expr {
|
||||
Expr::Field(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,3 +99,41 @@ impl HasSpan for FuncDef {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FuncDef {
|
||||
pub fn anon_no_arg(body: Box<Expr>, span: Span) -> Self {
|
||||
Self::AnonNoArg {
|
||||
s0: Space::empty(span),
|
||||
s1: Space::empty(span),
|
||||
s2: Space::empty(span),
|
||||
body,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn anon_arg(arg: Ident, body: Box<Expr>, span: Span) -> Self {
|
||||
Self::AnonArg {
|
||||
s0: Space::empty(span),
|
||||
s1: Space::empty(span),
|
||||
arg,
|
||||
s2: Space::empty(span),
|
||||
s3: Space::empty(span),
|
||||
body,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn anon_destr(pattern: TablePattern, body: Box<Expr>, span: Span) -> Self {
|
||||
Self::AnonDestr {
|
||||
s0: Space::empty(span),
|
||||
pattern,
|
||||
s1: Space::empty(span),
|
||||
body,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr(self) -> Expr {
|
||||
Expr::FuncDef(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -93,6 +93,19 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lit(self) -> Lit {
|
||||
Lit::String(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasSpan for StringLit {
|
||||
fn span(&self) -> Span {
|
||||
self.span
|
||||
|
|
@ -125,20 +138,31 @@ impl HasSpan for TableLitElem {
|
|||
}
|
||||
}
|
||||
|
||||
/// `'{ a, foo: b }`
|
||||
///
|
||||
/// Structure: `'{ s0 elems s1 }`
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TableLit {
|
||||
pub s0: Space,
|
||||
pub elems: Separated<TableLitElem, (Space, Space), Space>,
|
||||
pub s1: Space,
|
||||
pub span: Span,
|
||||
impl TableLitElem {
|
||||
pub fn named(name: Ident, value: Box<Expr>, 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<TableLitElem>);
|
||||
|
||||
impl HasSpan for TableLit {
|
||||
fn span(&self) -> Span {
|
||||
self.span
|
||||
self.0.span()
|
||||
}
|
||||
}
|
||||
|
||||
impl TableLit {
|
||||
pub fn lit(self) -> Lit {
|
||||
Lit::Table(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -196,3 +220,9 @@ impl HasSpan for Lit {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Lit {
|
||||
pub fn expr(self) -> Expr {
|
||||
Expr::Lit(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TableLitElem, (Space, Space), Space>,
|
||||
s2: Space,
|
||||
elems: BoundedSeparated<TableLitElem>,
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::span::{HasSpan, Span};
|
||||
|
||||
use super::{Expr, Separated, Space, TableLitElem};
|
||||
use super::{BoundedSeparated, Expr, Ident, Space, TableLitElem};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TableConstrElem {
|
||||
|
|
@ -30,19 +30,28 @@ 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<TableConstrElem, (Space, Space), Space>,
|
||||
pub s1: Space,
|
||||
pub span: Span,
|
||||
impl TableConstrElem {
|
||||
pub fn positional(value: Box<Expr>) -> Self {
|
||||
Self::Lit(TableLitElem::Positional(value))
|
||||
}
|
||||
|
||||
pub fn named(name: Ident, value: Box<Expr>, span: Span) -> Self {
|
||||
Self::Lit(TableLitElem::named(name, value, span))
|
||||
}
|
||||
}
|
||||
|
||||
/// `{ a, b, foo: c, [d]: e }`
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TableConstr(pub BoundedSeparated<TableConstrElem>);
|
||||
|
||||
impl HasSpan for TableConstr {
|
||||
fn span(&self) -> Span {
|
||||
self.span
|
||||
self.0.span()
|
||||
}
|
||||
}
|
||||
|
||||
impl TableConstr {
|
||||
pub fn expr(self) -> Expr {
|
||||
Expr::TableConstr(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TablePatternElem, (Space, Space), Space>,
|
||||
pub s1: Space,
|
||||
pub span: Span,
|
||||
}
|
||||
pub struct TablePattern(pub BoundedSeparated<TablePatternElem>);
|
||||
|
||||
impl HasSpan for TablePattern {
|
||||
fn span(&self) -> Span {
|
||||
self.span
|
||||
self.0.span()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,3 +61,26 @@ impl HasSpan for TableDestr {
|
|||
self.span
|
||||
}
|
||||
}
|
||||
|
||||
impl TableDestr {
|
||||
pub fn new(local: bool, pattern: TablePattern, value: Box<Expr>, span: Span) -> Self {
|
||||
let local = if local {
|
||||
Some(Space::empty(span))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Self {
|
||||
local,
|
||||
pattern,
|
||||
s0: Space::empty(span),
|
||||
s1: Space::empty(span),
|
||||
value,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr(self) -> Expr {
|
||||
Expr::TableDestr(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,3 +56,54 @@ impl HasSpan for Var {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Var {
|
||||
pub fn access(index: Box<Expr>, span: Span) -> Self {
|
||||
Self::Access {
|
||||
s0: Space::empty(span),
|
||||
index,
|
||||
s1: Space::empty(span),
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assign(local: bool, index: Box<Expr>, value: Box<Expr>, span: Span) -> Self {
|
||||
let local = if local {
|
||||
Some(Space::empty(span))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Self::Assign {
|
||||
local,
|
||||
s0: Space::empty(span),
|
||||
index,
|
||||
s1: Space::empty(span),
|
||||
s2: Space::empty(span),
|
||||
s3: Space::empty(span),
|
||||
value,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assign_ident(local: bool, name: Ident, value: Box<Expr>, span: Span) -> Self {
|
||||
let local = if local {
|
||||
Some(Space::empty(span))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Self::AssignIdent {
|
||||
local,
|
||||
name,
|
||||
s0: Space::empty(span),
|
||||
s1: Space::empty(span),
|
||||
value,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr(self) -> Expr {
|
||||
Expr::Var(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ mod basic;
|
|||
mod call;
|
||||
mod expr;
|
||||
mod field;
|
||||
mod func_def;
|
||||
mod lit;
|
||||
mod program;
|
||||
mod table_constr;
|
||||
mod table_destr;
|
||||
mod var;
|
||||
|
|
|
|||
|
|
@ -1,36 +1,24 @@
|
|||
use crate::ast::Separated;
|
||||
use crate::ast::BoundedSeparated;
|
||||
|
||||
impl<E, S1, S2> Separated<E, S1, S2> {
|
||||
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 {
|
||||
impl<E> BoundedSeparated<E> {
|
||||
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 {
|
||||
new_last_elems.push((separator, elem));
|
||||
elems.push((s0, elem, s1));
|
||||
} else {
|
||||
let (elem, elem_desugared) = desugar_elem(elem);
|
||||
desugared = desugared || elem_desugared;
|
||||
new_last_elems.push((separator, elem));
|
||||
elems.push((s0, elem, s1));
|
||||
}
|
||||
}
|
||||
|
||||
let new = Self::NonEmpty {
|
||||
first_elem: new_first_elem,
|
||||
last_elems: new_last_elems,
|
||||
trailing,
|
||||
span,
|
||||
let new = Self {
|
||||
elems,
|
||||
trailing: self.trailing,
|
||||
span: self.span,
|
||||
};
|
||||
(new, desugared)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ast::{Call, Expr, Ident, Lit, Separated, Space, TableLit, TableLitElem};
|
||||
use crate::ast::{BoundedSeparated, Call, Expr, Ident, Lit, TableLitElem};
|
||||
|
||||
// TODO Add span for just the parentheses to ast, or limit span to parentheses
|
||||
|
||||
|
|
@ -7,74 +7,37 @@ 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),
|
||||
s1: Space::empty(span),
|
||||
value: expr,
|
||||
span,
|
||||
};
|
||||
let arg = TableLitElem::Named {
|
||||
name: Ident::new("arg", span),
|
||||
s0: Space::empty(span),
|
||||
s1,
|
||||
value: arg,
|
||||
span,
|
||||
};
|
||||
let elems = Separated::NonEmpty {
|
||||
first_elem: call,
|
||||
last_elems: vec![((Space::empty(span), Space::empty(span)), arg)],
|
||||
trailing: None,
|
||||
span,
|
||||
};
|
||||
let new = Expr::Lit(Lit::Table(TableLit {
|
||||
s0,
|
||||
elems,
|
||||
s1: s2,
|
||||
span,
|
||||
}));
|
||||
(new, true)
|
||||
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();
|
||||
(new.lit().expr(), true)
|
||||
}
|
||||
|
||||
Self::NoArg { expr, s0, s1, span } => {
|
||||
// `expr s0 ( s1 )`
|
||||
// -> `expr s0 ( s1 nil )`
|
||||
let new = Expr::Call(Self::Arg {
|
||||
Self::NoArg {
|
||||
expr,
|
||||
s0,
|
||||
s1,
|
||||
arg: Box::new(Expr::Lit(Lit::Nil(span))),
|
||||
s2: Space::empty(span),
|
||||
s0: _,
|
||||
s1: _,
|
||||
span,
|
||||
});
|
||||
(new, true)
|
||||
} => {
|
||||
let new = Self::arg(expr, Lit::Nil(span).expr().boxed(), span);
|
||||
(new.expr(), true)
|
||||
}
|
||||
|
||||
Self::Constr {
|
||||
expr,
|
||||
s0,
|
||||
s0: _,
|
||||
constr,
|
||||
span,
|
||||
} => {
|
||||
// `expr s0 {..}`
|
||||
// -> `expr s0 ( {..} )`
|
||||
let new = Expr::Call(Self::Arg {
|
||||
expr,
|
||||
s0,
|
||||
s1: Space::empty(span),
|
||||
arg: Box::new(Expr::TableConstr(constr)),
|
||||
s2: Space::empty(span),
|
||||
span,
|
||||
});
|
||||
(new, true)
|
||||
let new = Self::arg(expr, constr.expr().boxed(), span);
|
||||
(new.expr(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,84 +1,78 @@
|
|||
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) {
|
||||
match self {
|
||||
Self::Lit(lit) => {
|
||||
let (lit, desugared) = lit.desugar();
|
||||
(Self::Lit(lit), desugared)
|
||||
(lit.expr(), desugared)
|
||||
}
|
||||
|
||||
Self::Call(call) => call.desugar(),
|
||||
Self::Field(field) => field.desugar(),
|
||||
Self::Var(var) => var.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::TableConstr(constr) => constr.desugar(),
|
||||
Self::TableDestr(destr) => destr.desugar(),
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
use crate::ast::{
|
||||
Call, Expr, Field, Line, Lit, Separated, Space, StringLit, StringLitElem, TableConstr,
|
||||
TableConstrElem, TableLitElem,
|
||||
};
|
||||
use crate::ast::{BoundedSeparated, Call, Expr, Field, Lit, StringLit, TableConstrElem};
|
||||
use crate::builtin::Builtin;
|
||||
|
||||
impl Field {
|
||||
|
|
@ -9,133 +6,80 @@ 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 = Separated::NonEmpty {
|
||||
first_elem: TableConstrElem::Lit(TableLitElem::Positional(expr)),
|
||||
last_elems: vec![(
|
||||
(Space::empty(span), s1),
|
||||
TableConstrElem::Lit(TableLitElem::Positional(index)),
|
||||
)],
|
||||
trailing: None,
|
||||
span,
|
||||
};
|
||||
let constr = TableConstr {
|
||||
s0: Space::empty(span),
|
||||
elems,
|
||||
s1: s2,
|
||||
span,
|
||||
};
|
||||
let new = Expr::Call(Call::Constr {
|
||||
expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Get, span))),
|
||||
s0,
|
||||
let constr = BoundedSeparated::new(span)
|
||||
.then(TableConstrElem::positional(expr))
|
||||
.then(TableConstrElem::positional(index))
|
||||
.table_constr();
|
||||
let new = Call::constr(
|
||||
Lit::Builtin(Builtin::Get, span).expr().boxed(),
|
||||
constr,
|
||||
span,
|
||||
});
|
||||
(new, true)
|
||||
);
|
||||
(new.expr(), true)
|
||||
}
|
||||
|
||||
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 = 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 new = Expr::Call(Call::Constr {
|
||||
expr: Box::new(Expr::Lit(Lit::Builtin(Builtin::Set, span))),
|
||||
s0,
|
||||
let constr = BoundedSeparated::new(span)
|
||||
.then(TableConstrElem::positional(expr))
|
||||
.then(TableConstrElem::positional(index))
|
||||
.then(TableConstrElem::positional(value))
|
||||
.table_constr();
|
||||
let new = Call::constr(
|
||||
Lit::Builtin(Builtin::Set, span).expr().boxed(),
|
||||
constr,
|
||||
span,
|
||||
});
|
||||
(new, true)
|
||||
);
|
||||
(new.expr(), true)
|
||||
}
|
||||
|
||||
Self::AccessIdent {
|
||||
expr,
|
||||
s0,
|
||||
s1,
|
||||
s0: _,
|
||||
s1: _,
|
||||
ident,
|
||||
span,
|
||||
} => {
|
||||
// `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 {
|
||||
let new = Self::access(
|
||||
expr,
|
||||
s0,
|
||||
s1,
|
||||
index: Box::new(ident_str),
|
||||
s2: Space::empty(span),
|
||||
StringLit::from_ident(ident).lit().expr().boxed(),
|
||||
span,
|
||||
});
|
||||
(new, true)
|
||||
);
|
||||
(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 ident_str = Expr::Lit(Lit::String(StringLit {
|
||||
elems: vec![StringLitElem::Plain(ident.name)],
|
||||
span: ident.span,
|
||||
}));
|
||||
let new = Expr::Field(Self::Assign {
|
||||
let new = Self::assign(
|
||||
expr,
|
||||
s0,
|
||||
s1,
|
||||
index: Box::new(ident_str),
|
||||
s2: Space::empty(span),
|
||||
s3: s2,
|
||||
s4: s3,
|
||||
StringLit::from_ident(ident).lit().expr().boxed(),
|
||||
value,
|
||||
span,
|
||||
});
|
||||
(new, true)
|
||||
);
|
||||
(new.expr(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
128
src/desugar/func_def.rs
Normal file
128
src/desugar/func_def.rs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
use crate::ast::{
|
||||
BoundedSeparated, Call, Expr, FuncDef, Ident, Lit, Space, TableConstrElem, TableDestr,
|
||||
TableLitElem, Var,
|
||||
};
|
||||
use crate::builtin::Builtin;
|
||||
|
||||
impl FuncDef {
|
||||
pub fn desugar(self) -> (Expr, bool) {
|
||||
match self {
|
||||
Self::AnonNoArg {
|
||||
s0: _,
|
||||
s1: _,
|
||||
s2: _,
|
||||
body,
|
||||
span,
|
||||
} => {
|
||||
let quote = BoundedSeparated::new(span)
|
||||
.then(TableLitElem::named(Ident::new("quote", span), body, span))
|
||||
.table_lit();
|
||||
let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span);
|
||||
let new = BoundedSeparated::new(span)
|
||||
.then(TableConstrElem::positional(Box::new(quote.lit().expr())))
|
||||
.then(TableConstrElem::named(
|
||||
Ident::new("scope", span),
|
||||
scope.expr().boxed(),
|
||||
span,
|
||||
))
|
||||
.table_constr();
|
||||
(new.expr(), true)
|
||||
}
|
||||
|
||||
Self::AnonArg {
|
||||
s0: _,
|
||||
s1: _,
|
||||
arg,
|
||||
s2: _,
|
||||
s3: _,
|
||||
body,
|
||||
span,
|
||||
} => {
|
||||
let arg_call = Call::no_arg(Lit::Builtin(Builtin::Arg, span).expr().boxed(), span);
|
||||
let arg_assign = Var::assign_ident(true, arg, arg_call.expr().boxed(), span);
|
||||
let body = BoundedSeparated::new(span)
|
||||
.then(TableLitElem::Positional(arg_assign.expr().boxed()))
|
||||
.then(TableLitElem::Positional(body))
|
||||
.table_lit();
|
||||
let new = Self::AnonNoArg {
|
||||
s0: Space::empty(span),
|
||||
s1: Space::empty(span),
|
||||
s2: Space::empty(span),
|
||||
body: body.lit().expr().boxed(),
|
||||
span,
|
||||
};
|
||||
(new.expr(), true)
|
||||
}
|
||||
|
||||
Self::AnonDestr {
|
||||
s0: _,
|
||||
pattern,
|
||||
s1: _,
|
||||
body,
|
||||
span,
|
||||
} => {
|
||||
let arg_call = Call::no_arg(Lit::Builtin(Builtin::Arg, span).expr().boxed(), span);
|
||||
let arg_destr = TableDestr::new(true, pattern, arg_call.expr().boxed(), span);
|
||||
let body = BoundedSeparated::new(span)
|
||||
.then(TableLitElem::Positional(arg_destr.expr().boxed()))
|
||||
.then(TableLitElem::Positional(body))
|
||||
.table_lit();
|
||||
let new = Self::AnonNoArg {
|
||||
s0: Space::empty(span),
|
||||
s1: Space::empty(span),
|
||||
s2: Space::empty(span),
|
||||
body: body.lit().expr().boxed(),
|
||||
span,
|
||||
};
|
||||
(new.expr(), true)
|
||||
}
|
||||
|
||||
Self::NamedNoArg {
|
||||
local,
|
||||
s0: _,
|
||||
name,
|
||||
s1: _,
|
||||
s2: _,
|
||||
s3: _,
|
||||
body,
|
||||
span,
|
||||
} => {
|
||||
let anon = Self::anon_no_arg(body, span);
|
||||
let new = Var::assign_ident(local.is_some(), name, anon.expr().boxed(), span);
|
||||
(new.expr(), true)
|
||||
}
|
||||
|
||||
Self::NamedArg {
|
||||
local,
|
||||
s0: _,
|
||||
name,
|
||||
s1: _,
|
||||
s2: _,
|
||||
arg,
|
||||
s3: _,
|
||||
s4: _,
|
||||
body,
|
||||
span,
|
||||
} => {
|
||||
let anon = Self::anon_arg(arg, body, span);
|
||||
let new = Var::assign_ident(local.is_some(), name, anon.expr().boxed(), span);
|
||||
(new.expr(), true)
|
||||
}
|
||||
|
||||
Self::NamedDestr {
|
||||
local,
|
||||
s0: _,
|
||||
name,
|
||||
s1: _,
|
||||
pattern,
|
||||
s2: _,
|
||||
body,
|
||||
span,
|
||||
} => {
|
||||
let anon = Self::anon_destr(pattern, body, span);
|
||||
let new = Var::assign_ident(local.is_some(), name, anon.expr().boxed(), span);
|
||||
(new.expr(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::ast::{Lit, TableLit, TableLitElem};
|
||||
use crate::ast::{Expr, 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::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)
|
||||
|
|
@ -31,21 +31,18 @@ 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, 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 {
|
||||
(elems.table_lit(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +51,7 @@ impl Lit {
|
|||
match self {
|
||||
Self::Table(table) => {
|
||||
let (table, desugared) = table.desugar();
|
||||
(Self::Table(table), desugared)
|
||||
(table.lit(), desugared)
|
||||
}
|
||||
|
||||
lit => (lit, false),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ast::{Expr, Lit, Program, Space, TableLit};
|
||||
use crate::ast::{Program, Space};
|
||||
|
||||
impl Program {
|
||||
pub fn desugar(self) -> (Self, bool) {
|
||||
|
|
@ -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: elems.table_lit().lit().expr(),
|
||||
s1: Space::empty(span),
|
||||
span,
|
||||
};
|
||||
|
|
|
|||
39
src/desugar/table_constr.rs
Normal file
39
src/desugar/table_constr.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
use crate::ast::{
|
||||
BoundedSeparated, Expr, Field, Ident, TableConstr, TableConstrElem, TableLitElem,
|
||||
};
|
||||
use crate::span::HasSpan;
|
||||
|
||||
impl TableConstr {
|
||||
pub fn desugar(self) -> (Expr, bool) {
|
||||
let span = self.span();
|
||||
|
||||
let (elems, setters) = self.0.remove_map(|e| match e {
|
||||
TableConstrElem::Lit(lit) => Ok(lit),
|
||||
TableConstrElem::Indexed {
|
||||
s0: _,
|
||||
index,
|
||||
s1: _,
|
||||
s2: _,
|
||||
s3: _,
|
||||
value,
|
||||
span,
|
||||
} => Err((index, value, span)),
|
||||
});
|
||||
|
||||
let mut expr = BoundedSeparated::new(span)
|
||||
.then(TableLitElem::named(
|
||||
Ident::new("raw", span),
|
||||
elems.table_lit().lit().expr().boxed(),
|
||||
span,
|
||||
))
|
||||
.table_lit()
|
||||
.lit()
|
||||
.expr();
|
||||
|
||||
for (_, (index, value, span), _) in setters {
|
||||
expr = Field::assign(expr.boxed(), index, value, span).expr();
|
||||
}
|
||||
|
||||
(expr, true)
|
||||
}
|
||||
}
|
||||
63
src/desugar/table_destr.rs
Normal file
63
src/desugar/table_destr.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use crate::ast::{
|
||||
BoundedSeparated, Call, Expr, Ident, Lit, StringLit, TableConstr, TableConstrElem, TableDestr,
|
||||
TableLitElem, TablePattern, TablePatternElem,
|
||||
};
|
||||
use crate::builtin::Builtin;
|
||||
|
||||
fn pattern_to_constr(pattern: TablePattern) -> TableConstr {
|
||||
pattern
|
||||
.0
|
||||
.map(|e| match e {
|
||||
TablePatternElem::Positional(ident) => {
|
||||
TableConstrElem::positional(StringLit::from_ident(ident).lit().expr().boxed())
|
||||
}
|
||||
|
||||
TablePatternElem::Named {
|
||||
name,
|
||||
s0,
|
||||
s1,
|
||||
ident,
|
||||
span,
|
||||
} => TableConstrElem::Lit(TableLitElem::Named {
|
||||
name,
|
||||
s0,
|
||||
s1,
|
||||
value: StringLit::from_ident(ident).lit().expr().boxed(),
|
||||
span,
|
||||
}),
|
||||
})
|
||||
.table_constr()
|
||||
}
|
||||
|
||||
impl TableDestr {
|
||||
pub fn desugar(self) -> (Expr, bool) {
|
||||
let Self {
|
||||
local,
|
||||
pattern,
|
||||
s0: _,
|
||||
s1: _,
|
||||
value,
|
||||
span,
|
||||
} = self;
|
||||
|
||||
let mut constr = BoundedSeparated::new(span)
|
||||
.then(TableConstrElem::positional(
|
||||
pattern_to_constr(pattern).expr().boxed(),
|
||||
))
|
||||
.then(TableConstrElem::positional(value));
|
||||
if local.is_some() {
|
||||
constr = constr.then(TableConstrElem::named(
|
||||
Ident::new("local", span),
|
||||
Lit::Bool(true, span).expr().boxed(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let new = Call::constr(
|
||||
Lit::Builtin(Builtin::Destructure, span).expr().boxed(),
|
||||
constr.table_constr(),
|
||||
span,
|
||||
);
|
||||
(new.expr(), true)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
use crate::ast::{
|
||||
Call, Expr, Field, Line, Lit, Separated, Space, StringLit, StringLitElem, TableConstr,
|
||||
TableConstrElem, TableLitElem, Var,
|
||||
};
|
||||
use crate::ast::{BoundedSeparated, Call, Expr, Field, Lit, StringLit, TableConstrElem, Var};
|
||||
use crate::builtin::Builtin;
|
||||
use crate::span::HasSpan;
|
||||
|
||||
|
|
@ -9,152 +6,76 @@ impl Var {
|
|||
pub fn desugar(self) -> (Expr, bool) {
|
||||
match self {
|
||||
Self::Access {
|
||||
s0,
|
||||
s0: _,
|
||||
index,
|
||||
s1,
|
||||
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)
|
||||
let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), 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,
|
||||
} => {
|
||||
// `[ 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)
|
||||
let scope = Call::no_arg(Lit::Builtin(Builtin::Scope, span).expr().boxed(), span);
|
||||
let new = Field::assign(scope.expr().boxed(), index, value, span);
|
||||
(new.expr(), true)
|
||||
}
|
||||
|
||||
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 = 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),
|
||||
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(
|
||||
Lit::Builtin(Builtin::SetRaw, span).expr().boxed(),
|
||||
constr,
|
||||
span,
|
||||
});
|
||||
(new, true)
|
||||
);
|
||||
(new.expr(), 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)
|
||||
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 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,
|
||||
let new = Self::assign(
|
||||
local.is_some(),
|
||||
StringLit::from_ident(name).lit().expr().boxed(),
|
||||
value,
|
||||
span,
|
||||
});
|
||||
(new, true)
|
||||
);
|
||||
(new.expr(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use chumsky::prelude::*;
|
||||
use chumsky::text::Character;
|
||||
|
||||
use crate::ast::{Ident, Line, Separated, Space};
|
||||
use crate::ast::{BoundedSeparated, Ident, Line, Space};
|
||||
use crate::span::Span;
|
||||
|
||||
pub type Error = Simple<char, Span>;
|
||||
|
|
@ -62,23 +62,42 @@ pub fn local(space: EParser<Space>) -> EParser<Option<Space>> {
|
|||
// This function is more of a utility function. Because of this and to keep the
|
||||
// code nicer, I have decided that the rules specified in the `parser` module
|
||||
// don't apply to it.
|
||||
pub fn separated_by<E: 'static, S1: 'static, S2: 'static>(
|
||||
pub fn bounded_separated<E: 'static>(
|
||||
space: impl Parser<char, Space, Error = Error> + Clone + 'static,
|
||||
start: impl Parser<char, (), Error = Error> + 'static,
|
||||
end: impl Parser<char, (), Error = Error> + 'static,
|
||||
separator: impl Parser<char, (), Error = Error> + 'static,
|
||||
elem: impl Parser<char, E, Error = Error> + Clone + 'static,
|
||||
separator: impl Parser<char, S1, Error = Error> + 'static,
|
||||
trailing_separator: impl Parser<char, S2, Error = Error> + 'static,
|
||||
) -> EParser<Separated<E, S1, S2>> {
|
||||
) -> EParser<BoundedSeparated<E>> {
|
||||
start
|
||||
.ignore_then(space.clone())
|
||||
.then(
|
||||
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,
|
||||
.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,
|
||||
},
|
||||
None => Separated::Empty(span),
|
||||
}
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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<char, Builtin, Error = Error> {
|
||||
just('\'').ignore_then(choice((
|
||||
|
|
@ -132,7 +132,7 @@ pub fn table_lit_elem(
|
|||
) -> EParser<TableLitElem> {
|
||||
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,
|
||||
});
|
||||
|
||||
|
|
@ -154,20 +154,14 @@ fn table_lit(
|
|||
space: EParser<Space>,
|
||||
table_lit_elem: EParser<TableLitElem>,
|
||||
) -> impl Parser<char, TableLit, Error = Error> {
|
||||
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<Space>, table_lit_elem: EParser<TableLitElem>) -> EParser<Lit> {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<Space>,
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,31 +57,38 @@ 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 {
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -143,7 +155,7 @@ fn suffix_call_arg(
|
|||
.map(|(((s0, s1), arg), s2)| Suffix::CallArg {
|
||||
s0,
|
||||
s1,
|
||||
arg: Box::new(arg),
|
||||
arg: arg.boxed(),
|
||||
s2,
|
||||
})
|
||||
}
|
||||
|
|
@ -180,7 +192,7 @@ fn suffix_field_access(
|
|||
.map(|(((s0, s1), index), s2)| Suffix::FieldAccess {
|
||||
s0,
|
||||
s1,
|
||||
index: Box::new(index),
|
||||
index: index.boxed(),
|
||||
s2,
|
||||
})
|
||||
}
|
||||
|
|
@ -204,11 +216,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 +258,7 @@ fn suffix_field_assign_ident(
|
|||
ident,
|
||||
s2,
|
||||
s3,
|
||||
value: Box::new(value),
|
||||
value: value.boxed(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Space>,
|
||||
|
|
@ -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,
|
||||
},
|
||||
);
|
||||
|
|
@ -43,19 +43,13 @@ pub fn table_constr(
|
|||
expr: EParser<Expr>,
|
||||
) -> EParser<TableConstr> {
|
||||
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,
|
||||
})
|
||||
bounded_separated(
|
||||
space,
|
||||
just('{').to(()),
|
||||
just('}').to(()),
|
||||
just(',').to(()),
|
||||
elem,
|
||||
)
|
||||
.map(TableConstr)
|
||||
.boxed()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Space>,
|
||||
|
|
@ -31,20 +31,14 @@ fn table_pattern_elem(
|
|||
|
||||
pub fn table_pattern(space: EParser<Space>, ident: EParser<Ident>) -> EParser<TablePattern> {
|
||||
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,
|
||||
})
|
||||
bounded_separated(
|
||||
space,
|
||||
just('{').to(()),
|
||||
just('}').to(()),
|
||||
just(',').to(()),
|
||||
elem,
|
||||
)
|
||||
.map(TablePattern)
|
||||
.boxed()
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +59,7 @@ pub fn table_destr(
|
|||
pattern,
|
||||
s0,
|
||||
s1,
|
||||
value: Box::new(value),
|
||||
value: value.boxed(),
|
||||
span,
|
||||
})
|
||||
.boxed()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ fn var_access(space: EParser<Space>, expr: EParser<Expr>) -> impl Parser<char, V
|
|||
.then_ignore(just(']'))
|
||||
.map_with_span(|((s0, index), s1), span| Var::Access {
|
||||
s0,
|
||||
index: Box::new(index),
|
||||
index: index.boxed(),
|
||||
s1,
|
||||
span,
|
||||
})
|
||||
|
|
@ -39,11 +39,11 @@ fn var_assign(
|
|||
|((((((local, s0), index), s1), s2), s3), value), span| Var::Assign {
|
||||
local,
|
||||
s0,
|
||||
index: Box::new(index),
|
||||
index: index.boxed(),
|
||||
s1,
|
||||
s2,
|
||||
s3,
|
||||
value: Box::new(value),
|
||||
value: value.boxed(),
|
||||
span,
|
||||
},
|
||||
)
|
||||
|
|
@ -67,7 +67,7 @@ fn var_assign_ident(
|
|||
name,
|
||||
s0,
|
||||
s1,
|
||||
value: Box::new(value),
|
||||
value: value.boxed(),
|
||||
span,
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// TODO Remove this and print whitespace and comments properly
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use pretty::{Pretty, RcAllocator};
|
||||
|
||||
mod basic;
|
||||
|
|
@ -18,5 +21,7 @@ pub fn pretty_to_string<P: Pretty<'static, RcAllocator>>(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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use pretty::{DocAllocator, DocBuilder, Pretty};
|
||||
|
||||
use crate::ast::{Ident, Separated};
|
||||
use crate::ast::{BoundedSeparated, Ident};
|
||||
|
||||
use super::NEST_DEPTH;
|
||||
|
||||
impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Ident {
|
||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
|
||||
|
|
@ -8,40 +10,32 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Ident {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E, S1, S2> Separated<E, S1, S2> {
|
||||
pub fn pretty<'a, D, FE, FS1, FS2>(
|
||||
impl<E> BoundedSeparated<E> {
|
||||
pub fn pretty<'a, D, FE>(
|
||||
self,
|
||||
allocator: &'a D,
|
||||
elem_to_doc: FE,
|
||||
separator_to_doc: FS1,
|
||||
trailing_separator_to_doc: FS2,
|
||||
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>,
|
||||
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
|
||||
let elems_empty = self.elems.is_empty();
|
||||
allocator
|
||||
.intersperse(
|
||||
self.elems
|
||||
.into_iter()
|
||||
.map(|(s, e)| separator_to_doc(s).append(elem_to_doc(e))),
|
||||
),
|
||||
.map(|(s0, elem, s1)| allocator.line().append(elem_pretty(elem))),
|
||||
separator.clone(),
|
||||
)
|
||||
.append(
|
||||
trailing
|
||||
.map(trailing_separator_to_doc)
|
||||
.unwrap_or_else(|| allocator.nil()),
|
||||
),
|
||||
}
|
||||
.append(self.trailing.filter(|_| !elems_empty).map(|s| separator))
|
||||
.nest(NEST_DEPTH)
|
||||
.append(allocator.line())
|
||||
.enclose(start, end)
|
||||
.group()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
self.0.pretty(
|
||||
allocator,
|
||||
|e| allocator.line().append(e.pretty(allocator)),
|
||||
|(s0, s1)| allocator.text(","),
|
||||
|s| allocator.text(","),
|
||||
allocator.text("'{"),
|
||||
allocator.text("}"),
|
||||
allocator.text(","),
|
||||
|e| e.pretty(allocator),
|
||||
)
|
||||
.nest(NEST_DEPTH)
|
||||
.append(allocator.line())
|
||||
.enclose(allocator.text("'{"), allocator.text("}"))
|
||||
.group()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for Lit {
|
||||
impl<'a, D> Pretty<'a, D> for Lit
|
||||
where
|
||||
D: DocAllocator<'a>,
|
||||
D::Doc: Clone,
|
||||
{
|
||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
|
||||
match self {
|
||||
Self::Nil(_) => allocator.text("nil"),
|
||||
|
|
|
|||
|
|
@ -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(","))),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ use pretty::{DocAllocator, DocBuilder, Pretty};
|
|||
|
||||
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,18 +27,18 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableConstrElem {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableConstr {
|
||||
impl<'a, D> Pretty<'a, D> for TableConstr
|
||||
where
|
||||
D: DocAllocator<'a>,
|
||||
D::Doc: Clone,
|
||||
{
|
||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
|
||||
self.elems
|
||||
.pretty(
|
||||
self.0.pretty(
|
||||
allocator,
|
||||
|e| allocator.line().append(e.pretty(allocator)),
|
||||
|(s0, s1)| allocator.text(","),
|
||||
|s| allocator.text(","),
|
||||
allocator.text("{"),
|
||||
allocator.text("}"),
|
||||
allocator.text(","),
|
||||
|e| e.pretty(allocator),
|
||||
)
|
||||
.nest(NEST_DEPTH)
|
||||
.append(allocator.line())
|
||||
.braces()
|
||||
.group()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,23 +20,27 @@ impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePatternElem {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TablePattern {
|
||||
impl<'a, D> Pretty<'a, D> for TablePattern
|
||||
where
|
||||
D: DocAllocator<'a>,
|
||||
D::Doc: Clone,
|
||||
{
|
||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
|
||||
self.elems
|
||||
.pretty(
|
||||
self.0.pretty(
|
||||
allocator,
|
||||
|e| allocator.line().append(e.pretty(allocator)),
|
||||
|(s0, s1)| allocator.text(","),
|
||||
|s| allocator.text(","),
|
||||
allocator.text("{"),
|
||||
allocator.text("}"),
|
||||
allocator.text(","),
|
||||
|e| e.pretty(allocator),
|
||||
)
|
||||
.nest(NEST_DEPTH)
|
||||
.append(allocator.line())
|
||||
.braces()
|
||||
.group()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, D: DocAllocator<'a>> Pretty<'a, D> for TableDestr {
|
||||
impl<'a, D> Pretty<'a, D> for TableDestr
|
||||
where
|
||||
D: DocAllocator<'a>,
|
||||
D::Doc: Clone,
|
||||
{
|
||||
fn pretty(self, allocator: &'a D) -> DocBuilder<'a, D> {
|
||||
// TODO Handle spaces
|
||||
self.local
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue