Implement display and string support resolves #10

This commit is contained in:
2021-05-30 22:49:31 -04:00
parent a7caac30f9
commit 2e67e1220c
5 changed files with 65 additions and 2 deletions

View File

@@ -20,6 +20,10 @@ 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("display"),
Datum::Procedure(primitives::display),
),
], ],
outer: None, outer: None,
} }

View File

@@ -83,6 +83,10 @@ fn interpret_define(args: &Vec<Datum>, env: &mut Env) -> Datum {
} }
} }
fn interpret_cond(_vec: &Vec<Datum>, _env: &mut Env) -> Datum {
Datum::Unspecified
}
fn interpret_begin(vec: &Vec<Datum>, env: &mut Env) -> Datum { fn interpret_begin(vec: &Vec<Datum>, env: &mut Env) -> Datum {
let mut r = Datum::Unspecified; let mut r = Datum::Unspecified;
for i in 1..vec.len() { for i in 1..vec.len() {
@@ -127,16 +131,17 @@ pub fn interpret(exp: &Datum, env: &mut Env) -> Datum {
match exp { match exp {
Boolean(_) => exp.clone(), Boolean(_) => exp.clone(),
Number(_) => exp.clone(), Number(_) => exp.clone(),
Unspecified => Unspecified, String(_) => exp.clone(),
Symbol(_) => environment::lookup_variable_value(exp, env), Symbol(_) => environment::lookup_variable_value(exp, env),
List(v) if has_tag(v, "if") => interpret_if(v, env), List(v) if has_tag(v, "if") => interpret_if(v, env),
List(v) if has_tag(v, "set!") => interpret_set(v, env), List(v) if has_tag(v, "set!") => interpret_set(v, env),
List(v) if has_tag(v, "define") => interpret_define(v, env), List(v) if has_tag(v, "define") => interpret_define(v, env),
List(v) if has_tag(v, "cond") => panic!("cond-not-supported"), List(v) if has_tag(v, "cond") => interpret_cond(v, env),
List(v) if has_tag(v, "let") => panic!("let-not-supported"), List(v) if has_tag(v, "let") => panic!("let-not-supported"),
List(v) if has_tag(v, "begin") => interpret_begin(v, env), List(v) if has_tag(v, "begin") => interpret_begin(v, env),
List(v) if has_tag(v, "quote") => v[1].clone(), List(v) if has_tag(v, "quote") => v[1].clone(),
List(v) => interpret_application(v, env), List(v) => interpret_application(v, env),
Unspecified => Unspecified,
_ => panic!("unknown-expression {:?}", exp), _ => panic!("unknown-expression {:?}", exp),
} }
} }

View File

@@ -3,6 +3,7 @@ pub enum Token {
Identifier(String), Identifier(String),
Boolean(bool), Boolean(bool),
Number(i64), Number(i64),
String(String),
LeftRoundBracket, LeftRoundBracket,
RightRoundBracket, RightRoundBracket,
Quote, Quote,
@@ -33,6 +34,8 @@ fn scan(code: &str, mut ix: usize, mut tokens: Tokens) -> Tokens {
return scan_boolean(code, ix, tokens); return scan_boolean(code, ix, tokens);
} else if c == ';' { } else if c == ';' {
return scan_comment(code, ix, tokens); return scan_comment(code, ix, tokens);
} else if c == '"' {
return scan_string(code, ix, tokens);
} else if c.is_ascii_digit() { } else if c.is_ascii_digit() {
return scan_number(code, ix, tokens); return scan_number(code, ix, tokens);
} else if c.is_ascii_alphabetic() || SPECIAL_INITIAL.contains(&c) { } else if c.is_ascii_alphabetic() || SPECIAL_INITIAL.contains(&c) {
@@ -95,6 +98,39 @@ fn scan_comment(code: &str, mut ix: usize, tokens: Tokens) -> Tokens {
scan(code, ix, tokens) scan(code, ix, tokens)
} }
fn scan_string(code: &str, mut ix: usize, mut tokens: Tokens) -> Tokens {
let mut s = String::new();
let mut chars = code[ix..].chars();
let c = chars.next().unwrap();
assert!(c == '"');
ix += 1;
while let Some(c) = chars.next() {
ix += 1;
if c == '"' {
break;
} else if c == '\\' {
ix += 1;
if let Some(next_c) = chars.next() {
let escaped_c = match next_c {
'n' => '\n',
'"' => '"',
'\\' => '\\',
_ => panic!("SCAN-STRING -- cannot escape {}", next_c),
};
s.push(escaped_c);
} else {
panic!("SCAN-STRING -- found escape at eof")
}
} else {
s.push(c);
}
}
let token = Token::String(s);
tokens.push(token);
scan(code, ix, tokens)
}
fn scan_number(code: &str, mut ix: usize, mut tokens: Tokens) -> Tokens { fn scan_number(code: &str, mut ix: usize, mut tokens: Tokens) -> Tokens {
let start_ix = ix; let start_ix = ix;
let mut chars = code[ix..].chars(); let mut chars = code[ix..].chars();

View File

@@ -6,6 +6,7 @@ use std::cmp::Ordering;
pub enum Datum { pub enum Datum {
Boolean(bool), Boolean(bool),
Number(i64), Number(i64),
String(String),
Symbol(String), Symbol(String),
List(Vec<Datum>), List(Vec<Datum>),
Procedure(fn(Vec<Datum>) -> Datum), Procedure(fn(Vec<Datum>) -> Datum),
@@ -52,6 +53,7 @@ fn parse_datum(tokens: &Tokens, ix: usize) -> (Datum, usize) {
Token::Identifier(s) => (Datum::Symbol(s.to_string()), ix + 1), Token::Identifier(s) => (Datum::Symbol(s.to_string()), ix + 1),
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::String(s) => (Datum::String(s.to_string()), ix + 1),
Token::Quote => parse_quote(tokens, ix + 1), Token::Quote => parse_quote(tokens, 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]),

View File

@@ -1,5 +1,7 @@
use crate::parser::Datum; use crate::parser::Datum;
use crate::parser::Datum::*; use crate::parser::Datum::*;
use std::io;
use std::io::prelude::*;
use std::mem; use std::mem;
pub fn add(mut args: Vec<Datum>) -> Datum { pub fn add(mut args: Vec<Datum>) -> Datum {
@@ -84,3 +86,17 @@ pub fn lt(args: Vec<Datum>) -> Datum {
Boolean(true) Boolean(true)
} }
} }
pub fn display(args: Vec<Datum>) -> Datum {
for i in 1..args.len() {
match &args[i] {
Boolean(b) => print!("{}", b),
Number(n) => print!("{}", n),
String(s) => print!("{}", s),
List(v) => print!("{:?}", v),
_ => panic!("DISPLAY -- cannot-print {:?}", args[1]),
};
}
io::stdout().flush().ok().expect("Could not flush stdout");
Unspecified
}