Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple primitive operations #4

Merged
merged 5 commits into from
Sep 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 121 additions & 2 deletions src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,42 @@ struct Closure {
env: Enviroment,
}

#[derive(Debug)]
enum Continuation {
teofr marked this conversation as resolved.
Show resolved Hide resolved
Ite(Closure, Closure),
Plus0(Enviroment, Closure),
teofr marked this conversation as resolved.
Show resolved Hide resolved
Plus1(Enviroment, f64),
teofr marked this conversation as resolved.
Show resolved Hide resolved
}

#[derive(Debug)]
enum Marker {
Arg(Closure),
Thunk(Weak<RefCell<Closure>>),
Cont(Continuation),
}

impl Marker {
pub fn is_arg(&self) -> bool {
match *self {
Marker::Arg(_) => true,
Marker::Thunk(_) => false,
Marker::Cont(_) => false,
}
}

pub fn is_thunk(&self) -> bool {
match *self {
Marker::Arg(_) => false,
Marker::Thunk(_) => true,
Marker::Cont(_) => false,
}
}

pub fn is_cont(&self) -> bool {
match *self {
Marker::Arg(_) => false,
Marker::Thunk(_) => false,
Marker::Cont(_) => true,
}
}
}
Expand Down Expand Up @@ -75,6 +93,10 @@ impl Stack {
Stack::count(self, Marker::is_thunk)
}

pub fn count_conts(&self) -> usize {
Stack::count(self, Marker::is_cont)
}

pub fn push_arg(&mut self, arg: Closure) {
self.0.push(Marker::Arg(arg))
}
Expand All @@ -83,6 +105,10 @@ impl Stack {
self.0.push(Marker::Thunk(thunk))
}

pub fn push_cont(&mut self, cont: Continuation) {
self.0.push(Marker::Cont(cont))
}

pub fn pop_arg(&mut self) -> Option<Closure> {
match self.0.pop() {
Some(Marker::Arg(arg)) => Some(arg),
Expand All @@ -104,6 +130,17 @@ impl Stack {
_ => None,
}
}

pub fn pop_cont(&mut self) -> Option<Continuation> {
match self.0.pop() {
Some(Marker::Cont(cont)) => Some(cont),
Some(m) => {
self.0.push(m);
None
}
_ => None,
}
}
}

fn is_value(_term: &Term) -> bool {
Expand Down Expand Up @@ -145,7 +182,7 @@ pub fn eval(t0: Term) -> Term {
// Let
Closure {
body: Term::Let(x, s, t),
env: mut env,
mut env,
} => {
let thunk = Rc::new(RefCell::new(Closure {
body: *s,
Expand All @@ -154,6 +191,37 @@ pub fn eval(t0: Term) -> Term {
env.insert(x, Rc::clone(&thunk));
clos = Closure { body: *t, env: env };
}
// Ite
Closure {
body: Term::Ite(b, t, e),
env,
} => {
stack.push_cont(Continuation::Ite(
Closure {
body: *t,
env: env.clone(),
},
Closure {
body: *e,
env: env.clone(),
},
));
clos = Closure { body: *b, env };
}
// Plus
Closure {
body: Term::Plus(t1, t2),
env,
} => {
stack.push_cont(Continuation::Plus0(
env.clone(),
Closure {
body: *t2,
env: env.clone(),
},
));
clos = Closure { body: *t1, env };
}
// Update
_ if 0 < stack.count_thunks() => {
while let Some(thunk) = stack.pop_thunk() {
Expand All @@ -162,10 +230,16 @@ pub fn eval(t0: Term) -> Term {
}
}
}
// Continuate
_ if 0 < stack.count_conts() => continuate(
stack.pop_cont().expect("Condition already checked"),
&mut clos,
&mut stack,
),
// Call
Closure {
body: Term::Fun(mut xs, t),
env: mut env,
mut env,
} => {
if xs.len() <= stack.count_args() {
let args = &mut stack;
Expand All @@ -192,3 +266,48 @@ pub fn eval(t0: Term) -> Term {

clos.body
}

fn continuate(cont: Continuation, clos: &mut Closure, stack: &mut Stack) {
match cont {
// If Then Else
Continuation::Ite(t, e) => {
if let Closure {
body: Term::Bool(b),
env: _,
} = *clos
{
*clos = if b { t } else { e };
} else {
panic!("Expected Bool, got {:?}", clos);
}
}
// Plus unapplied
Continuation::Plus0(plus_env, t) => {
if let Closure {
body: Term::Num(n),
env: _,
} = *clos
{
stack.push_cont(Continuation::Plus1(plus_env, n));
*clos = t;
} else {
panic!("Expected Num, got {:?}", clos);
}
}
// Plus partially applied
Continuation::Plus1(plus_env, n) => {
if let Closure {
body: Term::Num(n2),
env: _,
} = *clos
{
*clos = Closure {
body: Term::Num(n + n2),
env: plus_env,
};
} else {
panic!("Expected Num, got {:?}", clos);
}
}
}
}
4 changes: 4 additions & 0 deletions src/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ pub Term = {
Term::Fun(ps, Box::new(t)),
"let" <id:Ident> "=" <t1:Term> "in" <t2:Term> =>
Term::Let(id, Box::new(t1), Box::new(t2)),
"if" <b:Term> "then" <t:Term> "else" <e:Term> =>
Term::Ite(Box::new(b), Box::new(t), Box::new(e)),
// TODO make infix
"+" <t1:Atom> <t2:Atom> => Term::Plus(Box::new(t1), Box::new(t2)),
teofr marked this conversation as resolved.
Show resolved Hide resolved
Applicative,
};

Expand Down
25 changes: 25 additions & 0 deletions src/parser/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,38 @@ fn numbers() {
assert_eq!(parser.parse("((22))").unwrap(), Num(22.0));
}

#[test]
fn plus() {
let parser = super::grammar::TermParser::new();
assert_eq!(
parser.parse("+ 3 4").unwrap(),
Plus(Box::new(Num(3.0)), Box::new(Num(4.)))
);
assert_eq!(
parser.parse("+ (+ true false) 4").unwrap(),
Plus(
Box::new(Plus(Box::new(Bool(true)), Box::new(Bool(false)))),
Box::new(Num(4.))
)
);
}

#[test]
fn booleans() {
let parser = super::grammar::TermParser::new();
assert_eq!(parser.parse("true").unwrap(), Bool(true));
assert_eq!(parser.parse("false").unwrap(), Bool(false));
}

#[test]
fn ite() {
let parser = super::grammar::TermParser::new();
assert_eq!(
parser.parse("if true then 3 else 4").unwrap(),
Ite(Box::new(Bool(true)), Box::new(Num(3.0)), Box::new(Num(4.0)))
);
}

#[test]
fn applications() {
let parser = super::grammar::TermParser::new();
Expand Down
2 changes: 2 additions & 0 deletions src/term.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ pub enum Term {
Fun(Vec<Ident>, Box<Term>),
Let(Ident, Box<Term>, Box<Term>),
App(Box<Term>, Box<Term>),
Ite(Box<Term>, Box<Term>, Box<Term>),
Plus(Box<Term>, Box<Term>),
}
2 changes: 2 additions & 0 deletions src/tests/primBool.ncl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
let g = fun x => if x then 0 else false in
g ((fun x => true) 0 )
2 changes: 2 additions & 0 deletions src/tests/primBoolWrong.ncl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
let g = fun x => if x then 0 else false in
g ((fun x => 32) 0 )
1 change: 1 addition & 0 deletions src/tests/primNum.ncl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
+ 34 (if true then 2 else 222)