diff --git a/cl-ast/src/ast_impl.rs b/cl-ast/src/ast_impl.rs
index ca07eb8..2712f8e 100644
--- a/cl-ast/src/ast_impl.rs
+++ b/cl-ast/src/ast_impl.rs
@@ -166,9 +166,30 @@ mod display {
}
impl Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let Self { name, args, body, rety } = self;
+ let Self { name, sign: sign @ TyFn { args, rety }, bind, body } = self;
+ let types = match **args {
+ TyKind::Tuple(TyTuple { ref types }) => types.as_slice(),
+ TyKind::Empty => Default::default(),
+ _ => {
+ write!(f, "Invalid function signature: {sign}")?;
+ Default::default()
+ }
+ };
+
+ debug_assert_eq!(bind.len(), types.len());
write!(f, "fn {name} ")?;
- delimit(separate(args, ", "), INLINE_PARENS)(f)?;
+ delimit(
+ |f| {
+ for (idx, (arg, ty)) in bind.iter().zip(types.iter()).enumerate() {
+ if idx != 0 {
+ f.write_str(", ")?;
+ }
+ write!(f, "{arg}: {ty}")?;
+ }
+ Ok(())
+ },
+ INLINE_PARENS,
+ )(f)?;
if let Some(rety) = rety {
write!(f, " -> {rety}")?;
}
@@ -180,8 +201,8 @@ mod display {
}
impl Display for Param {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let Self { mutability, name, ty } = self;
- write!(f, "{mutability}{name}: {ty}")
+ let Self { mutability, name } = self;
+ write!(f, "{mutability}{name}")
}
}
impl Display for Struct {
diff --git a/cl-ast/src/lib.rs b/cl-ast/src/lib.rs
index 3e3c671..22e24e9 100644
--- a/cl-ast/src/lib.rs
+++ b/cl-ast/src/lib.rs
@@ -135,9 +135,9 @@ pub enum ModuleKind {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Function {
pub name: Identifier,
- pub args: Vec,
+ pub sign: TyFn,
+ pub bind: Vec,
pub body: Option,
- pub rety: Option>,
}
/// A single parameter for a [Function]
@@ -145,7 +145,6 @@ pub struct Function {
pub struct Param {
pub mutability: Mutability,
pub name: Identifier,
- pub ty: Box,
}
/// A user-defined product type
diff --git a/cl-interpret/src/lib.rs b/cl-interpret/src/lib.rs
index 70d6901..a8f0f85 100644
--- a/cl-interpret/src/lib.rs
+++ b/cl-interpret/src/lib.rs
@@ -324,7 +324,7 @@ pub mod function {
name
}
fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult {
- let FnDecl { name: Identifier(name), args: declargs, body, rety: _ } = &*self.decl;
+ let FnDecl { name: Identifier(name), bind: declargs, body, sign: _ } = &*self.decl;
// Check arg mapping
if args.len() != declargs.len() {
return Err(Error::ArgNumber { want: declargs.len(), got: args.len() });
@@ -334,7 +334,7 @@ pub mod function {
};
// TODO: completely refactor data storage
let mut frame = env.frame("fn args");
- for (Param { mutability: _, name: Identifier(name), ty: _ }, value) in
+ for (Param { mutability: _, name: Identifier(name) }, value) in
declargs.iter().zip(args)
{
frame.insert(name, Some(value.clone()));
diff --git a/cl-parser/src/parser.rs b/cl-parser/src/parser.rs
index c69a0d9..add07d8 100644
--- a/cl-parser/src/parser.rs
+++ b/cl-parser/src/parser.rs
@@ -394,20 +394,19 @@ impl<'t> Parser<'t> {
const PARSING: Parsing = Parsing::Function;
self.match_type(TokenKind::Fn, PARSING)?;
+ let name = self.identifier()?;
+ let (bind, types) = delim(Self::parse_params, PARENS, PARSING)(self)?;
+ let sign = TyFn {
+ args: Box::new(match types.len() {
+ 0 => TyKind::Empty,
+ _ => TyKind::Tuple(TyTuple { types }),
+ }),
+ rety: self.parse_rety()?.map(Box::new),
+ };
Ok(Function {
- name: self.identifier()?,
- args: self.parse_params()?,
- rety: match self.peek_kind(PARSING)? {
- TokenKind::Punct(Punct::LCurly) | TokenKind::Punct(Punct::Semi) => None,
- TokenKind::Punct(Punct::Arrow) => {
- self.consume_peeked();
- Some(self.ty()?.into())
- }
- got => Err(self.error(
- ExpectedToken { want: TokenKind::Punct(Punct::Arrow), got },
- PARSING,
- ))?,
- },
+ name,
+ sign,
+ bind,
body: match self.peek_kind(PARSING)? {
TokenKind::Punct(Punct::LCurly) => Some(self.block()?),
TokenKind::Punct(Punct::Semi) => {
@@ -420,25 +419,29 @@ impl<'t> Parser<'t> {
}
/// Parses the [parameters](Param) associated with a Function
- pub fn parse_params(&mut self) -> PResult> {
+ pub fn parse_params(&mut self) -> PResult<(Vec, Vec)> {
const PARSING: Parsing = Parsing::Function;
- delim(
- sep(Self::parse_param, Punct::Comma, PARENS.1, PARSING),
- PARENS,
- PARSING,
- )(self)
+ let (mut params, mut types) = (vec![], vec![]);
+ while Ok(TokenKind::Punct(Punct::RParen)) != self.peek_kind(PARSING) {
+ let (param, ty) = self.parse_param()?;
+ params.push(param);
+ types.push(ty);
+ if self.match_op(Punct::Comma, PARSING).is_err() {
+ break;
+ }
+ }
+ Ok((params, types))
}
/// Parses a single function [parameter](Param)
- pub fn parse_param(&mut self) -> PResult {
- Ok(Param {
- mutability: self.mutability()?,
- name: self.identifier()?,
- ty: {
+ pub fn parse_param(&mut self) -> PResult<(Param, TyKind)> {
+ Ok((
+ Param { mutability: self.mutability()?, name: self.identifier()? },
+ {
self.match_op(Punct::Colon, Parsing::Param)?;
- self.ty()?.into()
+ self.tykind()?
},
- })
+ ))
}
/// Parses a [`struct` definition](Struct)
@@ -680,13 +683,14 @@ impl<'t> Parser<'t> {
t if t.is_empty() => TyKind::Empty,
types => TyKind::Tuple(TyTuple { types }),
}),
- rety: match self.peek_kind(PARSING) {
- Ok(TokenKind::Punct(Punct::Arrow)) => {
- self.consume_peeked();
- Some(self.ty()?.into())
- }
- _ => None,
- },
+ rety: self.parse_rety()?.map(Into::into),
+ })
+ }
+
+ pub fn parse_rety(&mut self) -> PResult