Add test file, implement and/or/not, prepare for proper compound proc

This commit is contained in:
2021-06-01 21:32:06 -04:00
parent 7b5435141a
commit 9d0003ff14
8 changed files with 108 additions and 15 deletions

1
.gitignore vendored
View File

@@ -7,4 +7,3 @@
**/*.rs.bk **/*.rs.bk
.vscode .vscode
test.scm

View File

@@ -1,3 +1,9 @@
# schemers # schemers
A crude Scheme interpreter implemented for SICP exercise 5.51. A crude Scheme interpreter implemented for SICP exercise 5.51.
```bash
cargo build
./target/debug/schemers test.scm
```

View File

@@ -22,6 +22,9 @@ pub fn get_global_environment<'a>() -> Env<'a> {
(make_symbol("-"), Primitive(sub)), (make_symbol("-"), Primitive(sub)),
(make_symbol("="), Primitive(eq)), (make_symbol("="), Primitive(eq)),
(make_symbol("<"), Primitive(lt)), (make_symbol("<"), Primitive(lt)),
(make_symbol("or"), Primitive(or)),
(make_symbol("and"), Primitive(and)),
(make_symbol("not"), Primitive(not)),
(make_symbol("list"), Primitive(list)), (make_symbol("list"), Primitive(list)),
(make_symbol("cons"), Primitive(cons)), (make_symbol("cons"), Primitive(cons)),
(make_symbol("car"), Primitive(car)), (make_symbol("car"), Primitive(car)),

View File

@@ -3,7 +3,7 @@ use crate::environment::Env;
use crate::parser::Datum; use crate::parser::Datum;
use crate::parser::Datum::*; use crate::parser::Datum::*;
fn is_true(exp: &Datum) -> bool { pub fn is_true(exp: &Datum) -> bool {
match exp { match exp {
Boolean(b) => *b, Boolean(b) => *b,
Number(_) => true, Number(_) => true,
@@ -72,14 +72,13 @@ fn interpret_define(args: &Vec<Datum>, env: &mut Env) -> Datum {
} }
} }
// XXX: A procedure is clearly not a lambda. We have to keep the // XXX: a procedure includes the current environment
// scope of the definition. Otherwise, closures won't work. let body = args[2..].to_vec();
let lambda_body = args[2..].to_vec(); let proc = Procedure {
let lambda = Lambda {
parameters: parameters, parameters: parameters,
body: lambda_body, body: body,
}; };
environment::define_variable(definition_var, lambda, env) environment::define_variable(definition_var, proc, env)
} }
_ => panic!("INTERPRET-DEFINE -- cannot define {:?}", args), _ => panic!("INTERPRET-DEFINE -- cannot define {:?}", args),
} }
@@ -157,7 +156,7 @@ fn interpret_application(vec: &Vec<Datum>, env: &mut Env) -> Datum {
match &args[0] { match &args[0] {
Primitive(proc) => proc(args), Primitive(proc) => proc(args),
Lambda { parameters, body } => { Lambda { parameters, body } | Procedure { parameters, body } => {
let lambda_args = args[1..].to_vec(); let lambda_args = args[1..].to_vec();
let mut new_env = let mut new_env =
environment::extend(List(parameters.to_vec()), List(lambda_args), env); environment::extend(List(parameters.to_vec()), List(lambda_args), env);

View File

@@ -42,8 +42,8 @@ fn interpret_file(filename: &Path) {
let tokens = lexer::read(scm_code.as_str()); let tokens = lexer::read(scm_code.as_str());
let datum = parser::parse(tokens); let datum = parser::parse(tokens);
let mut env = environment::get_global_environment(); let mut env = environment::get_global_environment();
let result = interpreter::interpret(&datum, &mut env); let _result = interpreter::interpret(&datum, &mut env);
println!("{:?}", result); // println!("{:?}", result);
} }
Err(error) => println!("error: {} {:?}", error, filename), Err(error) => println!("error: {} {:?}", error, filename),
} }
@@ -51,8 +51,7 @@ fn interpret_file(filename: &Path) {
fn main() { fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
// let scm_code = "(begin (define (f n) (if (= n 1) 1 (* n (f (- n 1))))) (f 10))"; let scm_code = "";
let scm_code = "(let ((a 3) (b 4)) (define c (+ a b)) (* c c))";
if args.len() == 2 { if args.len() == 2 {
let arg_path = Path::new(&args[1]); let arg_path = Path::new(&args[1]);

View File

@@ -16,6 +16,10 @@ pub enum Datum {
parameters: Vec<Datum>, parameters: Vec<Datum>,
body: Vec<Datum>, body: Vec<Datum>,
}, },
Procedure {
parameters: Vec<Datum>,
body: Vec<Datum>,
},
Unspecified, Unspecified,
} }
@@ -42,7 +46,8 @@ impl PartialEq for Datum {
impl fmt::Display for Datum { impl fmt::Display for Datum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Datum::Boolean(b) => write!(f, "{}", b), Datum::Boolean(true) => write!(f, "#t"),
Datum::Boolean(false) => write!(f, "#f"),
Datum::Number(n) => write!(f, "{}", n), Datum::Number(n) => write!(f, "{}", n),
Datum::Symbol(s) => write!(f, "{}", s), Datum::Symbol(s) => write!(f, "{}", s),
Datum::String(s) => write!(f, "{}", s), Datum::String(s) => write!(f, "{}", s),

View File

@@ -1,4 +1,5 @@
use crate::interpreter::has_tag; use crate::interpreter::has_tag;
use crate::interpreter::is_true;
use crate::parser::make_symbol; use crate::parser::make_symbol;
use crate::parser::Datum; use crate::parser::Datum;
use crate::parser::Datum::*; use crate::parser::Datum::*;
@@ -89,6 +90,44 @@ pub fn lt(args: Vec<Datum>) -> Datum {
} }
} }
pub fn or(args: Vec<Datum>) -> Datum {
if args.len() == 1 {
Boolean(false)
} else {
for i in 1..args.len() {
if is_true(&args[i]) {
return args[i].clone();
}
}
Boolean(false)
}
}
pub fn and(args: Vec<Datum>) -> Datum {
if args.len() == 1 {
Boolean(true)
} else {
for i in 1..args.len() {
if !is_true(&args[i]) {
return Boolean(false);
}
}
args[args.len() - 1].clone()
}
}
pub fn not(args: Vec<Datum>) -> Datum {
if args.len() != 2 {
panic!("NOT -- takes one argument");
} else {
if is_true(&args[1]) {
Boolean(false)
} else {
Boolean(true)
}
}
}
pub fn display(args: Vec<Datum>) -> Datum { pub fn display(args: Vec<Datum>) -> Datum {
for i in 1..args.len() { for i in 1..args.len() {
print!("{}", args[i]); print!("{}", args[i]);

43
test.scm Normal file
View File

@@ -0,0 +1,43 @@
(begin
(define (newline) (display "\n"))
(display (or #t #f)) (newline)
(display (and #t #f)) (newline)
(display (not #f)) (newline)
(define a 5)
(define (fib n)
(cond
((< n 0) (display "WARNING: n smaller than 0"))
((< n 3) 1)
(else (+ (fib (- n 2)) (fib (- n 1))))))
(define (fac n) (if (= n 1) 1 (* n (fac (- n 1)))))
(set! a (+ a a))
(define l (list a (* 3 3) (+ a a)))
(begin
(display "(fac ") (display a)
(display ") -> ") (display (fac a)) (display "\n"))
(begin
(display "(fib ") (display a)
(display ") -> ") (display (fib a)) (display "\n"))
(define l (cons 'a l))
(display l) (newline)
(display (cons 'a 'b)) (newline)
(display (car l)) (newline)
(display (cdr (cdr l))) (newline)
(display (pair? l)) (newline)
(display (pair? 'a)) (newline)
(display ((lambda (x y) (* x a)) 3 5)) (newline)
(display
(let ((a (+ a a))
(b (* a a))
(x 42))
(+ a b x)))
(newline)
(define (p)
(define a 42)
(define (f) a)
f)
(display ((p))) ; should return 42
(newline)
'done
)