Implement display and string support resolves #10
This commit is contained in:
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/lexer.rs
36
src/lexer.rs
@@ -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();
|
||||||
|
|||||||
@@ -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]),
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user