diff --git a/src/interpreter.rs b/src/interpreter.rs index 237a694..14c12e6 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,15 +1,15 @@ use crate::parser::Datum; use crate::parser::Datum::*; - -fn add(args: Vec) -> Datum { - Number(42) -} +use crate::primitives::*; +use std::mem; fn lookup_variable_value(exp: Datum) -> Datum { if let Symbol(string) = exp { match string.as_str() { "+" => Procedure(add), - _ => panic!("unbound-variable {:?}", string) + "*" => Procedure(mul), + "-" => Procedure(sub), + _ => panic!("unbound-variable {:?}", string), } } else { panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp) @@ -18,9 +18,19 @@ fn lookup_variable_value(exp: Datum) -> Datum { fn application(exp: Datum) -> Datum { if let List(vector) = exp { - vector[0] + if vector.len() == 0 { + panic!("Application needs at least a procedure") + } + + let mut args: Vec = 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!("The object {:?} is not applicable", args[0]) + } } else { - panic!("APPLICATION -- cannot-apply {:?}", exp) + panic!("Cannot apply {:?}", exp) } } @@ -29,6 +39,6 @@ pub fn interpret(exp: Datum) -> Datum { Boolean(_) | Number(_) => exp, Symbol(_) => lookup_variable_value(exp), List(_) => application(exp), - _ => panic!("unknown-expression {:?}", exp) + _ => panic!("unknown-expression {:?}", exp), } -} \ No newline at end of file +} diff --git a/src/lexer.rs b/src/lexer.rs index ad2a3d0..a6cc661 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -70,12 +70,12 @@ fn scan_boolean(code: &str, ix: usize, mut tokens: Tokens) -> Tokens { "#t" => { let token = Token::Boolean(true); tokens.push(token); - }, + } "#f" => { let token = Token::Boolean(false); tokens.push(token); } - _ => panic!("Expected boolean but got {}", c) + _ => panic!("Expected boolean but got {}", c), } return scan(code, ix + 2, tokens); } @@ -135,6 +135,4 @@ const SPECIAL_INITIAL: &[char] = &[ '!', '$', '%', '&', '*', '/', ':', '<', '=', '>', '?', '^', '_', '~', '+', '-', ]; -const SPECIAL_SUBSEQUENT: &[char] = &[ - '+', '-', '.', '@', -]; +const SPECIAL_SUBSEQUENT: &[char] = &['+', '-', '.', '@']; diff --git a/src/main.rs b/src/main.rs index 1bb50aa..f81a901 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ +mod interpreter; mod lexer; mod parser; -mod interpreter; - +mod primitives; fn main() { // let scm_code = "(+ a (* 32 b) c #t #f)"; - let scm_code = "+"; + let scm_code = "(* 1 (- 2 2 2) 3)"; let tokens = lexer::read(scm_code); let datum = parser::parse(tokens); let result = interpreter::interpret(datum); diff --git a/src/parser.rs b/src/parser.rs index 437b47c..dda21ed 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,6 @@ use crate::lexer::Token; use crate::lexer::Tokens; - - #[derive(Debug)] pub enum Datum { Boolean(bool), @@ -10,6 +8,13 @@ pub enum Datum { Symbol(String), List(Vec), Procedure(fn(Vec) -> Datum), + None, +} + +impl Default for Datum { + fn default() -> Self { + Datum::None + } } pub fn parse(tokens: Tokens) -> Datum { @@ -23,14 +28,14 @@ fn parse_datum(tokens: &Tokens, ix: usize) -> (Datum, usize) { Token::Boolean(b) => (Datum::Boolean(*b), ix + 1), Token::Number(n) => (Datum::Number(*n), ix + 1), Token::LeftRoundBracket => parse_list(tokens, ix + 1), - _ => panic!("Unexpected token {:?}", tokens[ix]) + _ => panic!("Unexpected token {:?}", tokens[ix]), } } pub fn parse_list(tokens: &Tokens, mut ix: usize) -> (Datum, usize) { let mut datums = vec![]; - // FIXME: will crash when RightRoundBracket is missing + // FIXME: will crash when RightRoundBracket is missing while tokens[ix] != Token::RightRoundBracket { let (datum, new_ix) = parse_datum(tokens, ix); datums.push(datum); diff --git a/src/primitives.rs b/src/primitives.rs new file mode 100644 index 0000000..4ba9a23 --- /dev/null +++ b/src/primitives.rs @@ -0,0 +1,58 @@ +use crate::parser::Datum; +use crate::parser::Datum::*; +use std::mem; + +pub fn add(mut args: Vec) -> Datum { + let mut r = 0; + for i in 1..args.len() { + let datum = mem::take(&mut args[i]); + if let Number(n) = datum { + r += n; + } else { + panic!("ADD -- not-all-args-are-numbers {:?}", args) + } + } + Number(r) +} + +pub fn mul(mut args: Vec) -> Datum { + let mut r = 1; + for i in 1..args.len() { + let datum = mem::take(&mut args[i]); + if let Number(n) = datum { + r *= n; + } else { + panic!("MUL -- not-all-args-are-numbers {:?}", args) + } + } + Number(r) +} + +pub fn sub(mut args: Vec) -> Datum { + if args.len() == 2 { + let datum = mem::take(&mut args[1]); + if let Number(n) = datum { + return Number(-n); + } else { + panic!("SUB -- not-all-args-are-numbers {:?}", args) + } + } + + let mut r; + let datum = mem::take(&mut args[1]); + if let Number(n) = datum { + r = n; + } else { + panic!("SUB -- not-all-args-are-numbers {:?}", args) + } + + for i in 2..args.len() { + let datum = mem::take(&mut args[i]); + if let Number(n) = datum { + r -= n; + } else { + panic!("SUB -- not-all-args-are-numbers {:?}", args) + } + } + Number(r) +}