schemers/src/parser.rs

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)
}