Implement primitive procedure application
This commit is contained in:
@@ -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 {
|
||||||
|
panic!("The object {:?} is not applicable", args[0])
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
panic!("APPLICATION -- cannot-apply {:?}", exp)
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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] = &['+', '-', '.', '@'];
|
||||||
'+', '-', '.', '@',
|
|
||||||
];
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,14 +28,14 @@ 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]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_list(tokens: &Tokens, mut ix: usize) -> (Datum, usize) {
|
pub fn parse_list(tokens: &Tokens, mut ix: usize) -> (Datum, usize) {
|
||||||
let mut datums = vec![];
|
let mut datums = vec![];
|
||||||
|
|
||||||
// FIXME: will crash when RightRoundBracket is missing
|
// FIXME: will crash when RightRoundBracket is missing
|
||||||
while tokens[ix] != Token::RightRoundBracket {
|
while tokens[ix] != Token::RightRoundBracket {
|
||||||
let (datum, new_ix) = parse_datum(tokens, ix);
|
let (datum, new_ix) = parse_datum(tokens, ix);
|
||||||
datums.push(datum);
|
datums.push(datum);
|
||||||
|
|||||||
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