132 lines
3.6 KiB
Rust
132 lines
3.6 KiB
Rust
use crate::environment::Env;
|
|
use crate::lexer::Token;
|
|
use crate::lexer::Tokens;
|
|
use std::cmp::Ordering;
|
|
use std::fmt;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Datum {
|
|
Boolean(bool),
|
|
Number(i64),
|
|
String(String),
|
|
Symbol(String),
|
|
Pair(Box<(Datum, Datum)>),
|
|
List(Vec<Datum>),
|
|
Primitive(fn(Vec<Datum>) -> Datum),
|
|
Lambda {
|
|
parameters: Vec<Datum>,
|
|
body: Vec<Datum>,
|
|
},
|
|
Procedure {
|
|
parameters: Vec<Datum>,
|
|
body: Vec<Datum>,
|
|
env: Env,
|
|
},
|
|
Unspecified,
|
|
}
|
|
|
|
pub fn make_symbol(s: &str) -> Datum {
|
|
Datum::Symbol(s.to_string())
|
|
}
|
|
|
|
impl Default for Datum {
|
|
fn default() -> Self {
|
|
Datum::Unspecified
|
|
}
|
|
}
|
|
|
|
impl PartialEq for Datum {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(Datum::Boolean(b1), Datum::Boolean(b2)) => b1 == b2,
|
|
(Datum::Number(n1), Datum::Number(n2)) => n1 == n2,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Datum {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Datum::Boolean(true) => write!(f, "#t"),
|
|
Datum::Boolean(false) => write!(f, "#f"),
|
|
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 {
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
match (self, other) {
|
|
(Datum::Boolean(b1), Datum::Boolean(b2)) => Some(b1.cmp(b2)),
|
|
(Datum::Number(n1), Datum::Number(n2)) => Some(n1.cmp(n2)),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Datum {
|
|
pub fn as_str(&self) -> Option<std::string::String> {
|
|
match self {
|
|
Datum::Symbol(s) => Some(s.to_string()),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn parse(tokens: Tokens) -> Datum {
|
|
let (datum, _) = parse_datum(&tokens, 0);
|
|
datum
|
|
}
|
|
|
|
fn parse_datum(tokens: &Tokens, ix: usize) -> (Datum, usize) {
|
|
match &tokens[ix] {
|
|
Token::Identifier(s) => (Datum::Symbol(s.to_string()), ix + 1),
|
|
Token::Boolean(b) => (Datum::Boolean(*b), 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::LeftRoundBracket => parse_list(tokens, ix + 1),
|
|
_ => panic!("Unexpected token {:?}", tokens[ix]),
|
|
}
|
|
}
|
|
|
|
pub fn parse_quote(tokens: &Tokens, ix: usize) -> (Datum, usize) {
|
|
let mut datums = vec![make_symbol("quote")];
|
|
let (datum, ix) = parse_datum(tokens, ix);
|
|
datums.push(datum);
|
|
(Datum::List(datums), ix)
|
|
}
|
|
|
|
pub fn parse_list(tokens: &Tokens, mut ix: usize) -> (Datum, usize) {
|
|
let mut datums = vec![];
|
|
|
|
while ix < tokens.len() && tokens[ix] != Token::RightRoundBracket {
|
|
let (datum, new_ix) = parse_datum(tokens, ix);
|
|
datums.push(datum);
|
|
ix = new_ix;
|
|
}
|
|
if ix == tokens.len() {
|
|
panic!("PARSE_LIST -- missing closing bracket {:?}", tokens)
|
|
}
|
|
|
|
(Datum::List(datums), ix + 1)
|
|
}
|