diff --git a/examples/expr.not b/examples/expr.not index 089673e..84621e0 100644 --- a/examples/expr.not +++ b/examples/expr.not @@ -1,7 +1,9 @@ -# pow = (n, p) { -# p == 0 -# ?? 1 -# !! n * pow(n, p - 1) +# pow = fn (n, p) { +# if p == 0 { +# 1 +# } else { +# n * pow(n, p - 1) +# } # } kilo = pow(2, 10) diff --git a/src/compile/locals.rs b/src/compile/locals.rs index d7ef3a9..751f5d8 100644 --- a/src/compile/locals.rs +++ b/src/compile/locals.rs @@ -48,5 +48,8 @@ impl Visit for CollectLocals<'_> { fn visit_call_expr(&mut self, expr: &CallExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); } fn visit_index_expr(&mut self, expr: &IndexExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); } fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); } + fn visit_fun_expr(&mut self, _expr: &FunExpr) -> Self::Out { + // Do not collect names for function expressions, since they have their own scope. + } fn visit_atom(&mut self, atom: &Atom) -> Self::Out { DefaultAccept::default_accept(atom, self); } } diff --git a/src/compile/thunk.rs b/src/compile/thunk.rs index f76d6d2..a0df7cb 100644 --- a/src/compile/thunk.rs +++ b/src/compile/thunk.rs @@ -345,6 +345,11 @@ impl Visit for CompileBody<'_> { Ok(thunk) } + fn visit_fun_expr(&mut self, _expr: &FunExpr) -> Self::Out { + // TODO : fun exprs should be compiled as constants and put into the constant pool + todo!() + } + fn visit_atom(&mut self, atom: &Atom) -> Self::Out { let thunk = match atom { Atom::Ident(ident) => { diff --git a/src/syn/ast.rs b/src/syn/ast.rs index 04a1b06..49a1f96 100644 --- a/src/syn/ast.rs +++ b/src/syn/ast.rs @@ -104,12 +104,13 @@ impl> DefaultAccept for LhsExpr { // #[derive(Debug, Clone, PartialEq, Eq)] pub enum Expr { - Atom(Atom), Bin(Box), Un(Box), - Access(Box), Call(Box), Index(Box), + Access(Box), + Fun(Box), + Atom(Atom), } // @@ -127,12 +128,13 @@ impl Accept for Expr { impl DefaultAccept for Expr { fn default_accept(&self, visitor: &mut V) -> V::Out { match self { - Expr::Atom(a) => a.accept(visitor), Expr::Bin(b) => b.accept(visitor), Expr::Un(u) => u.accept(visitor), - Expr::Access(a) => a.accept(visitor), Expr::Call(c) => c.accept(visitor), Expr::Index(i) => i.accept(visitor), + Expr::Access(a) => a.accept(visitor), + Expr::Fun(f) => f.accept(visitor), + Expr::Atom(a) => a.accept(visitor), } } } @@ -176,6 +178,12 @@ impl From for Expr { } } +impl From for Expr { + fn from(other: FunExpr) -> Self { + Expr::Fun(other.into()) + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum BinOp { Plus, @@ -368,6 +376,45 @@ impl DefaultAccept for AccessExpr { } } +// +// struct FunExpr +// +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FunExpr { + pub params: Vec, + pub body: Body, +} + +// +// impl FunExpr +// +impl FunExpr { + pub fn new_expr(params: Vec, body: Body) -> Expr { + Self { params, body, }.into() + } +} + +// +// impl Accept for FunExpr +// +impl Accept for FunExpr { + fn accept(&self, visitor: &mut V) -> V::Out { + visitor.visit_fun_expr(self) + } +} + +// +// impl DefaultAccept for FunExpr +// +impl DefaultAccept for FunExpr { + fn default_accept(&self, visitor: &mut V) -> V::Out { + visitor.visit_body(&self.body) + } +} + +// +// enum Atom +// #[derive(Debug, Clone, PartialEq, Eq)] pub enum Atom { Ident(String), @@ -376,12 +423,20 @@ pub enum Atom { String(String), } +// +// impl Accept for Atom +// + impl Accept for Atom { fn accept(&self, visitor: &mut V) -> V::Out { visitor.visit_atom(self) } } +// +// impl DefaultAccept for Atom +// + impl> DefaultAccept for Atom { fn default_accept(&self, _visitor: &mut V) -> V::Out { } } diff --git a/src/syn/lexer.l b/src/syn/lexer.l index 28365cb..5438eaa 100644 --- a/src/syn/lexer.l +++ b/src/syn/lexer.l @@ -1,4 +1,6 @@ %% +fn "fn" + [\r\n;]+ "EOL" [a-zA-Z_][a-zA-Z0-9_]* "IDENT" :[a-zA-Z_][a-zA-Z0-9_]* "SYM" @@ -22,6 +24,8 @@ \) ")" \[ "[" \] "]" +\{ "{" +\} "}" \. "." , "," diff --git a/src/syn/parser.y b/src/syn/parser.y index 6e12e87..d4cd754 100644 --- a/src/syn/parser.y +++ b/src/syn/parser.y @@ -92,10 +92,25 @@ IndexExpr -> Result: ; AccessExpr -> Result: - AtomExpr { $1 } + FunExpr { $1 } | CallIndexExpr '.' Ident { Ok(AccessExpr::new_expr($1?, $3?)) } ; +FunExpr -> Result: + AtomExpr { $1 } + | 'fn' '(' FunParams ')' '{' Body '}' { Ok(FunExpr::new_expr($3?, $6?)) } + ; + +FunParams -> Result>: + FunParamsTail { $1 } + | { Ok(Vec::new()) } + ; + +FunParamsTail -> Result>: + FunParamsTail ',' Ident { flatten($1, $3) } + | Ident { Ok(vec![$1?]) } + ; + AtomExpr -> Result: Atom { $1.map(Expr::Atom) } | '(' Expr ')' { $2 } diff --git a/src/syn/visit.rs b/src/syn/visit.rs index 6dade5d..e60822b 100644 --- a/src/syn/visit.rs +++ b/src/syn/visit.rs @@ -21,6 +21,7 @@ pub trait Visit { fn visit_call_expr(&mut self, expr: &CallExpr) -> Self::Out; fn visit_index_expr(&mut self, expr: &IndexExpr) -> Self::Out; fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out; + fn visit_fun_expr(&mut self, expr: &FunExpr) -> Self::Out; fn visit_atom(&mut self, atom: &Atom) -> Self::Out; } @@ -37,6 +38,7 @@ copy/paste of default_accepts fn visit_call_expr(&mut self, expr: &CallExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); } fn visit_index_expr(&mut self, expr: &IndexExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); } fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); } + fn visit_fun_expr(&mut self, expr: &FunExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); } fn visit_atom(&mut self, atom: &Atom) -> Self::Out { DefaultAccept(atom, self); } */