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;
use crate::parser::Datum::*; use crate::parser::Datum::*;
use crate::primitives::*;
fn add(args: Vec<Datum>) -> Datum { use std::mem;
Number(42)
}
fn lookup_variable_value(exp: Datum) -> Datum { fn lookup_variable_value(exp: Datum) -> Datum {
if let Symbol(string) = exp { if let Symbol(string) = exp {
match string.as_str() { match string.as_str() {
"+" => Procedure(add), "+" => Procedure(add),
_ => panic!("unbound-variable {:?}", string) "*" => Procedure(mul),
"-" => Procedure(sub),
_ => panic!("unbound-variable {:?}", string),
} }
} else { } else {
panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp) panic!("LOOKUP-VARIABLE-VALUE -- not-a-symbol {:?}", exp)
@@ -18,9 +18,19 @@ fn lookup_variable_value(exp: Datum) -> Datum {
fn application(exp: Datum) -> Datum { fn application(exp: Datum) -> Datum {
if let List(vector) = exp { 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 { } 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, Boolean(_) | Number(_) => exp,
Symbol(_) => lookup_variable_value(exp), Symbol(_) => lookup_variable_value(exp),
List(_) => application(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" => { "#t" => {
let token = Token::Boolean(true); let token = Token::Boolean(true);
tokens.push(token); tokens.push(token);
}, }
"#f" => { "#f" => {
let token = Token::Boolean(false); let token = Token::Boolean(false);
tokens.push(token); tokens.push(token);
} }
_ => panic!("Expected boolean but got {}", c) _ => panic!("Expected boolean but got {}", c),
} }
return scan(code, ix + 2, tokens); 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 lexer;
mod parser; mod parser;
mod interpreter; mod primitives;
fn main() { fn main() {
// let scm_code = "(+ a (* 32 b) c #t #f)"; // 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 tokens = lexer::read(scm_code);
let datum = parser::parse(tokens); let datum = parser::parse(tokens);
let result = interpreter::interpret(datum); let result = interpreter::interpret(datum);

View File

@@ -1,8 +1,6 @@
use crate::lexer::Token; use crate::lexer::Token;
use crate::lexer::Tokens; use crate::lexer::Tokens;
#[derive(Debug)] #[derive(Debug)]
pub enum Datum { pub enum Datum {
Boolean(bool), Boolean(bool),
@@ -10,6 +8,13 @@ pub enum Datum {
Symbol(String), Symbol(String),
List(Vec<Datum>), List(Vec<Datum>),
Procedure(fn(Vec<Datum>) -> Datum), Procedure(fn(Vec<Datum>) -> Datum),
None,
}
impl Default for Datum {
fn default() -> Self {
Datum::None
}
} }
pub fn parse(tokens: Tokens) -> Datum { 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::Boolean(b) => (Datum::Boolean(*b), ix + 1),
Token::Number(n) => (Datum::Number(*n), ix + 1), Token::Number(n) => (Datum::Number(*n), ix + 1),
Token::LeftRoundBracket => parse_list(tokens, 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
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)
}