Implement primitive procedure application

This commit is contained in:
2021-05-20 23:18:19 -04:00
parent f4c58cfa02
commit b0bf78a3bd
5 changed files with 92 additions and 21 deletions

View File

@@ -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!("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),
}
}
}

View File

@@ -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] = &['+', '-', '.', '@'];

View File

@@ -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);

View File

@@ -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,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);

58
src/primitives.rs Normal file
View 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)
}