Implement primitive procedure application
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
use crate::parser::Datum;
|
||||
use crate::parser::Datum::*;
|
||||
|
||||
fn add(args: Vec<Datum>) -> 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<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 -- cannot-apply {:?}", exp)
|
||||
panic!("The object {:?} is not applicable", args[0])
|
||||
}
|
||||
} else {
|
||||
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),
|
||||
}
|
||||
}
|
||||
@@ -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] = &['+', '-', '.', '@'];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<Datum>),
|
||||
Procedure(fn(Vec<Datum>) -> Datum),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Default for Datum {
|
||||
fn default() -> Self {
|
||||
Datum::None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(tokens: Tokens) -> Datum {
|
||||
@@ -23,7 +28,7 @@ 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]),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
58
src/primitives.rs
Normal file
58
src/primitives.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use crate::parser::Datum;
|
||||
use crate::parser::Datum::*;
|
||||
use std::mem;
|
||||
|
||||
pub fn add(mut args: Vec<Datum>) -> 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>) -> 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>) -> 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)
|
||||
}
|
||||
Reference in New Issue
Block a user