Add function expr parsing

* Introduce new `fn` keyword
* Function example is added to examples/expr.not

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-09-18 16:39:06 -07:00
parent 337be88849
commit f0032afe12
7 changed files with 95 additions and 9 deletions

View File

@@ -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)

View File

@@ -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); }
}

View File

@@ -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) => {

View File

@@ -104,12 +104,13 @@ impl<V: Visit<Out=()>> DefaultAccept<V> for LhsExpr {
//
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expr {
Atom(Atom),
Bin(Box<BinExpr>),
Un(Box<UnExpr>),
Access(Box<AccessExpr>),
Call(Box<CallExpr>),
Index(Box<IndexExpr>),
Access(Box<AccessExpr>),
Fun(Box<FunExpr>),
Atom(Atom),
}
//
@@ -127,12 +128,13 @@ impl<V: Visit> Accept<V> for Expr {
impl<V: Visit> DefaultAccept<V> 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<IndexExpr> for Expr {
}
}
impl From<FunExpr> 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<V: Visit> DefaultAccept<V> for AccessExpr {
}
}
//
// struct FunExpr
//
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunExpr {
pub params: Vec<String>,
pub body: Body,
}
//
// impl FunExpr
//
impl FunExpr {
pub fn new_expr(params: Vec<String>, body: Body) -> Expr {
Self { params, body, }.into()
}
}
//
// impl Accept for FunExpr
//
impl<V: Visit> Accept<V> for FunExpr {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_fun_expr(self)
}
}
//
// impl DefaultAccept for FunExpr
//
impl<V: Visit> DefaultAccept<V> 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<V: Visit> Accept<V> for Atom {
fn accept(&self, visitor: &mut V) -> V::Out {
visitor.visit_atom(self)
}
}
//
// impl DefaultAccept for Atom
//
impl<V: Visit<Out=()>> DefaultAccept<V> for Atom {
fn default_accept(&self, _visitor: &mut V) -> V::Out { }
}

View File

@@ -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 @@
\) ")"
\[ "["
\] "]"
\{ "{"
\} "}"
\. "."
, ","

View File

@@ -92,10 +92,25 @@ IndexExpr -> Result<Expr>:
;
AccessExpr -> Result<Expr>:
AtomExpr { $1 }
FunExpr { $1 }
| CallIndexExpr '.' Ident { Ok(AccessExpr::new_expr($1?, $3?)) }
;
FunExpr -> Result<Expr>:
AtomExpr { $1 }
| 'fn' '(' FunParams ')' '{' Body '}' { Ok(FunExpr::new_expr($3?, $6?)) }
;
FunParams -> Result<Vec<String>>:
FunParamsTail { $1 }
| { Ok(Vec::new()) }
;
FunParamsTail -> Result<Vec<String>>:
FunParamsTail ',' Ident { flatten($1, $3) }
| Ident { Ok(vec![$1?]) }
;
AtomExpr -> Result<Expr>:
Atom { $1.map(Expr::Atom) }
| '(' Expr ')' { $2 }

View File

@@ -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); }
*/