diff --git a/src/ast.rs b/src/ast.rs index d27f1e2..1602c87 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -46,20 +46,6 @@ pub enum Pat { Typed(Box, Ty), } -/// The arms of a make expression -/// ```ignore -/// Identifier (':' Expr)? -/// ``` -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MakeArm(pub String, pub Option, A>>); - -/// The arms of a match expression -/// ```ignore -/// (Pat |)* Pat? => Expr -/// ``` -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MatchArm(pub Pat, pub Anno, A>); - /// In-universe types #[derive(Clone, Debug, PartialEq, Eq)] pub enum Ty { @@ -73,26 +59,66 @@ pub enum Ty { Slice(Box), /// `[Ty; _]` Array(Box, Box), - /// `[Rety, ..Args]` + /// `[..Args, Rety]` Fn(Vec), } -/// A `const` binding (which defines its name before executing) -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Const(pub Pat, pub Anno, A>); - -/// A function definition `fn Ident? (Pat,*) Expr` -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Fn(pub Option, pub Pat, pub Anno, A>); - -/// A `let` binding: `let Pat (= Expr)?` +/// A `let` binding +/// ```ignore +/// let Pat (= Expr)? +/// `````` #[derive(Clone, Debug, PartialEq, Eq)] pub struct Let(pub Pat, pub Option, A>>); -/// `match Expr { MatchArm,* }`` +/// A `const` binding (which defines its name before executing) +/// ```ignore +/// const Pat = Expr +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Const(pub Pat, pub Anno, A>); + +/// A function definition +/// ```ignore +/// fn Ident? (Pat) Expr +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Fn(pub Option, pub Pat, pub Anno, A>); + +/// A match expression +/// ```ignore +/// match Expr { MatchArm,* } +/// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub struct Match(pub Anno, A>, pub Vec>); +/// The "arms" of a match expression +/// ```ignore +/// Pat => Expr +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MatchArm(pub Pat, pub Anno, A>); + +/// A make (constructor) expression +/// ```ignore +/// Expr { (Ident (: Expr)?),* } +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Make(pub Box, A>>, pub Vec>); + +/// A single "arm" of a make expression +/// ```ignore +/// Identifier (':' Expr)? +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MakeArm(pub String, pub Option, A>>); + +/// An inline namespace +/// ```ignore +/// mod Ty Expr +/// ``` +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Mod(pub Ty, pub Anno, A>); + /// Expressions: The beating heart of Dough #[derive(Clone, Debug, PartialEq, Eq)] pub enum Expr { @@ -109,9 +135,11 @@ pub enum Expr { /// `| Pat | Expr` | `|| Expr` | `fn Ident? (Pat,*) Expr` Fn(Box>), /// Expr { (Ident (: Expr)?),* } - Make(Box>, Vec>), + Make(Box>), /// match Expr { MatchArm,* } Match(Box>), + /// mod Ty Expr + Mod(Box>), /// Op Expr | Expr Op | Expr (Op Expr)+ | Op Expr Expr else Expr Op(Op, Vec>), } @@ -149,6 +177,7 @@ pub enum Op { Macro, // macro Expr => Expr Block, // { Expr } Array, // [ Expr,* ] + ArRep, // [ Expr ; Expr ] Group, // ( Expr ,?) Tuple, // Expr (, Expr)* @@ -156,6 +185,7 @@ pub enum Op { Index, // Expr [ Expr,* ] Call, // Expr ( Expr,* ) + Pub, // pub Expr Loop, // loop Expr If, // if Expr Expr (else Expr)? While, // while Expr Expr (else Expr)? @@ -254,6 +284,20 @@ impl Display for Match { } } +impl Display for Make { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self(expr, make_arms) = self; + f.delimit(fmt!("({expr} {{"), "})").list(make_arms, ", ") + } +} + +impl Display for Mod { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self(ty, expr) = self; + write!(f, "mod {ty} {expr}") + } +} + impl Display for Expr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -262,10 +306,9 @@ impl Display for Expr { Self::Lit(literal) => literal.fmt(f), Self::Let(v) => v.fmt(f), Self::Const(v) => v.fmt(f), - Self::Make(expr, make_arms) => { - f.delimit(fmt!("({expr} {{"), "})").list(make_arms, ", ") - } + Self::Make(v) => v.fmt(f), Self::Match(v) => v.fmt(f), + Self::Mod(v) => v.fmt(f), Self::Fn(v) => v.fmt(f), Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() { @@ -273,6 +316,7 @@ impl Display for Expr { other => f.delimit(fmt!("({op}, "), ")").list(other, ", "), }, Self::Op(Op::Array, exprs) => f.delimit("[", "]").list(exprs, ", "), + Self::Op(Op::ArRep, exprs) => f.delimit("[", "]").list(exprs, "; "), Self::Op(Op::Block, exprs) => f .delimit_indented("{", "}") .list_wrap("\n", exprs, "\n", "\n"), @@ -292,7 +336,7 @@ impl Display for Expr { Self::Op(op @ Op::Macro, exprs) => f.delimit(op, "").list(exprs, " => "), Self::Op(op @ Op::Try, exprs) => f.delimit("(", fmt!("){op}")).list(exprs, ", "), Self::Op(op, exprs) => match exprs.as_slice() { - [one] => write!(f, "{op}({one})"), + [one] => write!(f, "{op}{one}"), many => f.delimit("(", ")").list(many, op), }, } @@ -307,11 +351,13 @@ impl Display for Op { Op::Macro => "macro ".fmt(f), Op::Block => "{}".fmt(f), Op::Array => "[]".fmt(f), + Op::ArRep => "[;]".fmt(f), Op::Group => "()".fmt(f), Op::Tuple => "()".fmt(f), Op::Try => "?".fmt(f), Op::Index => "".fmt(f), Op::Call => "".fmt(f), + Op::Pub => "pub ".fmt(f), Op::Loop => "loop ".fmt(f), Op::If => "if ".fmt(f), Op::While => "while ".fmt(f), @@ -393,7 +439,7 @@ impl Display for Ty { Self::Array(ty, n) => write!(f, "[{ty}; {n}]"), Self::Fn(items) => match items.as_slice() { [] => write!(f, "fn ()"), - [rety, args @ ..] => f + [args @ .., rety] => f .delimit(fmt!("fn ("), fmt!(") -> {rety}")) .list(args, ", "), }, diff --git a/src/ast/macro_matcher.rs b/src/ast/macro_matcher.rs index db1cd1a..49ad50e 100644 --- a/src/ast/macro_matcher.rs +++ b/src/ast/macro_matcher.rs @@ -132,6 +132,33 @@ impl Match for crate::ast::Match { } } +impl Match for crate::ast::Make { + fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { + let (Make(pat, pat_arms), Make(expr, expr_arms)) = (pat, expr); + Match::recurse(sub, pat, expr) && Match::recurse(sub, pat_arms, expr_arms) + } + + fn apply(&mut self, sub: &Subst) { + let Make(expr, make_arms) = self; + expr.apply(sub); + make_arms.apply(sub); + } +} + +impl Match for Mod { + fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { + let (Self(_pat_ty, pat_expr), Self(_expr_ty, expr_expr)) = (pat, expr); + // TODO: unify types for ast matching + // Match::recurse(sub, pat_ty, expr_ty) && + Match::recurse(sub, pat_expr, expr_expr) + } + + fn apply(&mut self, sub: &Subst) { + let Mod(_ty, expr) = self; + expr.apply(sub); + } +} + impl Match for Expr { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { match (pat, expr) { @@ -145,12 +172,12 @@ impl Match for Expr { (Expr::Let(..), _) => false, (Expr::Const(pat), Expr::Const(expr)) => Match::recurse(sub, pat, expr), (Expr::Const(..), _) => false, - (Expr::Make(pat, pat_arms), Expr::Make(expr, expr_arms)) => { - Match::recurse(sub, pat, expr) && Match::recurse(sub, pat_arms, expr_arms) - } + (Expr::Make(pat), Expr::Make(expr)) => Match::recurse(sub, pat, expr), (Expr::Make(..), _) => false, (Expr::Match(pat), Expr::Match(expr)) => Match::recurse(sub, pat, expr), (Expr::Match(..), _) => false, + (Expr::Mod(pat), Expr::Mod(expr)) => Match::recurse(sub, pat, expr), + (Expr::Mod(..), _) => false, (Expr::Fn(pat), Expr::Fn(expr)) => Match::recurse(sub, pat, expr), (Expr::Fn(..), _) => false, (Expr::Op(pat_op, pat_exprs), Expr::Op(expr_op, expr_exprs)) => { @@ -168,22 +195,12 @@ impl Match for Expr { } } Expr::Id(_) | Expr::Lit(_) => {} - Expr::Let(expr) => { - expr.apply(sub); - } - Expr::Const(expr) => { - expr.apply(sub); - } - Expr::Make(expr, make_arms) => { - expr.apply(sub); - make_arms.apply(sub); - } - Expr::Match(expr) => { - expr.apply(sub); - } - Expr::Fn(expr) => { - expr.apply(sub); - } + Expr::Let(expr) => expr.apply(sub), + Expr::Const(expr) => expr.apply(sub), + Expr::Make(expr) => expr.apply(sub), + Expr::Match(expr) => expr.apply(sub), + Expr::Mod(expr) => expr.apply(sub), + Expr::Fn(expr) => expr.apply(sub), Expr::Op(op, exprs) => { op.apply(sub); exprs.apply(sub); diff --git a/src/lexer.rs b/src/lexer.rs index 40a4d85..26ec567 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -232,6 +232,8 @@ impl<'t> Lexer<'t> { "loop" => TKind::Loop, "macro" => TKind::Macro, "match" => TKind::Match, + "mod" => TKind::Module, + "pub" => TKind::Public, "return" => TKind::Return, "then" => TKind::Do, "true" => TKind::True, diff --git a/src/parser.rs b/src/parser.rs index a65d731..3d00bbd 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -318,6 +318,28 @@ impl<'t> Parse<'t> for Ty { tok => Err(ParseError::NotType(tok.kind, tok.span))?, } } + TKind::Fn => { + p.consume().consume_if(TKind::LParen)?; + + let mut tys = p.list(vec![], (), TKind::Comma, TKind::RParen)?; + match p.next_if(TKind::Arrow) { + Ok(_) => { + tys.push(p.parse(())?); + Ty::Fn(tys) + } + _ => Ty::Tuple(tys), + } + } + TKind::LParen => { + let mut tys = p.consume().list(vec![], (), TKind::Comma, TKind::RParen)?; + match p.next_if(TKind::Arrow) { + Ok(_) => { + tys.push(p.parse(())?); + Ty::Fn(tys) + } + _ => Ty::Tuple(tys), + } + } _ => Err(ParseError::NotType(tok.kind, tok.span))?, }; @@ -399,6 +421,7 @@ pub enum Ps { DoubleRef, // && Expr Make, // Expr{ Expr,* } Match, // match Expr { MatchArm,* } + Mod, // mod Ty Expr End, // Produces an empty value. Op(Op), // A normal [ast::Op] } @@ -414,9 +437,11 @@ fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> { (Ps::Lit, Prec::Max) } + TKind::Public => (Ps::Op(Op::Pub), Prec::Body), TKind::Fn => (Ps::Fn, Prec::Body), TKind::Match => (Ps::Match, Prec::Body), TKind::Macro => (Ps::Op(Op::Macro), Prec::Assign), + TKind::Module => (Ps::Mod, Prec::Body), TKind::Let => (Ps::Let, Prec::Tuple), TKind::Const => (Ps::Const, Prec::Body), TKind::Loop => (Ps::Op(Op::Loop), Prec::Body), @@ -427,7 +452,7 @@ fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> { TKind::LCurly => (Ps::Op(Op::Block), Prec::Min), TKind::RCurly => (Ps::End, Prec::Do), - TKind::LBrack => (Ps::Op(Op::Array), Prec::Min), + TKind::LBrack => (Ps::Op(Op::Array), Prec::Tuple), TKind::RBrack => (Ps::End, Prec::Tuple), TKind::LParen => (Ps::Op(Op::Group), Prec::Min), TKind::RParen => (Ps::End, Prec::Tuple), @@ -560,6 +585,13 @@ impl<'t> Parse<'t> for MakeArm { } } +impl<'t> Parse<'t> for Mod { + type Prec = (); + fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult { + Ok(Mod(p.consume().parse(())?, p.parse(Prec::Body.value())?)) + } +} + impl<'t> Parse<'t> for Expr { type Prec = usize; @@ -585,22 +617,13 @@ impl<'t> Parse<'t> for Expr { Ps::Lit => Expr::Lit(p.parse(())?), Ps::Let => Expr::Let(p.parse(())?), Ps::Const => Expr::Const(p.parse(())?), - Ps::Op(Op::Macro) => Expr::Op( - Op::Macro, - vec![p.consume().parse(prec.next())?, { - p.next_if(TKind::FatArrow)?; - p.parse(prec.next())? - }], - ), Ps::Match => Expr::Match(p.parse(())?), + Ps::Mod => Expr::Mod(p.parse(())?), Ps::Op(Op::Block) => Expr::Op( Op::Block, p.consume().opt(MIN, TKind::RCurly)?.into_iter().collect(), ), - Ps::Op(Op::Array) => Expr::Op( - Op::Array, - p.consume().list(vec![], 0, TKind::Comma, TKind::RBrack)?, - ), + Ps::Op(Op::Array) => parse_array(p)?, Ps::Op(Op::Group) => match p.consume().opt(MIN, TKind::RParen)? { Some(value) => Expr::Op(Op::Group, vec![value]), None => Expr::Op(Op::Tuple, vec![]), @@ -629,10 +652,12 @@ impl<'t> Parse<'t> for Expr { Ps::Lambda0 => Expr::Fn(Box::new(Fn(None, Pat::Tuple(vec![]), { p.consume().parse(Prec::Body.next())? }))), - Ps::DoubleRef => Expr::Op( - Op::Refer, - vec![Expr::Op(Op::Refer, vec![p.consume().parse(prec.next())?]).anno(span)], - ), + Ps::DoubleRef => p.consume().parse(prec.next()).map(|Anno(expr, span)| { + Expr::Op( + Op::Refer, + vec![Anno(Expr::Op(Op::Refer, vec![Anno(expr, span)]), span)], + ) + })?, Ps::Op(op) => Expr::Op(op, vec![p.consume().parse(prec.next())?]), _ => unimplemented!("prefix {op:?}"), @@ -650,10 +675,12 @@ impl<'t> Parse<'t> for Expr { head = match op { // Make (structor expressions) are context-sensitive Ps::Make => match &head { - Expr::Op(Op::Path, _) | Expr::Id(_) | Expr::MetId(_) => Expr::Make( - head.anno(span).into(), - p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?, - ), + Expr::Op(Op::Path, _) | Expr::Id(_) | Expr::MetId(_) => { + Expr::Make(Box::new(Make( + head.anno(span).into(), + p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?, + ))) + } _ => break, }, Ps::Op(Op::Index) => Expr::Op( @@ -686,6 +713,25 @@ impl<'t> Parse<'t> for Expr { } } +/// Parses an array with 0 or more elements, or an array-repetition +fn parse_array<'t>(p: &mut Parser<'t>) -> PResult { + if p.consume().peek()?.kind == TKind::RBrack { + p.consume(); + return Ok(Expr::Op(Op::Array, vec![])); + } + + let prec = Prec::Tuple; + let item = p.parse(prec.value())?; + let repeat = p.opt_if(prec.next(), TKind::Semi)?; + p.next_if(TKind::RBrack)?; + + Ok(match (repeat, item) { + (Some(repeat), item) => Expr::Op(Op::ArRep, vec![item, repeat]), + (None, Anno(Expr::Op(Op::Tuple, items), _)) => Expr::Op(Op::Array, items), + (None, item) => Expr::Op(Op::Array, vec![item]), + }) +} + impl<'t, P: Parse<'t> + Annotation> Parse<'t> for Anno

{ type Prec = P::Prec; fn parse(p: &mut Parser<'t>, level: P::Prec) -> PResult diff --git a/src/token.rs b/src/token.rs index b3511e4..1ca67f2 100644 --- a/src/token.rs +++ b/src/token.rs @@ -24,6 +24,8 @@ pub enum TKind { Loop, Macro, Match, + Module, + Public, Return, True, While,