commit
f138d8c66b
|
@ -22,3 +22,8 @@ lalrpop = "0.19.6"
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "2.0.2"
|
assert_cmd = "2.0.2"
|
||||||
insta = { version = "1.9.0", features = ["glob"] }
|
insta = { version = "1.9.0", features = ["glob"] }
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
# https://github.com/rust-lang/rust/issues/92163
|
||||||
|
# https://github.com/rust-lang/rust/issues/92315
|
||||||
|
incremental=false
|
|
@ -0,0 +1,3 @@
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
Many of the tests are adapted from [craftinginterpriters](https://github.com/munificent/craftinginterpreters/tree/master/test).
|
17
src/ast.rs
17
src/ast.rs
|
@ -1,20 +1,25 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, debug2::Debug, PartialEq)]
|
#[derive(Debug /*/*, debug2::Debug*/*/, PartialEq)]
|
||||||
|
|
||||||
crate enum Tree {
|
crate enum Tree {
|
||||||
Leaf(Literal),
|
Leaf(Literal),
|
||||||
Define(String, Box<Tree>),
|
Define(String, Box<Tree>),
|
||||||
|
Set(String, Box<Tree>),
|
||||||
If(Box<[Tree; 3]>),
|
If(Box<[Tree; 3]>),
|
||||||
Lambda(Lambda),
|
// Its easier to box the lambdas in the parser than the vm, as
|
||||||
|
// here we see all of them exactly once
|
||||||
|
Func(Rc<Func>),
|
||||||
Branch(Vec<Tree>),
|
Branch(Vec<Tree>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, debug2::Debug, PartialEq, Clone)]
|
#[derive(Debug /*/*, debug2::Debug*/*/, PartialEq)]
|
||||||
|
crate struct Func {
|
||||||
|
crate args: Vec<String>,
|
||||||
|
crate body: Vec<Tree>,
|
||||||
|
}
|
||||||
|
|
||||||
crate struct Lambda(crate Rc<[String]>, crate Rc<[Tree]>);
|
#[derive(Debug /*/*, debug2::Debug*/*/, PartialEq)]
|
||||||
|
|
||||||
#[derive(Debug, debug2::Debug, PartialEq)]
|
|
||||||
|
|
||||||
crate enum Literal {
|
crate enum Literal {
|
||||||
Sym(String),
|
Sym(String),
|
||||||
|
|
116
src/eval.rs
116
src/eval.rs
|
@ -1,58 +1,82 @@
|
||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::{ast, prims};
|
use crate::{ast, prims};
|
||||||
|
|
||||||
pub(crate) fn eval(t: &ast::Tree, env: &mut Env) -> Result<Value, RTError> {
|
#[derive(/*debug2::Debug,*/ Debug, Clone)]
|
||||||
|
crate struct Lambda {
|
||||||
|
crate func: Rc<ast::Func>,
|
||||||
|
crate captures: Rc<RefCell<Env>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn eval(t: &ast::Tree, env: Rc<RefCell<Env>>) -> Result<Value, RTError> {
|
||||||
Ok(match t {
|
Ok(match t {
|
||||||
ast::Tree::Leaf(l) => match l {
|
ast::Tree::Leaf(l) => match l {
|
||||||
ast::Literal::Sym(s) => match env.lookup(s) {
|
ast::Literal::Sym(s) => match env.borrow().lookup(s) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return err(format!("Undefined variable `{}`", s)),
|
None => return err(format!("Undefined variable `{}`", s)),
|
||||||
},
|
},
|
||||||
ast::Literal::Num(v) => Value::Num(*v),
|
ast::Literal::Num(v) => Value::Num(*v),
|
||||||
ast::Literal::Bool(b) => Value::Bool(*b),
|
ast::Literal::Bool(b) => Value::Bool(*b),
|
||||||
},
|
},
|
||||||
ast::Tree::Lambda(l) => Value::Lambda(l.clone()),
|
ast::Tree::Func(l) => Value::Lambda(Lambda {
|
||||||
|
func: Rc::clone(l),
|
||||||
|
captures: Rc::clone(&env),
|
||||||
|
}),
|
||||||
ast::Tree::Branch(args) => {
|
ast::Tree::Branch(args) => {
|
||||||
let Some(fun) = args.get(0) else { return err("No argument given".to_owned()) };
|
let Some(fun) = args.get(0) else { return err("No func given".to_owned()) };
|
||||||
let fun = eval(fun, env)?;
|
|
||||||
let fun = fun.as_func()?;
|
let fun = eval(fun, Rc::clone(&env))?.as_func()?;
|
||||||
|
|
||||||
let args = args
|
let args = args
|
||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.map(|a| eval(a, env))
|
.map(|a| eval(a, Rc::clone(&env)))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
// return fun(&args);
|
|
||||||
match fun {
|
match fun {
|
||||||
Callable::Func(f) => f(&args)?,
|
Callable::Func(f) => f(&args)?,
|
||||||
Callable::Lambda(l) => {
|
Callable::Lambda(l) => {
|
||||||
if l.0.len() == args.len() {
|
if l.func.args.len() == args.len() {
|
||||||
let mut env = env.child();
|
// let mut env = env.child();
|
||||||
for (x, y) in l.0.iter().zip(args) {
|
let mut env = Env::child(Rc::clone(&l.captures));
|
||||||
|
|
||||||
|
for (x, y) in l.func.args.iter().zip(args) {
|
||||||
env.define(x.clone(), y)
|
env.define(x.clone(), y)
|
||||||
}
|
}
|
||||||
|
let env = Rc::new(RefCell::new(env));
|
||||||
|
|
||||||
let [main @ .., tail] = &l.1[..] else { unreachable!("Body has 1+ element by parser") };
|
let [main @ .., tail] = &l.func.body[..] else { unreachable!("Body has 1+ element by parser") };
|
||||||
for i in main {
|
for i in main {
|
||||||
eval(i, &mut env)?;
|
eval(i, Rc::clone(&env))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
eval(tail, &mut env)?
|
eval(tail, env)?
|
||||||
} else {
|
} else {
|
||||||
return err(format!("Need {} args, got {}", l.0.len(), args.len()));
|
return err(format!(
|
||||||
|
"Need {} args, got {}",
|
||||||
|
l.func.args.len(),
|
||||||
|
args.len()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::Tree::Define(name, to) => {
|
ast::Tree::Define(name, to) => {
|
||||||
let val = eval(to, env)?;
|
let val = eval(to, Rc::clone(&env))?;
|
||||||
env.define(name.to_owned(), val);
|
env.borrow_mut().define(name.to_owned(), val);
|
||||||
|
Value::Trap
|
||||||
|
}
|
||||||
|
ast::Tree::Set(name, to) => {
|
||||||
|
let val = eval(to, Rc::clone(&env))?;
|
||||||
|
env.borrow_mut().set(name, val)?;
|
||||||
Value::Trap
|
Value::Trap
|
||||||
}
|
}
|
||||||
ast::Tree::If(box [cond, tcase, fcase]) => {
|
ast::Tree::If(box [cond, tcase, fcase]) => {
|
||||||
let b = eval(cond, env)?.as_bool()?;
|
let b = eval(cond, Rc::clone(&env))?.as_bool()?;
|
||||||
let body = if b { tcase } else { fcase };
|
let body = if b { tcase } else { fcase };
|
||||||
eval(body, env)?
|
eval(body, env)?
|
||||||
}
|
}
|
||||||
|
@ -66,40 +90,72 @@ pub(crate) fn err<T>(s: String) -> Result<T, RTError> {
|
||||||
Err(RTError(s))
|
Err(RTError(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum Callable<'a> {
|
pub(crate) enum Callable {
|
||||||
Func(prims::Func),
|
Func(prims::NativeFunc),
|
||||||
Lambda(&'a ast::Lambda),
|
Lambda(Lambda),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Env<'a> {
|
#[derive(Clone /*, debug2::Debug*/)]
|
||||||
pub(crate) vars: HashMap<String, Value>,
|
pub(crate) struct Env {
|
||||||
pub(crate) enclosing: Option<&'a Env<'a>>,
|
vars: HashMap<String, Value>,
|
||||||
|
enclosing: Option<Rc<RefCell<Env>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Env<'a> {
|
impl std::fmt::Debug for Env {
|
||||||
pub(crate) fn child(&'a self) -> Env<'a> {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
struct Vars<'a>(&'a HashMap<String, Value>);
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Vars<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_set().entries(self.0.keys()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.debug_struct("Env")
|
||||||
|
.field("vars", &Vars(&self.vars))
|
||||||
|
.field("enclosing", &self.enclosing)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Env {
|
||||||
|
pub(crate) fn child(this: Rc<RefCell<Self>>) -> Env {
|
||||||
Env {
|
Env {
|
||||||
vars: HashMap::new(),
|
vars: HashMap::new(),
|
||||||
enclosing: Some(self),
|
enclosing: Some(this),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lookup(&self, s: &str) -> Option<Value> {
|
pub(crate) fn lookup(&self, s: &str) -> Option<Value> {
|
||||||
if let Some(v) = self.vars.get(s) {
|
if let Some(v) = self.vars.get(s) {
|
||||||
Some(v.clone())
|
Some(v.clone())
|
||||||
} else if let Some(parent) = self.enclosing {
|
} else if let Some(parent) = &self.enclosing {
|
||||||
parent.lookup(s)
|
parent.borrow().lookup(s)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn define(&mut self, name: String, val: Value) {
|
pub(crate) fn define(&mut self, name: String, val: Value) {
|
||||||
|
assert_ne!(val, Value::Trap); // TODO: Better error
|
||||||
|
|
||||||
|
// TODO: Error on previous def
|
||||||
self.vars.insert(name, val);
|
self.vars.insert(name, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate fn set(&mut self, name: &str, val: Value) -> Result<(), RTError> {
|
||||||
|
if let Some(loc) = self.vars.get_mut(name) {
|
||||||
|
*loc = val;
|
||||||
|
Ok(())
|
||||||
|
} else if let Some(parent) = &self.enclosing {
|
||||||
|
parent.borrow_mut().set(name, val)
|
||||||
|
} else {
|
||||||
|
err(format!("Tried to `set!` un `define`d var `{}`", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn default_env() -> Env<'static> {
|
pub(crate) fn default_env() -> Env {
|
||||||
let mut vars = HashMap::new();
|
let mut vars = HashMap::new();
|
||||||
|
|
||||||
for (name, fun) in prims::prims() {
|
for (name, fun) in prims::prims() {
|
||||||
|
|
|
@ -17,9 +17,11 @@ Trees = Tree+;
|
||||||
pub(crate) Tree: Tree = {
|
pub(crate) Tree: Tree = {
|
||||||
"(" <Tree+> ")" => Tree::Branch(<>),
|
"(" <Tree+> ")" => Tree::Branch(<>),
|
||||||
"(" "define" <Sym> <BTree> ")" => Tree::Define(<>),
|
"(" "define" <Sym> <BTree> ")" => Tree::Define(<>),
|
||||||
"(" "define" "(" <name:Sym> <args:RcSlice<Sym>> ")" <body:RcSlice<Tree>> ")" => Tree::Define(name, Box::new(Tree::Lambda(Lambda(args, body)))),
|
"(" "define" "(" <name:Sym> <args:Sym*> ")" <body:Trees> ")"
|
||||||
|
=> Tree::Define(name, Box::new(Tree::Func(Rc::new(Func{args, body})))),
|
||||||
"(" "if" <Tree> <Tree> <Tree> ")" => Tree::If(Box::new([<>])),
|
"(" "if" <Tree> <Tree> <Tree> ")" => Tree::If(Box::new([<>])),
|
||||||
"(" "lambda (" <RcSlice<Sym>> ")" <RcSlice<Tree>> ")" => Tree::Lambda(Lambda(<>)),
|
"(" "lambda (" <args:Sym*> ")" <body:Trees> ")" => Tree::Func(Rc::new(Func{<>})),
|
||||||
|
"(" "set!" <Sym> <BTree> ")" => Tree::Set(<>),
|
||||||
Literal => Tree::Leaf(<>),
|
Literal => Tree::Leaf(<>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1988
src/grammar.rs
1988
src/grammar.rs
File diff suppressed because it is too large
Load Diff
19
src/main.rs
19
src/main.rs
|
@ -4,7 +4,9 @@
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
#![feature(let_else)]
|
#![feature(let_else)]
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use rustyline::validate::{
|
use rustyline::validate::{
|
||||||
MatchingBracketValidator, ValidationContext, ValidationResult, Validator,
|
MatchingBracketValidator, ValidationContext, ValidationResult, Validator,
|
||||||
|
@ -33,9 +35,9 @@ fn main() {
|
||||||
fn run_file(file: &str) -> io::Result<()> {
|
fn run_file(file: &str) -> io::Result<()> {
|
||||||
let src = std::fs::read_to_string(file)?;
|
let src = std::fs::read_to_string(file)?;
|
||||||
let tree = grammar::FileParser::new().parse(&src).unwrap();
|
let tree = grammar::FileParser::new().parse(&src).unwrap();
|
||||||
let mut env = eval::default_env();
|
let env = Rc::new(RefCell::new(eval::default_env()));
|
||||||
for i in tree {
|
for i in tree {
|
||||||
eval::eval(&i, &mut env).unwrap();
|
eval::eval(&i, Rc::clone(&env)).unwrap();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -46,14 +48,23 @@ fn repl() {
|
||||||
brackets: MatchingBracketValidator::new(),
|
brackets: MatchingBracketValidator::new(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let mut env = eval::default_env();
|
let env = Rc::new(RefCell::new(eval::default_env()));
|
||||||
|
|
||||||
while let Ok(line) = rl.readline("> ") {
|
while let Ok(line) = rl.readline("> ") {
|
||||||
rl.add_history_entry(&line);
|
rl.add_history_entry(&line);
|
||||||
|
|
||||||
let tree = grammar::TreeParser::new().parse(&line).unwrap();
|
let tree = grammar::TreeParser::new().parse(&line).unwrap();
|
||||||
// dbg!(&tree);
|
// dbg!(&tree);
|
||||||
println!("< {:?}", eval::eval(&tree, &mut env))
|
match eval::eval(&tree, Rc::clone(&env)) {
|
||||||
|
Ok(v) => {
|
||||||
|
// Cant use == because it will panic. This is the only
|
||||||
|
// valid comparison to trap
|
||||||
|
if !matches!(v, value::Value::Trap) {
|
||||||
|
println!("{}", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => println!("! {}", e.0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
src/prims.rs
36
src/prims.rs
|
@ -1,9 +1,12 @@
|
||||||
use crate::eval::{err, RTError};
|
use crate::eval::{err, RTError};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
crate type Func = fn(&[Value]) -> Result<Value, RTError>;
|
|
||||||
|
|
||||||
crate fn prims() -> &'static [(&'static str, Func)] {
|
type Result = std::result::Result<Value, RTError>;
|
||||||
|
|
||||||
|
crate type NativeFunc = for<'a> fn(&'a [Value]) -> Result;
|
||||||
|
|
||||||
|
crate fn prims() -> &'static [(&'static str, NativeFunc)] {
|
||||||
&[
|
&[
|
||||||
("*", mul),
|
("*", mul),
|
||||||
("+", add),
|
("+", add),
|
||||||
|
@ -21,25 +24,27 @@ crate fn prims() -> &'static [(&'static str, Func)] {
|
||||||
(">", gt),
|
(">", gt),
|
||||||
("<=", le),
|
("<=", le),
|
||||||
(">=", ge),
|
(">=", ge),
|
||||||
|
|
||||||
|
("_Z_debug", z_debug)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: DRY +-/*
|
// TODO: DRY +-/*
|
||||||
fn add(args: &[Value]) -> Result<Value, RTError> {
|
fn add(args: &[Value]) -> Result {
|
||||||
args.iter()
|
args.iter()
|
||||||
.map(Value::as_num)
|
.map(Value::as_num)
|
||||||
.try_fold(0.0, |a, b| Ok(a + b?))
|
.try_fold(0.0, |a, b| Ok(a + b?))
|
||||||
.map(Value::Num)
|
.map(Value::Num)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mul(args: &[Value]) -> Result<Value, RTError> {
|
fn mul(args: &[Value]) -> Result {
|
||||||
args.iter()
|
args.iter()
|
||||||
.map(Value::as_num)
|
.map(Value::as_num)
|
||||||
.try_fold(1.0, |a, b| Ok(a * b?))
|
.try_fold(1.0, |a, b| Ok(a * b?))
|
||||||
.map(Value::Num)
|
.map(Value::Num)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn div(args: &[Value]) -> Result<Value, RTError> {
|
fn div(args: &[Value]) -> Result {
|
||||||
let init = args
|
let init = args
|
||||||
.get(0)
|
.get(0)
|
||||||
.ok_or_else(|| RTError("`div` needs at least one argument".to_owned()))?
|
.ok_or_else(|| RTError("`div` needs at least one argument".to_owned()))?
|
||||||
|
@ -53,7 +58,7 @@ fn div(args: &[Value]) -> Result<Value, RTError> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub(args: &[Value]) -> Result<Value, RTError> {
|
fn sub(args: &[Value]) -> Result {
|
||||||
let init = args
|
let init = args
|
||||||
.get(0)
|
.get(0)
|
||||||
.ok_or_else(|| RTError("`sub` needs at least one argument".to_owned()))?
|
.ok_or_else(|| RTError("`sub` needs at least one argument".to_owned()))?
|
||||||
|
@ -67,17 +72,17 @@ fn sub(args: &[Value]) -> Result<Value, RTError> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equals(args: &[Value]) -> Result<Value, RTError> {
|
fn equals(args: &[Value]) -> Result {
|
||||||
Ok(Value::Bool(args.array_windows().all(|[l, r]| l == r)))
|
Ok(Value::Bool(args.array_windows().all(|[l, r]| l == r)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display(args: &[Value]) -> Result<Value, RTError> {
|
fn display(args: &[Value]) -> Result {
|
||||||
let [arg] = args else {return err("To many args to `display`".to_owned())};
|
let [arg] = args else {return err("To many args to `display`".to_owned())};
|
||||||
print!("{:?}", arg);
|
print!("{}", arg);
|
||||||
Ok(Value::Trap)
|
Ok(Value::Trap)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn newline(args: &[Value]) -> Result<Value, RTError> {
|
fn newline(args: &[Value]) -> Result {
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
return err("Newline takes no args".to_owned());
|
return err("Newline takes no args".to_owned());
|
||||||
}
|
}
|
||||||
|
@ -85,7 +90,7 @@ fn newline(args: &[Value]) -> Result<Value, RTError> {
|
||||||
Ok(Value::Trap)
|
Ok(Value::Trap)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abs(args: &[Value]) -> Result<Value, RTError> {
|
fn abs(args: &[Value]) -> Result {
|
||||||
let [v] = args else { return err("abs takes 1 arg".to_owned()) };
|
let [v] = args else { return err("abs takes 1 arg".to_owned()) };
|
||||||
let ans = v.as_num()?.abs();
|
let ans = v.as_num()?.abs();
|
||||||
Ok(Value::Num(ans))
|
Ok(Value::Num(ans))
|
||||||
|
@ -95,7 +100,7 @@ crate fn compare_core(
|
||||||
args: &[Value],
|
args: &[Value],
|
||||||
f: fn(f64, f64) -> bool,
|
f: fn(f64, f64) -> bool,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
) -> Result<Value, RTError> {
|
) -> Result {
|
||||||
for [l, r] in args.array_windows() {
|
for [l, r] in args.array_windows() {
|
||||||
let (Value::Num(l), Value::Num(r)) = (l,r) else
|
let (Value::Num(l), Value::Num(r)) = (l,r) else
|
||||||
{
|
{
|
||||||
|
@ -114,7 +119,7 @@ crate fn compare_core(
|
||||||
macro_rules! cmps {
|
macro_rules! cmps {
|
||||||
($(($name:ident $op:tt))*) => {
|
($(($name:ident $op:tt))*) => {
|
||||||
$(
|
$(
|
||||||
fn $name(args: &[Value]) -> Result<Value, RTError> {
|
fn $name(args: &[Value]) -> Result {
|
||||||
compare_core(args, |l, r| l $op r, stringify!($op))
|
compare_core(args, |l, r| l $op r, stringify!($op))
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
@ -122,3 +127,8 @@ macro_rules! cmps {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmps! { (lt <) (gt >) (le <=) (ge >=) }
|
cmps! { (lt <) (gt >) (le <=) (ge >=) }
|
||||||
|
|
||||||
|
fn z_debug(args: &[Value]) -> Result {
|
||||||
|
eprintln!("{:?}", args);
|
||||||
|
Ok(Value::Trap)
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass r7rs-spec\\4-1-6-Assignments.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
3.05.0
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: run-pass ambig-scope.scm
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
42.0
|
||||||
|
1.0
|
||||||
|
2.0
|
||||||
|
3.0
|
||||||
|
2.0
|
||||||
|
1.0
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\assign-closures.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
||||||
|
2.0
|
||||||
|
2.0
|
||||||
|
3.0
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\assign-shadowed-later.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
||||||
|
0.0
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\bagel-donut.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
4.0
|
||||||
|
2.0
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: run-pass capture.scm
|
||||||
|
|
||||||
|
---
|
||||||
|
#<procedure>
|
||||||
|
2.0
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\close-over-function-param.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
77.0
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\close-over-later-variable.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
2.0
|
||||||
|
1.0
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\close-unused.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
7.0
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\closed-closure-in-function.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: run-pass curry.scm
|
||||||
|
|
||||||
|
---
|
||||||
|
3.0
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\gnarly-i.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
3.0
|
||||||
|
2.0
|
||||||
|
1.0
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\mutate-levels.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
2.0
|
||||||
|
3.0
|
||||||
|
3.0
|
||||||
|
3.0
|
||||||
|
7.0
|
||||||
|
8.0
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\nested-assign.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\nested-closure.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
||||||
|
2.0
|
||||||
|
3.0
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\objects-are-a-poor-mans-closure.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
||||||
|
7.0
|
||||||
|
1.0
|
||||||
|
7.0
|
||||||
|
|
||||||
|
8.0
|
||||||
|
2.0
|
||||||
|
8.0
|
||||||
|
2.0
|
||||||
|
|
||||||
|
9.0
|
||||||
|
9.0
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\open-closure-in-function.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\reference-closure-multiple-times.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
||||||
|
1.0
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\reuse-closure-slot.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\scope.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
7.0
|
||||||
|
2.0
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\shadow-closure-with-local.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
0.0
|
||||||
|
1.0
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\unused-later-closures.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
||||||
|
1.0
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\use-after-close.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
1.0
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
source: src/tests.rs
|
||||||
|
assertion_line: 41
|
||||||
|
expression: "run-pass closure\\val-or-var.scm"
|
||||||
|
|
||||||
|
---
|
||||||
|
0.0
|
||||||
|
1.0
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
#lang scheme
|
||||||
|
|
||||||
|
(define (displayln x)
|
||||||
|
(newline)
|
||||||
|
(display x))
|
||||||
|
|
||||||
|
(define (ambig1 x)
|
||||||
|
(lambda (x) x))
|
||||||
|
|
||||||
|
(displayln ((ambig1 13) 42))
|
||||||
|
|
||||||
|
(define (ambig2 a)
|
||||||
|
(displayln a)
|
||||||
|
(define a- a)
|
||||||
|
(lambda (b)
|
||||||
|
(displayln b)
|
||||||
|
(lambda (a)
|
||||||
|
(displayln a)
|
||||||
|
(displayln b)
|
||||||
|
(displayln a-))))
|
||||||
|
|
||||||
|
(((ambig2 1) 2) 3)
|
|
@ -0,0 +1,13 @@
|
||||||
|
#lang scheme
|
||||||
|
|
||||||
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(define (const x)
|
||||||
|
(lambda () x))
|
||||||
|
|
||||||
|
(define two-thunk (const 2))
|
||||||
|
|
||||||
|
(displayln two-thunk)
|
||||||
|
(displayln (two-thunk))
|
|
@ -0,0 +1,28 @@
|
||||||
|
; https://github.com/munificent/craftinginterpreters/blob/master/test/closure/assign_to_closure.lox
|
||||||
|
|
||||||
|
(define f #f)
|
||||||
|
(define g #f)
|
||||||
|
|
||||||
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define local 1)
|
||||||
|
|
||||||
|
(define (f_)
|
||||||
|
(displayln local)
|
||||||
|
(set! local 2)
|
||||||
|
(displayln local))
|
||||||
|
|
||||||
|
(set! f f_)
|
||||||
|
|
||||||
|
(define (g_)
|
||||||
|
(displayln local)
|
||||||
|
(set! local 3)
|
||||||
|
(displayln local))
|
||||||
|
|
||||||
|
(set! g g_)))
|
||||||
|
|
||||||
|
(f)
|
||||||
|
(g)
|
|
@ -0,0 +1,17 @@
|
||||||
|
; https://github.com/munificent/craftinginterpreters/blob/master/test/closure/assign_to_shadowed_later.lox
|
||||||
|
|
||||||
|
(define a 0)
|
||||||
|
|
||||||
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define (assign)
|
||||||
|
(set! a 1))
|
||||||
|
|
||||||
|
(define a 2)
|
||||||
|
(assign)
|
||||||
|
(displayln a)))
|
||||||
|
|
||||||
|
(displayln a)
|
|
@ -0,0 +1,14 @@
|
||||||
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(define (make-print x)
|
||||||
|
(define (print)
|
||||||
|
(displayln x))
|
||||||
|
print)
|
||||||
|
|
||||||
|
(define print-2 (make-print 2))
|
||||||
|
(define print-4 (make-print 4))
|
||||||
|
|
||||||
|
(print-4)
|
||||||
|
(print-2)
|
|
@ -0,0 +1,10 @@
|
||||||
|
(define f #f)
|
||||||
|
|
||||||
|
(define (foo param)
|
||||||
|
(define (f_)
|
||||||
|
(display param))
|
||||||
|
(set! f f_))
|
||||||
|
|
||||||
|
(foo 77)
|
||||||
|
|
||||||
|
(f)
|
|
@ -0,0 +1,14 @@
|
||||||
|
; https://github.com/munificent/craftinginterpreters/blob/master/test/closure/close_over_later_variable.lox
|
||||||
|
|
||||||
|
(define (f)
|
||||||
|
(define a 1)
|
||||||
|
(define b 2)
|
||||||
|
|
||||||
|
(define (g)
|
||||||
|
(display b)
|
||||||
|
(newline)
|
||||||
|
(display a))
|
||||||
|
|
||||||
|
(g))
|
||||||
|
|
||||||
|
(f)
|
|
@ -0,0 +1,6 @@
|
||||||
|
((lambda ()
|
||||||
|
(define a 1)
|
||||||
|
|
||||||
|
(if #f (lambda () a) 0)))
|
||||||
|
|
||||||
|
(display 7)
|
|
@ -0,0 +1,11 @@
|
||||||
|
; https://github.com/munificent/craftinginterpreters/blob/master/test/closure/closed_closure_in_function.lox
|
||||||
|
|
||||||
|
(define f #f)
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define local 1)
|
||||||
|
(define (f_)
|
||||||
|
(display local))
|
||||||
|
(set! f f_)))
|
||||||
|
|
||||||
|
(f)
|
|
@ -0,0 +1,22 @@
|
||||||
|
#lang scheme
|
||||||
|
|
||||||
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(define (outer)
|
||||||
|
(define x 1)
|
||||||
|
|
||||||
|
(define (middle)
|
||||||
|
(define (inner)
|
||||||
|
(displayln x))
|
||||||
|
(displayln 2)
|
||||||
|
inner)
|
||||||
|
|
||||||
|
(displayln 3)
|
||||||
|
|
||||||
|
middle)
|
||||||
|
|
||||||
|
(define mid (outer))
|
||||||
|
(define in (mid))
|
||||||
|
(in)
|
|
@ -0,0 +1,24 @@
|
||||||
|
(define x 2)
|
||||||
|
|
||||||
|
(define (show-x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(show-x)
|
||||||
|
(set! x 3)
|
||||||
|
(show-x)
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define x 7)
|
||||||
|
(show-x)
|
||||||
|
(set! x 8)
|
||||||
|
(show-x)))
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define (show-x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
(define x 7)
|
||||||
|
(show-x)
|
||||||
|
(set! x 8)
|
||||||
|
(show-x)))
|
|
@ -0,0 +1,8 @@
|
||||||
|
(define (outer)
|
||||||
|
(define x 0)
|
||||||
|
(define (y)
|
||||||
|
(set! x 1))
|
||||||
|
(y)
|
||||||
|
(display x))
|
||||||
|
|
||||||
|
(outer)
|
|
@ -0,0 +1,26 @@
|
||||||
|
; https://github.com/munificent/craftinginterpreters/blob/master/test/closure/nested_closure.lox
|
||||||
|
#lang scheme
|
||||||
|
|
||||||
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(define f #f)
|
||||||
|
|
||||||
|
(define (f1)
|
||||||
|
(define a 1)
|
||||||
|
(define (f2)
|
||||||
|
(define b 2)
|
||||||
|
(define (f3)
|
||||||
|
(define c 3)
|
||||||
|
(define (f4)
|
||||||
|
(displayln a)
|
||||||
|
(displayln b)
|
||||||
|
(displayln c))
|
||||||
|
(set! f f4))
|
||||||
|
(f3))
|
||||||
|
(f2))
|
||||||
|
|
||||||
|
(f1)
|
||||||
|
|
||||||
|
(f)
|
|
@ -0,0 +1,43 @@
|
||||||
|
#lang scheme
|
||||||
|
|
||||||
|
(define get-x 1)
|
||||||
|
(define get-y 2)
|
||||||
|
(define do-print 3)
|
||||||
|
(define add 4)
|
||||||
|
|
||||||
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(define (vector x y)
|
||||||
|
(define (add-to other)
|
||||||
|
(vector (+ x (other get-x)) (+ y (other get-y))))
|
||||||
|
|
||||||
|
(lambda (message)
|
||||||
|
(if (= message get-x)
|
||||||
|
x
|
||||||
|
(if (= message get-y)
|
||||||
|
y
|
||||||
|
(if (= message add)
|
||||||
|
add-to
|
||||||
|
(if (= message do-print)
|
||||||
|
((lambda ()
|
||||||
|
(displayln x)
|
||||||
|
(displayln y)
|
||||||
|
(newline)))
|
||||||
|
((lambda ()
|
||||||
|
(displayln -99)
|
||||||
|
0))))))))
|
||||||
|
|
||||||
|
(define v-1-7 (vector 1 7))
|
||||||
|
(displayln (v-1-7 get-x))
|
||||||
|
(displayln (v-1-7 get-y))
|
||||||
|
(v-1-7 do-print)
|
||||||
|
|
||||||
|
(define v-8-2 (vector 8 2))
|
||||||
|
(displayln (v-8-2 get-x))
|
||||||
|
(displayln (v-8-2 get-y))
|
||||||
|
(v-8-2 do-print)
|
||||||
|
|
||||||
|
(define v-9-9 ((v-8-2 add) v-1-7))
|
||||||
|
(v-9-9 do-print)
|
|
@ -0,0 +1,9 @@
|
||||||
|
#lang scheme
|
||||||
|
|
||||||
|
; https://github.com/munificent/craftinginterpreters/blob/master/test/closure/open_closure_in_function.lox
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define local 1)
|
||||||
|
(define (f)
|
||||||
|
(display local))
|
||||||
|
(f)))
|
|
@ -0,0 +1,14 @@
|
||||||
|
#lang scheme
|
||||||
|
; https://github.com/munificent/craftinginterpreters/blob/master/test/closure/reference_closure_multiple_times.lox
|
||||||
|
|
||||||
|
(define f #f)
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define a 1)
|
||||||
|
(define (f_)
|
||||||
|
(display a)
|
||||||
|
(newline)
|
||||||
|
(display a))
|
||||||
|
(set! f f_)))
|
||||||
|
|
||||||
|
(f)
|
|
@ -0,0 +1,15 @@
|
||||||
|
#lang scheme
|
||||||
|
|
||||||
|
; https://github.com/munificent/craftinginterpreters/blob/master/test/closure/reuse_closure_slot.lox
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define f #f)
|
||||||
|
((lambda ()
|
||||||
|
(define a 1)
|
||||||
|
(define (f_)
|
||||||
|
(display a))
|
||||||
|
(set! f f_)))
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define b 2)
|
||||||
|
(f)))))
|
|
@ -0,0 +1,13 @@
|
||||||
|
(define x 2)
|
||||||
|
|
||||||
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(define (gy y)
|
||||||
|
x)
|
||||||
|
(define (gx x)
|
||||||
|
x)
|
||||||
|
|
||||||
|
(displayln (gx 7))
|
||||||
|
(displayln (gy 7))
|
|
@ -0,0 +1,15 @@
|
||||||
|
; https://github.com/munificent/craftinginterpreters/blob/master/test/closure/shadow_closure_with_local.lox
|
||||||
|
; TODO: Forbid this https://discordapp.com/channels/571040468092321801/618895179343986688/925533402592079912
|
||||||
|
|
||||||
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define foo 0)
|
||||||
|
(define (f)
|
||||||
|
((lambda ()
|
||||||
|
(displayln foo)
|
||||||
|
(define foo 1)
|
||||||
|
(displayln foo))))
|
||||||
|
(f)))
|
|
@ -0,0 +1,19 @@
|
||||||
|
(define closure #f)
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define a 1)
|
||||||
|
|
||||||
|
((lambda ()
|
||||||
|
(define b 2)
|
||||||
|
|
||||||
|
(define (get-a)
|
||||||
|
a)
|
||||||
|
|
||||||
|
(set! closure get-a)
|
||||||
|
|
||||||
|
(if #f (lambda () b) 0)))
|
||||||
|
|
||||||
|
(display (closure))))
|
||||||
|
|
||||||
|
(newline)
|
||||||
|
(display (closure))
|
|
@ -0,0 +1,8 @@
|
||||||
|
(define (outer)
|
||||||
|
(define x 1)
|
||||||
|
(define (inner)
|
||||||
|
(display x))
|
||||||
|
inner)
|
||||||
|
|
||||||
|
(define clousre (outer))
|
||||||
|
(clousre)
|
|
@ -0,0 +1,19 @@
|
||||||
|
(define globalSet #f)
|
||||||
|
(define globalGet #f)
|
||||||
|
|
||||||
|
(define (main)
|
||||||
|
(define a 0)
|
||||||
|
|
||||||
|
(define (set)
|
||||||
|
(set! a 1))
|
||||||
|
(define (get)
|
||||||
|
(display a)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(set! globalSet set)
|
||||||
|
(set! globalGet get))
|
||||||
|
|
||||||
|
(main)
|
||||||
|
(globalGet)
|
||||||
|
(globalSet)
|
||||||
|
(globalGet)
|
|
@ -0,0 +1,10 @@
|
||||||
|
#lang scheme
|
||||||
|
|
||||||
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(define (curry2 f)
|
||||||
|
(lambda (l) (lambda (r) (f l r))))
|
||||||
|
|
||||||
|
(displayln (((curry2 +) 1) 2))
|
|
@ -1,21 +1,28 @@
|
||||||
#lang scheme
|
#lang scheme
|
||||||
|
|
||||||
(define (displayln x) (display x) (newline))
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
(define (my-or a b) (if a #t b)) ; Test was written before we had `or`
|
(define (my-or a b)
|
||||||
|
(if a #t b)) ; Test was written before we had `or`
|
||||||
|
|
||||||
|
(define (fib-base? n)
|
||||||
(define (fib-base? n) (my-or (= n 1) (= n 0)))
|
(my-or (= n 1) (= n 0)))
|
||||||
|
|
||||||
(define (fib n)
|
(define (fib n)
|
||||||
(if (fib-base? n) 1
|
(if (fib-base? n) 1 (+ (fib (- n 1)) (fib (- n 2)))))
|
||||||
(+ (fib (- n 1)) (fib (- n 2)))))
|
|
||||||
|
|
||||||
|
(define (pfib n)
|
||||||
(define (pfib n) (displayln n) (displayln (fib n)) (newline))
|
(displayln n)
|
||||||
|
(displayln (fib n))
|
||||||
|
(newline))
|
||||||
|
|
||||||
(define (pfibs n)
|
(define (pfibs n)
|
||||||
(if (= n (- 1)) 0 ; Hack
|
(if (= n (- 1))
|
||||||
((lambda () (pfib n) (pfibs (- n 1)))))) ; Hack
|
0 ; Hack
|
||||||
|
((lambda ()
|
||||||
|
(pfib n)
|
||||||
|
(pfibs (- n 1)))))) ; Hack
|
||||||
|
|
||||||
(pfibs 10)
|
(pfibs 10)
|
|
@ -1,6 +1,8 @@
|
||||||
#lang scheme
|
#lang scheme
|
||||||
|
|
||||||
(define (displayln x) (display x) (newline))
|
(define (displayln x)
|
||||||
|
(display x)
|
||||||
|
(newline))
|
||||||
|
|
||||||
(define add1 +)
|
(define add1 +)
|
||||||
(displayln (add1 2 3))
|
(displayln (add1 2 3))
|
||||||
|
@ -8,5 +10,6 @@
|
||||||
(define add2 (lambda (a b) (+ a b)))
|
(define add2 (lambda (a b) (+ a b)))
|
||||||
(displayln (add2 5 6))
|
(displayln (add2 5 6))
|
||||||
|
|
||||||
(define (add3 a b) (+ a b))
|
(define (add3 a b)
|
||||||
|
(+ a b))
|
||||||
(displayln (add3 5 9))
|
(displayln (add3 5 9))
|
|
@ -1,18 +1,24 @@
|
||||||
#lang scheme
|
#lang scheme
|
||||||
|
|
||||||
(define (displayln x) (display x) (newline))
|
(define (displayln x)
|
||||||
(define (printbool x) (displayln (bool->int x)))
|
(display x)
|
||||||
|
(newline))
|
||||||
|
(define (printbool x)
|
||||||
|
(displayln (bool->int x)))
|
||||||
|
|
||||||
(define (true x y) x)
|
(define (true x y)
|
||||||
(define (false x y) y)
|
x)
|
||||||
(define (and x y) (x y x))
|
(define (false x y)
|
||||||
(define (or x y) (x x y))
|
y)
|
||||||
(define (not x) (x false true))
|
(define (and x y)
|
||||||
|
(x y x))
|
||||||
|
(define (or x y)
|
||||||
|
(x x y))
|
||||||
|
(define (not x)
|
||||||
|
(x false true))
|
||||||
|
|
||||||
(define (bool->int x)
|
(define (bool->int x)
|
||||||
(if
|
(if (equal? x true) 1 (if (equal? x false) 0 (- 1))))
|
||||||
(equal? x true) 1
|
|
||||||
(if (equal? x false) 0 (- 1))))
|
|
||||||
|
|
||||||
(printbool true)
|
(printbool true)
|
||||||
(printbool false)
|
(printbool false)
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#lang scheme
|
#lang scheme
|
||||||
|
|
||||||
(define (multi) 1 2 3)
|
(define (multi)
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3)
|
||||||
|
|
||||||
(display (multi))
|
(display (multi))
|
|
@ -6,15 +6,14 @@
|
||||||
(define (sqrt x)
|
(define (sqrt x)
|
||||||
(define (sqrt-iter guess x)
|
(define (sqrt-iter guess x)
|
||||||
(define (good-enough? guess x)
|
(define (good-enough? guess x)
|
||||||
(define (square x) (* x x))
|
(define (square x)
|
||||||
|
(* x x))
|
||||||
(< (abs (- (square guess) x)) 0.001))
|
(< (abs (- (square guess) x)) 0.001))
|
||||||
(define (improve guess x)
|
(define (improve guess x)
|
||||||
(define (average x y)
|
(define (average x y)
|
||||||
(/ (+ x y) 2))
|
(/ (+ x y) 2))
|
||||||
(average guess (/ x guess)))
|
(average guess (/ x guess)))
|
||||||
(if (good-enough? guess x)
|
(if (good-enough? guess x) guess (sqrt-iter (improve guess x) x)))
|
||||||
guess
|
|
||||||
(sqrt-iter (improve guess x) x)))
|
|
||||||
(sqrt-iter 1.0 x))
|
(sqrt-iter 1.0 x))
|
||||||
|
|
||||||
(display (sqrt 2))
|
(display (sqrt 2))
|
|
@ -0,0 +1,4 @@
|
||||||
|
(define x 2)
|
||||||
|
(display (+ x 1))
|
||||||
|
(set! x 4)
|
||||||
|
(display (+ x 1))
|
|
@ -4,9 +4,7 @@
|
||||||
; http://sarabander.github.io/sicp/html/1_002e1.xhtml#g_t1_002e1_002e7
|
; http://sarabander.github.io/sicp/html/1_002e1.xhtml#g_t1_002e1_002e7
|
||||||
|
|
||||||
(define (sqrt-iter guess x)
|
(define (sqrt-iter guess x)
|
||||||
(if (good-enough? guess x)
|
(if (good-enough? guess x) guess (sqrt-iter (improve guess x) x)))
|
||||||
guess
|
|
||||||
(sqrt-iter (improve guess x) x)))
|
|
||||||
|
|
||||||
(define (improve guess x)
|
(define (improve guess x)
|
||||||
(average guess (/ x guess)))
|
(average guess (/ x guess)))
|
||||||
|
@ -14,7 +12,8 @@
|
||||||
(define (average x y)
|
(define (average x y)
|
||||||
(/ (+ x y) 2))
|
(/ (+ x y) 2))
|
||||||
|
|
||||||
(define (square x) (* x x))
|
(define (square x)
|
||||||
|
(* x x))
|
||||||
|
|
||||||
(define (good-enough? guess x)
|
(define (good-enough? guess x)
|
||||||
(< (abs (- (square guess) x)) 0.001))
|
(< (abs (- (square guess) x)) 0.001))
|
||||||
|
|
|
@ -18,7 +18,7 @@ upstream for this
|
||||||
fn run_pass() {
|
fn run_pass() {
|
||||||
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
|
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
|
||||||
insta::glob!("test/run-pass/**.scm", |p| {
|
insta::glob!("test/run-pass/**/*.scm", |p| {
|
||||||
let p = PathBuf::from(
|
let p = PathBuf::from(
|
||||||
p.canonicalize()
|
p.canonicalize()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
41
src/value.rs
41
src/value.rs
|
@ -1,16 +1,32 @@
|
||||||
use crate::{ast, eval, prims};
|
use crate::{eval, prims};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone /*, debug2::Debug*/)]
|
||||||
crate enum Value {
|
crate enum Value {
|
||||||
Num(f64),
|
Num(f64),
|
||||||
Func(prims::Func),
|
// TODO: implement debug2::Debug for `fn` type, and do it right
|
||||||
Lambda(ast::Lambda),
|
// https://godbolt.org/z/vr9erGeKq
|
||||||
|
Func(prims::NativeFunc),
|
||||||
|
Lambda(eval::Lambda),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
/// Result of things that shouldnt have values, like (define x 3)
|
/// Result of things that shouldnt have values, like (define x 3)
|
||||||
|
/// TODO: Figure this out
|
||||||
Trap,
|
Trap,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Value {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Num(arg0) => f.debug_tuple("Num").field(arg0).finish(),
|
||||||
|
// We cant just pass the field because of livetime bs, see https://godbolt.org/z/vr9erGeKq
|
||||||
|
Self::Func(_) => f.debug_struct("Func").finish_non_exhaustive(),
|
||||||
|
Self::Lambda(arg0) => f.debug_tuple("Lambda").field(arg0).finish(),
|
||||||
|
Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
|
||||||
|
Self::Trap => write!(f, "Trap"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for Value {
|
impl PartialEq for Value {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
|
@ -18,7 +34,9 @@ impl PartialEq for Value {
|
||||||
(Num(l), Num(r)) => l == r,
|
(Num(l), Num(r)) => l == r,
|
||||||
(Func(l), Func(r)) => *l as usize == *r as usize,
|
(Func(l), Func(r)) => *l as usize == *r as usize,
|
||||||
(Bool(l), Bool(r)) => l == r,
|
(Bool(l), Bool(r)) => l == r,
|
||||||
(Lambda(l), Lambda(r)) => Rc::ptr_eq(&l.0, &r.0) && Rc::ptr_eq(&l.1, &r.1),
|
(Lambda(l), Lambda(r)) => {
|
||||||
|
Rc::ptr_eq(&l.func, &r.func) && Rc::ptr_eq(&l.captures, &r.captures)
|
||||||
|
}
|
||||||
|
|
||||||
(Num(_), _) => false,
|
(Num(_), _) => false,
|
||||||
(Func(_), _) => false,
|
(Func(_), _) => false,
|
||||||
|
@ -30,10 +48,10 @@ impl PartialEq for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Value {
|
impl std::fmt::Display for Value {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Num(n) => n.fmt(f),
|
Self::Num(n) => std::fmt::Debug::fmt(n, f), // TODO: Change to displays
|
||||||
Self::Func(_) => f.write_str("#<procedure>"),
|
Self::Func(_) => f.write_str("#<procedure>"),
|
||||||
Self::Lambda(_) => f.write_str("#<procedure>"),
|
Self::Lambda(_) => f.write_str("#<procedure>"),
|
||||||
Self::Bool(b) => f.write_str(if *b { "#t" } else { "#f" }),
|
Self::Bool(b) => f.write_str(if *b { "#t" } else { "#f" }),
|
||||||
|
@ -51,14 +69,11 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn as_func(&self) -> Result<eval::Callable, eval::RTError> {
|
crate fn as_func(self) -> Result<eval::Callable, eval::RTError> {
|
||||||
match self {
|
match self {
|
||||||
Self::Func(f) => Ok(eval::Callable::Func(*f)),
|
Self::Func(f) => Ok(eval::Callable::Func(f)),
|
||||||
Self::Lambda(l) => Ok(eval::Callable::Lambda(l)),
|
Self::Lambda(l) => Ok(eval::Callable::Lambda(l)),
|
||||||
_ => Err(eval::RTError(format!(
|
_ => Err(eval::RTError(format!("Expected a function, got {}", self))),
|
||||||
"Expected a function, got {:?}",
|
|
||||||
self
|
|
||||||
))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue