Implement cons, car, cdr, null?, pair? resolves #1
This commit is contained in:
@@ -21,6 +21,12 @@ pub fn get_global_environment<'a>() -> Env<'a> {
|
|||||||
(make_symbol("-"), Datum::Procedure(primitives::sub)),
|
(make_symbol("-"), Datum::Procedure(primitives::sub)),
|
||||||
(make_symbol("="), Datum::Procedure(primitives::eq)),
|
(make_symbol("="), Datum::Procedure(primitives::eq)),
|
||||||
(make_symbol("<"), Datum::Procedure(primitives::lt)),
|
(make_symbol("<"), Datum::Procedure(primitives::lt)),
|
||||||
|
(make_symbol("list"), Datum::Procedure(primitives::list)),
|
||||||
|
(make_symbol("cons"), Datum::Procedure(primitives::cons)),
|
||||||
|
(make_symbol("car"), Datum::Procedure(primitives::car)),
|
||||||
|
(make_symbol("cdr"), Datum::Procedure(primitives::cdr)),
|
||||||
|
(make_symbol("pair?"), Datum::Procedure(primitives::pair)),
|
||||||
|
(make_symbol("null?"), Datum::Procedure(primitives::null)),
|
||||||
(
|
(
|
||||||
make_symbol("display"),
|
make_symbol("display"),
|
||||||
Datum::Procedure(primitives::display),
|
Datum::Procedure(primitives::display),
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ fn is_true(exp: &Datum) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_tag(vec: &Vec<Datum>, tag: &str) -> bool {
|
pub fn has_tag(vec: &Vec<Datum>, tag: &str) -> bool {
|
||||||
if vec.len() == 0 {
|
if vec.len() == 0 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -127,6 +127,7 @@ fn interpret_application(vec: &Vec<Datum>, env: &mut Env) -> Datum {
|
|||||||
for i in 0..(seq.len() - 1) {
|
for i in 0..(seq.len() - 1) {
|
||||||
interpret(&seq[i], &mut new_env);
|
interpret(&seq[i], &mut new_env);
|
||||||
}
|
}
|
||||||
|
// XXX: not tail-call optimized
|
||||||
interpret(&seq[seq.len() - 1], &mut new_env)
|
interpret(&seq[seq.len() - 1], &mut new_env)
|
||||||
} else {
|
} else {
|
||||||
panic!("INTERPRET-APPLICATION -- no-list {:?}", lambda_body)
|
panic!("INTERPRET-APPLICATION -- no-list {:?}", lambda_body)
|
||||||
|
|||||||
@@ -171,4 +171,4 @@ const SPECIAL_INITIAL: &[char] = &[
|
|||||||
'!', '$', '%', '&', '*', '/', ':', '<', '=', '>', '?', '^', '_', '~', '+', '-',
|
'!', '$', '%', '&', '*', '/', ':', '<', '=', '>', '?', '^', '_', '~', '+', '-',
|
||||||
];
|
];
|
||||||
|
|
||||||
const SPECIAL_SUBSEQUENT: &[char] = &['+', '-', '.', '@', '!'];
|
const SPECIAL_SUBSEQUENT: &[char] = &['+', '-', '.', '@', '!', '?'];
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ fn main() {
|
|||||||
// let scm_code = "(begin (define (f n) (if (= n 1) 1 (* n (f (- n 1))))) (f 10))";
|
// let scm_code = "(begin (define (f n) (if (= n 1) 1 (* n (f (- n 1))))) (f 10))";
|
||||||
let scm_code = "";
|
let scm_code = "";
|
||||||
|
|
||||||
if scm_code.len() > 0 {
|
if args.len() == 2 {
|
||||||
interpret_code(scm_code);
|
|
||||||
} else if args.len() == 2 {
|
|
||||||
let arg_path = Path::new(&args[1]);
|
let arg_path = Path::new(&args[1]);
|
||||||
interpret_file(arg_path);
|
interpret_file(arg_path);
|
||||||
|
} else if scm_code.len() > 0 {
|
||||||
|
interpret_code(scm_code);
|
||||||
} else {
|
} else {
|
||||||
repl();
|
repl();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::lexer::Token;
|
use crate::lexer::Token;
|
||||||
use crate::lexer::Tokens;
|
use crate::lexer::Tokens;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Datum {
|
pub enum Datum {
|
||||||
@@ -8,6 +9,7 @@ pub enum Datum {
|
|||||||
Number(i64),
|
Number(i64),
|
||||||
String(String),
|
String(String),
|
||||||
Symbol(String),
|
Symbol(String),
|
||||||
|
Pair(Box<(Datum, Datum)>),
|
||||||
List(Vec<Datum>),
|
List(Vec<Datum>),
|
||||||
Procedure(fn(Vec<Datum>) -> Datum),
|
Procedure(fn(Vec<Datum>) -> Datum),
|
||||||
Unspecified,
|
Unspecified,
|
||||||
@@ -33,6 +35,32 @@ impl PartialEq for Datum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Datum {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Datum::Boolean(b) => write!(f, "{}", b),
|
||||||
|
Datum::Number(n) => write!(f, "{}", n),
|
||||||
|
Datum::Symbol(s) => write!(f, "{}", s),
|
||||||
|
Datum::String(s) => write!(f, "{}", s),
|
||||||
|
Datum::Pair(p) => write!(f, "({} . {})", p.0, p.1),
|
||||||
|
Datum::List(v) => {
|
||||||
|
let mut s = String::new();
|
||||||
|
s.push_str("(");
|
||||||
|
for e in v {
|
||||||
|
let es = format!("{} ", e);
|
||||||
|
if es != "list " {
|
||||||
|
s.push_str(&es);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.pop(); // remove last space
|
||||||
|
s.push_str(")");
|
||||||
|
write!(f, "{}", s)
|
||||||
|
}
|
||||||
|
_ => panic!("DISPLAY -- cannot print {:?}", self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialOrd for Datum {
|
impl PartialOrd for Datum {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use crate::interpreter::has_tag;
|
||||||
|
use crate::parser::make_symbol;
|
||||||
use crate::parser::Datum;
|
use crate::parser::Datum;
|
||||||
use crate::parser::Datum::*;
|
use crate::parser::Datum::*;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -89,14 +91,91 @@ pub fn lt(args: Vec<Datum>) -> Datum {
|
|||||||
|
|
||||||
pub fn display(args: Vec<Datum>) -> Datum {
|
pub fn display(args: Vec<Datum>) -> Datum {
|
||||||
for i in 1..args.len() {
|
for i in 1..args.len() {
|
||||||
match &args[i] {
|
print!("{}", args[i]);
|
||||||
Boolean(b) => print!("{}", b),
|
|
||||||
Number(n) => print!("{}", n),
|
|
||||||
String(s) => print!("{}", s),
|
|
||||||
List(v) => print!("{:?}", v),
|
|
||||||
_ => panic!("DISPLAY -- cannot-print {:?}", args[i]),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
io::stdout().flush().ok().expect("Could not flush stdout");
|
io::stdout().flush().ok().expect("Could not flush stdout");
|
||||||
Unspecified
|
Unspecified
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn list(mut args: Vec<Datum>) -> Datum {
|
||||||
|
args[0] = make_symbol("list");
|
||||||
|
Datum::List(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cons(mut args: Vec<Datum>) -> Datum {
|
||||||
|
if args.len() != 3 {
|
||||||
|
panic!("CONS -- two args expected {:?}", args);
|
||||||
|
}
|
||||||
|
let a = std::mem::take(&mut args[1]);
|
||||||
|
let b = std::mem::take(&mut args[2]);
|
||||||
|
match b {
|
||||||
|
List(b_vec) if has_tag(&b_vec, "list") => {
|
||||||
|
let mut r_vec = vec![make_symbol("list"), a];
|
||||||
|
r_vec.append(&mut b_vec[1..].to_vec());
|
||||||
|
Datum::List(r_vec)
|
||||||
|
}
|
||||||
|
_ => Datum::Pair(Box::new((a, b))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn car(mut args: Vec<Datum>) -> Datum {
|
||||||
|
if args.len() != 2 {
|
||||||
|
panic!("CAR -- expected a single arg {:?}", args);
|
||||||
|
}
|
||||||
|
let a = std::mem::take(&mut args[1]);
|
||||||
|
match a {
|
||||||
|
List(mut v) if has_tag(&v, "list") => std::mem::take(&mut v[1]),
|
||||||
|
Pair(p) => p.0,
|
||||||
|
_ => panic!("CAR -- could not get car {:?}", a),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cdr(mut args: Vec<Datum>) -> Datum {
|
||||||
|
if args.len() != 2 {
|
||||||
|
panic!("CDR -- expected a single arg {:?}", args);
|
||||||
|
}
|
||||||
|
let a = std::mem::take(&mut args[1]);
|
||||||
|
match a {
|
||||||
|
List(v) if has_tag(&v, "list") => {
|
||||||
|
let mut v_cdr = v[1..].to_vec();
|
||||||
|
v_cdr[0] = make_symbol("list");
|
||||||
|
List(v_cdr)
|
||||||
|
}
|
||||||
|
Pair(p) => p.1,
|
||||||
|
_ => panic!("CAR -- could not get car {:?}", a),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pair(args: Vec<Datum>) -> Datum {
|
||||||
|
if args.len() != 2 {
|
||||||
|
panic!("PAIR? -- expected a single arg {:?}", args);
|
||||||
|
}
|
||||||
|
match &args[1] {
|
||||||
|
List(v) if has_tag(&v, "list") => {
|
||||||
|
if v.len() == 1 {
|
||||||
|
Boolean(false)
|
||||||
|
} else {
|
||||||
|
Boolean(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Pair(_) => Boolean(true),
|
||||||
|
_ => Boolean(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn null(args: Vec<Datum>) -> Datum {
|
||||||
|
if args.len() != 2 {
|
||||||
|
panic!("PAIR? -- expected a single arg {:?}", args);
|
||||||
|
}
|
||||||
|
match &args[1] {
|
||||||
|
List(v) if has_tag(&v, "list") => {
|
||||||
|
if v.len() == 1 {
|
||||||
|
Boolean(true)
|
||||||
|
} else {
|
||||||
|
Boolean(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Pair(_) => Boolean(false),
|
||||||
|
_ => Boolean(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user