154 lines
No EOL
3.3 KiB
Rust
154 lines
No EOL
3.3 KiB
Rust
use std::fmt;
|
|
|
|
use crate::Token;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum PreLispValue {
|
|
Nil,
|
|
String(String),
|
|
Var(String),
|
|
Integer(i32),
|
|
Float(f32),
|
|
List(Vec<PreLispValue>, bool), // Values, Quoted
|
|
LispFunction(String, Vec<PreLispValue>),
|
|
}
|
|
|
|
impl fmt::Display for PreLispValue {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
PreLispValue::Nil => write!(f, "nil"),
|
|
PreLispValue::String(str) => write!(f, "{}", str),
|
|
PreLispValue::LispFunction(name, _) => write!(f, "<'{}': Lisp Function>", name),
|
|
PreLispValue::Integer(num) => write!(f, "{}", num),
|
|
PreLispValue::Float(num) => write!(f, "{}", num),
|
|
_ => todo!()
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&str> for PreLispValue {
|
|
fn from(value: &str) -> Self {
|
|
PreLispValue::String(value.to_string())
|
|
}
|
|
}
|
|
impl From<String> for PreLispValue {
|
|
fn from(value: String) -> Self {
|
|
PreLispValue::String(value)
|
|
}
|
|
}
|
|
impl From<i32> for PreLispValue {
|
|
fn from(value: i32) -> Self {
|
|
PreLispValue::Integer(value)
|
|
}
|
|
}
|
|
impl From<f32> for PreLispValue {
|
|
fn from(value: f32) -> Self {
|
|
PreLispValue::Float(value)
|
|
}
|
|
}
|
|
impl From<Vec<PreLispValue>> for PreLispValue {
|
|
fn from(value: Vec<PreLispValue>) -> Self {
|
|
PreLispValue::List(value, false)
|
|
}
|
|
}
|
|
|
|
// TODO: Handle failure
|
|
fn read_exp(open_paren_idx: usize, tokens: &Vec<Token>) -> Option<(Vec<Token>, usize)> /* Option<tokens, close_paren_idx> */ {
|
|
let mut tkns = Vec::new();
|
|
let mut depth = 0;
|
|
|
|
for i in open_paren_idx..tokens.len() {
|
|
match &tokens[i] {
|
|
Token::OpenParen => {
|
|
if depth != 0 {
|
|
tkns.push(Token::OpenParen);
|
|
}
|
|
depth += 1;
|
|
}
|
|
Token::CloseParen => {
|
|
depth -= 1;
|
|
if depth == 0 {
|
|
return Some((tkns, i));
|
|
} else {
|
|
tkns.push(Token::CloseParen)
|
|
}
|
|
}
|
|
token => {
|
|
tkns.push(token.clone());
|
|
}
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn parse_exp(tokens: Vec<Token>, quoted: bool) -> PreLispValue {
|
|
let mut values = Vec::new();
|
|
|
|
if tokens.len() < 1 {
|
|
return PreLispValue::List(values, false);
|
|
}
|
|
|
|
let mut quote_next_list = false;
|
|
let mut unquote_next_list = false;
|
|
|
|
let mut i = 0;
|
|
while i < tokens.len() {
|
|
let tkn = &tokens[i];
|
|
match tkn {
|
|
Token::Quote => {
|
|
quote_next_list = true;
|
|
},
|
|
Token::Unquote => {
|
|
unquote_next_list = true;
|
|
}
|
|
Token::OpenParen => {
|
|
let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap();
|
|
values.push(parse_exp(tkns, if unquote_next_list {false} else {quote_next_list || quoted}));
|
|
i = close_paren_idx;
|
|
quote_next_list = false;
|
|
unquote_next_list = false;
|
|
},
|
|
Token::Identifier(name) => {
|
|
values.push(PreLispValue::Var(name.to_owned()));
|
|
},
|
|
Token::Integer(num) => {
|
|
values.push(PreLispValue::Integer(*num));
|
|
},
|
|
Token::Float(num) => {
|
|
values.push(PreLispValue::Float(*num));
|
|
},
|
|
Token::String(str) => {
|
|
values.push(PreLispValue::String(str.to_owned()));
|
|
},
|
|
Token::CloseParen => {
|
|
panic!("Unexpected closing parenthesis");
|
|
},
|
|
}
|
|
i += 1;
|
|
}
|
|
|
|
PreLispValue::List(values, quoted)
|
|
}
|
|
|
|
pub fn parse(tokens: Vec<Token>) -> Vec<PreLispValue> {
|
|
let mut values = Vec::new();
|
|
|
|
let mut i = 0;
|
|
while i < tokens.len() {
|
|
match &tokens[i] {
|
|
Token::OpenParen => {
|
|
let (tkns, close_paren_idx) = read_exp(i, &tokens).unwrap();
|
|
values.push(parse_exp(tkns, false));
|
|
i = close_paren_idx;
|
|
}
|
|
tkn => {
|
|
// TODO: Include more error data
|
|
panic!("Unexpected token {:?}", tkn);
|
|
}
|
|
}
|
|
i += 1;
|
|
}
|
|
|
|
values
|
|
} |