Initial version of environment model
This commit is contained in:
31
src/environment.rs
Normal file
31
src/environment.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use crate::parser::Datum;
|
||||
use crate::parser::Datum::{Procedure, Symbol};
|
||||
use crate::parser::make_symbol;
|
||||
use crate::primitives;
|
||||
|
||||
type Mapping = (Datum, Datum);
|
||||
type Frame = Vec<Mapping>;
|
||||
pub type Env = Vec<Frame>;
|
||||
|
||||
pub fn get_global_environment() -> Env {
|
||||
vec![vec![(make_symbol("+"), Procedure(primitives::add)),
|
||||
(make_symbol("*"), Procedure(primitives::mul)),
|
||||
(make_symbol("-"), Procedure(primitives::sub))]]
|
||||
}
|
||||
|
||||
pub fn lookup_variable_value(exp: &Datum, env: &Env) -> Datum {
|
||||
if let Symbol(symbol_name) = exp {
|
||||
for frame in env {
|
||||
for mapping in frame {
|
||||
if let (Symbol(current_name), datum) = mapping {
|
||||
if symbol_name == current_name {
|
||||
return datum.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp)
|
||||
}
|
||||
panic!("LOOKUP-VARIABLE-VALUE -- unbound-variable-error {:?}", exp)
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
use crate::parser::Datum;
|
||||
use crate::parser::Datum::*;
|
||||
use crate::primitives::*;
|
||||
use crate::environment;
|
||||
use crate::environment::Env;
|
||||
use std::mem;
|
||||
|
||||
|
||||
fn is_true(exp: &Datum) -> bool {
|
||||
match exp {
|
||||
Boolean(b) => *b,
|
||||
@@ -12,28 +13,20 @@ fn is_true(exp: &Datum) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_variable_value(exp: &Datum) -> Datum {
|
||||
if let Symbol(string) = exp {
|
||||
match string.as_str() {
|
||||
"+" => Procedure(add),
|
||||
"*" => Procedure(mul),
|
||||
"-" => Procedure(sub),
|
||||
_ => panic!("LOOKUP-VARIABLE-VALUE -- unbound-variable {:?}", string),
|
||||
}
|
||||
} else {
|
||||
panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp)
|
||||
}
|
||||
}
|
||||
|
||||
fn application(exp: Datum) -> Datum {
|
||||
fn application(exp: &Datum, env: &Env) -> Datum {
|
||||
if let List(vector) = exp {
|
||||
if vector.len() == 0 {
|
||||
panic!("APPLICATION -- no-procedure")
|
||||
}
|
||||
|
||||
let mut args = vec![];
|
||||
for v in vector {
|
||||
let a = interpret(v, env);
|
||||
args.push(a)
|
||||
}
|
||||
|
||||
let mut args: Vec<Datum> = vector.into_iter().map(interpret).collect();
|
||||
// let mut args: Vec<Datum> = vector.into_iter().map(interpret).collect();
|
||||
if let Procedure(proc) = mem::take(&mut args[0]) {
|
||||
// FIXME: call procedures with args only
|
||||
proc(args)
|
||||
} else {
|
||||
panic!("APPLICATION -- not-aplicable {:?}", args[0])
|
||||
@@ -57,34 +50,39 @@ fn has_tag(exp: &Datum, tag: &str) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn interpret_if(mut args: Vec<Datum>) -> Datum {
|
||||
let predicate = mem::take(&mut args[1]);
|
||||
let alternative = mem::take(&mut args[2]);
|
||||
fn interpret_if(args: &Vec<Datum>, env: &Env) -> Datum {
|
||||
let predicate = &args[1];
|
||||
let alternative = &args[2];
|
||||
|
||||
if is_true(&predicate) {
|
||||
interpret(alternative)
|
||||
interpret(&alternative, env)
|
||||
} else {
|
||||
if args.len() == 4 {
|
||||
let consequent = mem::take(&mut args[3]);
|
||||
interpret(consequent)
|
||||
let consequent = &args[3];
|
||||
interpret(&consequent, env)
|
||||
} else {
|
||||
Unspecified
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interpret(exp: Datum) -> Datum {
|
||||
fn interpret_define(_args: &Vec<Datum>) -> Datum {
|
||||
|
||||
Number(42)
|
||||
}
|
||||
|
||||
pub fn interpret(exp: &Datum, env: &Env) -> Datum {
|
||||
match exp {
|
||||
Boolean(_) => exp,
|
||||
Number(_) => exp,
|
||||
Symbol(_) => lookup_variable_value(&exp),
|
||||
List(v) if has_tag(&exp, "if") => interpret_if(v),
|
||||
Boolean(b) => Boolean(*b),
|
||||
Number(n) => Number(*n),
|
||||
Symbol(_) => environment::lookup_variable_value(&exp, &env),
|
||||
List(v) if has_tag(&exp, "if") => interpret_if(v, &env),
|
||||
List(_) if has_tag(&exp, "set!") => panic!("assignment-not-supported"),
|
||||
List(_) if has_tag(&exp, "define") => panic!("define-not-supported"),
|
||||
List(v) if has_tag(&exp, "define") => interpret_define(v),
|
||||
List(_) if has_tag(&exp, "cond") => panic!("cond-not-supported"),
|
||||
List(_) if has_tag(&exp, "let") => panic!("let-not-supported"),
|
||||
List(_) if has_tag(&exp, "begin") => panic!("begin-not-supported"),
|
||||
List(_) => application(exp),
|
||||
List(_) => application(exp, env),
|
||||
// TODO: quoted
|
||||
_ => panic!("unknown-expression {:?}", exp),
|
||||
}
|
||||
|
||||
@@ -2,12 +2,15 @@ mod interpreter;
|
||||
mod lexer;
|
||||
mod parser;
|
||||
mod primitives;
|
||||
mod environment;
|
||||
|
||||
fn main() {
|
||||
// let scm_code = "(+ a (* 32 b) c #t #f)";
|
||||
let scm_code = "(if #f (+ 1 1) (* 2 3 4))";
|
||||
// let scm_code = "(define a (+ 3 3)";
|
||||
// let scm_code = "(- (* 3 3) 4)";
|
||||
let env = environment::get_global_environment();
|
||||
let tokens = lexer::read(scm_code);
|
||||
let datum = parser::parse(tokens);
|
||||
let result = interpreter::interpret(datum);
|
||||
let result = interpreter::interpret(&datum, &env);
|
||||
println!("{:?}", result);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::lexer::Token;
|
||||
use crate::lexer::Tokens;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Datum {
|
||||
Boolean(bool),
|
||||
Number(i64),
|
||||
@@ -11,6 +11,10 @@ pub enum Datum {
|
||||
Unspecified,
|
||||
}
|
||||
|
||||
pub fn make_symbol(s: &str) -> Datum {
|
||||
Datum::Symbol(s.to_string())
|
||||
}
|
||||
|
||||
impl Default for Datum {
|
||||
fn default() -> Self {
|
||||
Datum::Unspecified
|
||||
@@ -35,12 +39,14 @@ fn parse_datum(tokens: &Tokens, ix: usize) -> (Datum, usize) {
|
||||
pub fn parse_list(tokens: &Tokens, mut ix: usize) -> (Datum, usize) {
|
||||
let mut datums = vec![];
|
||||
|
||||
// FIXME: will crash when RightRoundBracket is missing
|
||||
while tokens[ix] != Token::RightRoundBracket {
|
||||
while ix < tokens.len() && tokens[ix] != Token::RightRoundBracket {
|
||||
let (datum, new_ix) = parse_datum(tokens, ix);
|
||||
datums.push(datum);
|
||||
ix = new_ix;
|
||||
}
|
||||
if ix == tokens.len() {
|
||||
panic!("PARSE_LIST -- missing closing bracket {:?}", tokens)
|
||||
}
|
||||
|
||||
(Datum::List(datums), ix + 1)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user