Add test file, implement and/or/not, prepare for proper compound proc
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,4 +7,3 @@
|
||||
**/*.rs.bk
|
||||
|
||||
.vscode
|
||||
test.scm
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
# 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
|
||||
```
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ pub fn get_global_environment<'a>() -> Env<'a> {
|
||||
(make_symbol("-"), Primitive(sub)),
|
||||
(make_symbol("="), Primitive(eq)),
|
||||
(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("cons"), Primitive(cons)),
|
||||
(make_symbol("car"), Primitive(car)),
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::environment::Env;
|
||||
use crate::parser::Datum;
|
||||
use crate::parser::Datum::*;
|
||||
|
||||
fn is_true(exp: &Datum) -> bool {
|
||||
pub fn is_true(exp: &Datum) -> bool {
|
||||
match exp {
|
||||
Boolean(b) => *b,
|
||||
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
|
||||
// scope of the definition. Otherwise, closures won't work.
|
||||
let lambda_body = args[2..].to_vec();
|
||||
let lambda = Lambda {
|
||||
// XXX: a procedure includes the current environment
|
||||
let body = args[2..].to_vec();
|
||||
let proc = Procedure {
|
||||
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),
|
||||
}
|
||||
@@ -157,7 +156,7 @@ fn interpret_application(vec: &Vec<Datum>, env: &mut Env) -> Datum {
|
||||
|
||||
match &args[0] {
|
||||
Primitive(proc) => proc(args),
|
||||
Lambda { parameters, body } => {
|
||||
Lambda { parameters, body } | Procedure { parameters, body } => {
|
||||
let lambda_args = args[1..].to_vec();
|
||||
let mut new_env =
|
||||
environment::extend(List(parameters.to_vec()), List(lambda_args), env);
|
||||
|
||||
@@ -42,8 +42,8 @@ fn interpret_file(filename: &Path) {
|
||||
let tokens = lexer::read(scm_code.as_str());
|
||||
let datum = parser::parse(tokens);
|
||||
let mut env = environment::get_global_environment();
|
||||
let result = interpreter::interpret(&datum, &mut env);
|
||||
println!("{:?}", result);
|
||||
let _result = interpreter::interpret(&datum, &mut env);
|
||||
// println!("{:?}", result);
|
||||
}
|
||||
Err(error) => println!("error: {} {:?}", error, filename),
|
||||
}
|
||||
@@ -51,8 +51,7 @@ fn interpret_file(filename: &Path) {
|
||||
|
||||
fn main() {
|
||||
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 ((a 3) (b 4)) (define c (+ a b)) (* c c))";
|
||||
let scm_code = "";
|
||||
|
||||
if args.len() == 2 {
|
||||
let arg_path = Path::new(&args[1]);
|
||||
|
||||
@@ -16,6 +16,10 @@ pub enum Datum {
|
||||
parameters: Vec<Datum>,
|
||||
body: Vec<Datum>,
|
||||
},
|
||||
Procedure {
|
||||
parameters: Vec<Datum>,
|
||||
body: Vec<Datum>,
|
||||
},
|
||||
Unspecified,
|
||||
}
|
||||
|
||||
@@ -42,7 +46,8 @@ impl PartialEq for Datum {
|
||||
impl fmt::Display for Datum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
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::Symbol(s) => write!(f, "{}", s),
|
||||
Datum::String(s) => write!(f, "{}", s),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::interpreter::has_tag;
|
||||
use crate::interpreter::is_true;
|
||||
use crate::parser::make_symbol;
|
||||
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 {
|
||||
for i in 1..args.len() {
|
||||
print!("{}", args[i]);
|
||||
|
||||
43
test.scm
Normal file
43
test.scm
Normal 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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user