diff --git a/reuse-frontend/src/concrete.rs b/reuse-frontend/src/concrete.rs index 9f764d1..4a9160b 100644 --- a/reuse-frontend/src/concrete.rs +++ b/reuse-frontend/src/concrete.rs @@ -1,9 +1,14 @@ use crate::name::Ident; -use crate::syntax::{Decl, Param, Syntax}; +use crate::syntax::{Ctor, CtorParams, Decl, Param, Syntax}; #[allow(dead_code)] pub type ParamExpr<'src> = Param<'src, Expr<'src>>; +#[allow(dead_code)] +pub type CtorExpr<'src> = Ctor<'src, Expr<'src>>; +#[allow(dead_code)] +pub type CtorParamsExpr<'src> = CtorParams<'src, Expr<'src>>; + #[allow(dead_code)] pub struct File<'src> { pub decls: Box<[Decl<'src, Expr<'src>>]>, diff --git a/reuse-frontend/src/name.rs b/reuse-frontend/src/name.rs index 9af58f9..9797095 100644 --- a/reuse-frontend/src/name.rs +++ b/reuse-frontend/src/name.rs @@ -11,6 +11,10 @@ impl<'src> Ident<'src> { pub fn new(id: ID, raw: &'src str) -> Self { Self { id, raw } } + + pub fn unbound() -> Self { + Self { id: 0, raw: "_" } + } } impl<'src> Display for Ident<'src> { diff --git a/reuse-frontend/src/surface/mod.rs b/reuse-frontend/src/surface/mod.rs index 32a81a1..d2c5b3d 100644 --- a/reuse-frontend/src/surface/mod.rs +++ b/reuse-frontend/src/surface/mod.rs @@ -1,13 +1,12 @@ use chumsky::error::Rich; use chumsky::extra::Err; use chumsky::prelude::just; -use chumsky::text::ascii::keyword; use chumsky::text::{ident, inline_whitespace, newline}; use chumsky::{IterParser, Parser}; -use crate::concrete::{Expr, File, ParamExpr}; +use crate::concrete::{CtorExpr, CtorParamsExpr, Expr, File, ParamExpr}; use crate::name::{IDs, Ident}; -use crate::syntax::{Decl, Def, FnDef, Param}; +use crate::syntax::{DataDef, Decl, Def, FnDef, Param}; #[cfg(test)] mod tests; @@ -43,35 +42,17 @@ impl Surface { } fn decl<'src>(&mut self) -> out!(Decl<'src, Expr<'src>>) { - self.fn_decl() + self.fn_decl().or(self.data_decl()) } fn fn_decl<'src>(&mut self) -> out!(Decl<'src, Expr<'src>>) { - keyword("def") + just("def") .padded() .ignore_then(self.ident()) .padded() - .then( - self.ident() - .padded() - .map(|name| Param { - name, - typ: Box::new(Expr::Type), - }) - .separated_by(just(',')) - .at_least(1) - .collect::>() - .delimited_by(just('['), just(']')) - .or_not(), - ) + .then(self.typ_params().or_not()) .padded() - .then( - self.param() - .padded() - .separated_by(just(',')) - .collect::>() - .delimited_by(just('('), just(')')), - ) + .then(self.val_params()) .padded() .then( just("->") @@ -87,14 +68,89 @@ impl Surface { .then_ignore(newline()) .map(|((((name, typ_params), val_params), ret), body)| Decl { name, - typ_params: typ_params.unwrap_or_default().into_boxed_slice(), - val_params: val_params.into_boxed_slice(), - eff: Box::new(Expr::Pure), // TODO: parse effects - ret: ret.unwrap_or_else(|| Box::new(Expr::NoneType)), - def: Def::Fn(FnDef { body }), + def: Def::Fn(FnDef { + typ_params: typ_params.unwrap_or_default(), + val_params, + eff: Box::new(Expr::Pure), // TODO: parse effects + ret: ret.unwrap_or_else(|| Box::new(Expr::NoneType)), + body, + }), }) } + fn data_decl<'src>(&mut self) -> out!(Decl<'src, Expr<'src>>) { + just("data") + .padded() + .ignore_then(self.ident()) + .padded() + .then(self.typ_params().or_not()) + .padded() + .then_ignore(just(':')) + .then_ignore(inline_whitespace()) + .then_ignore(newline()) + .then(self.ctors()) + .map(|((name, typ_params), ctors)| Decl { + name, + def: Def::Data(DataDef { + typ_params: typ_params.unwrap_or_default(), + ctors, + }), + }) + } + + fn ctors<'src>(&mut self) -> out!(Box<[CtorExpr<'src>]>) { + self.ctor() + .padded_by(inline_whitespace()) + .repeated() + .at_least(1) + .collect::>() + .map(Vec::into_boxed_slice) + } + + fn ctor<'src>(&mut self) -> out!(CtorExpr<'src>) { + self.ident() + .then_ignore(inline_whitespace()) + .then( + self.ctor_unnamed_params() + .or(self.ctor_named_params()) + .or_not() + .map(Option::unwrap_or_default), + ) + .then_ignore(inline_whitespace()) + .then_ignore(newline()) + .map(|(name, params)| CtorExpr { name, params }) + } + + fn ctor_unnamed_params<'src>(&mut self) -> out!(CtorParamsExpr<'src>) { + just('(') + .ignore_then( + self.type_expr() + .padded() + .separated_by(just(',')) + .allow_trailing() + .at_least(1) + .collect::>() + .map(Vec::into_boxed_slice) + .map(CtorParamsExpr::Unnamed), + ) + .then_ignore(just(')')) + } + + fn ctor_named_params<'src>(&mut self) -> out!(CtorParamsExpr<'src>) { + just('(') + .ignore_then( + self.param() + .padded() + .separated_by(just(',')) + .allow_trailing() + .at_least(1) + .collect::>() + .map(Vec::into_boxed_slice) + .map(CtorParamsExpr::Named), + ) + .then_ignore(just(')')) + } + fn expr<'src>(&mut self) -> out!(Box>) { primitive!("None", None) .or(primitive!("False", True)) @@ -118,6 +174,39 @@ impl Surface { .map(|(name, typ)| Param { name, typ }) } + fn val_params<'src>(&mut self) -> out!(Box<[ParamExpr<'src>]>) { + just('(') + .ignore_then( + self.param() + .padded() + .separated_by(just(',')) + .allow_trailing() + .collect::>() + .map(Vec::into_boxed_slice) + .or_not() + .map(Option::unwrap_or_default), + ) + .then_ignore(just(')')) + } + + fn typ_params<'src>(&mut self) -> out!(Box<[ParamExpr<'src>]>) { + just('[') + .ignore_then( + self.ident() + .padded() + .map(|name| Param { + name, + typ: Box::new(Expr::Type), + }) + .separated_by(just(',')) + .allow_trailing() + .at_least(1) + .collect::>() + .map(Vec::into_boxed_slice), + ) + .then_ignore(just(']')) + } + fn ident<'src>(&mut self) -> out!(Ident<'src>) { let id = self.ids.fresh(); ident().map(move |s| Ident::new(id, s)) diff --git a/reuse-frontend/src/surface/tests.rs b/reuse-frontend/src/surface/tests.rs index 581824e..a0f67d1 100644 --- a/reuse-frontend/src/surface/tests.rs +++ b/reuse-frontend/src/surface/tests.rs @@ -10,9 +10,14 @@ fn it_parses_file() { def f0 () -> None : None def f1 () -> None : None -def f2 [T] (s: str) -> None : +def f2 [T, U,] (s: str) -> None : None +data + Foo [T]: + A +B(str) + "; Surface::default() diff --git a/reuse-frontend/src/syntax.rs b/reuse-frontend/src/syntax.rs index 6b9ef08..ddb6bd1 100644 --- a/reuse-frontend/src/syntax.rs +++ b/reuse-frontend/src/syntax.rs @@ -11,31 +11,45 @@ pub struct Param<'src, T: Syntax> { #[allow(dead_code)] pub struct Decl<'src, T: Syntax> { pub name: Ident<'src>, - pub typ_params: Box<[Param<'src, T>]>, - pub val_params: Box<[Param<'src, T>]>, - pub eff: Box, - pub ret: Box, pub def: Def<'src, T>, } #[allow(dead_code)] pub enum Def<'src, T: Syntax> { - Fn(FnDef), + Fn(FnDef<'src, T>), Data(DataDef<'src, T>), } #[allow(dead_code)] -pub struct FnDef { +pub struct FnDef<'src, T: Syntax> { + pub typ_params: Box<[Param<'src, T>]>, + pub val_params: Box<[Param<'src, T>]>, + pub eff: Box, + pub ret: Box, pub body: Box, } #[allow(dead_code)] pub struct DataDef<'src, T: Syntax> { - ctors: Box<[Ctor<'src, T>]>, + pub typ_params: Box<[Param<'src, T>]>, + pub ctors: Box<[Ctor<'src, T>]>, } #[allow(dead_code)] pub struct Ctor<'src, T: Syntax> { - name: Ident<'src>, - val_params: Box<[Param<'src, T>]>, + pub name: Ident<'src>, + pub params: CtorParams<'src, T>, +} + +#[allow(dead_code)] +pub enum CtorParams<'src, T: Syntax> { + None, + Unnamed(Box<[Box]>), + Named(Box<[Param<'src, T>]>), +} + +impl<'src, T: Syntax> Default for CtorParams<'src, T> { + fn default() -> Self { + Self::None + } }