Implementing new types

- nil symbols
- Bool
- Vectors
- Maps
This commit is contained in:
teo3300
2023-06-06 16:33:01 +02:00
parent 13790d0864
commit 703b6888b5
4 changed files with 64 additions and 33 deletions

View File

@ -2,8 +2,10 @@ use crate::types::MalType;
pub fn pr_str(ast: &MalType) -> String {
match ast {
MalType::Nil => "nil".to_string(),
MalType::Symbol(sym) => sym.to_string(),
MalType::Integer(val) => val.to_string(),
MalType::Bool(val) => val.to_string(),
MalType::List(el) => format!(
"({})",
el.iter()
@ -11,5 +13,20 @@ pub fn pr_str(ast: &MalType) -> String {
.collect::<Vec<String>>()
.join(" ")
),
// This is truly horrible
MalType::Vector(el) => format!(
"[{}]",
el.iter()
.map(|sub| pr_str(sub))
.collect::<Vec<String>>()
.join(" ")
),
MalType::Map(el) => format!(
"{{{}}}",
el.iter()
.map(|sub| vec![pr_str(sub.0), pr_str(sub.1)].join(" "))
.collect::<Vec<String>>()
.join(" ")
),
}
}

View File

@ -1,4 +1,4 @@
use std::collections::VecDeque;
use std::collections::{BTreeMap, VecDeque};
use crate::types::MalType;
@ -8,6 +8,9 @@ pub struct Reader {
tokens: VecDeque<String>,
}
// TODO: instead of panic on missing ")" try implementing a multi line parsing
// Status on return should always be The last element of the last opened lists
// (append to the "last" list) while traversing
const PAREN_ERROR: &str =
"Looks like you reached a dead end, did you perhaps miss any \")\" or left some extra \"(\"?";
@ -38,21 +41,18 @@ impl Reader {
/// Accumulates results into a MalList
/// NOTE: `read_list` calls `read_form` -> enable recursion
/// (lists can contains other lists)
fn read_list(&mut self) -> MalType {
MalType::List(
// Iterate over the the list
std::iter::from_fn(|| match self.peek() {
// consume "(" and return
")" => {
self.next();
None
fn read_list(&mut self, terminator: &str) -> Vec<MalType> {
std::iter::from_fn(|| match self.peek() {
")" | "]" | "}" => {
if terminator != self.peek() {
panic!("Unexpected token: {}", self.peek())
}
// Add read the token recursively
_ => Some(self.read_form()),
})
// create vector to return
.collect(),
)
self.next();
None
}
_ => Some(self.read_form()),
})
.collect()
}
/// Read atomic token and return appropriate scalar ()
@ -64,7 +64,10 @@ impl Reader {
Ok(value) => MalType::Integer(value),
// Otherwise assign the symbol
Err(_) => match token.as_str() {
")" => panic!("Invalid token \")\""),
")" | "]" | "}" => panic!("Lone parenthesis {}", token),
"false" => MalType::Bool(false),
"true" => MalType::Bool(true),
"nil" => MalType::Nil,
_ => MalType::Symbol(token),
},
}
@ -80,7 +83,24 @@ impl Reader {
// Consume "(" and parse list
"(" => {
self.next();
self.read_list()
MalType::List(self.read_list(")"))
}
"[" => {
self.next();
MalType::Vector(self.read_list("]"))
}
"{" => {
self.next();
// fallback to C mode for now 😎
let list = self.read_list("}");
if list.len() % 2 != 0 {
panic!("Missing Map element")
}
let mut map = BTreeMap::new();
for i in (0..list.len()).step_by(2) {
map.insert(list[i].clone(), list[i + 1].clone());
}
MalType::Map(map)
}
// read atomically
_ => self.read_atom(),
@ -88,24 +108,10 @@ impl Reader {
}
}
#[allow(dead_code)]
fn pretty_print(ast: &MalType, base: usize) {
print!("{}", "".repeat(base));
match ast {
MalType::Symbol(sym) => println!("Sym: {}", sym),
MalType::Integer(val) => println!("Int: {}", val),
MalType::List(vec) => {
println!("List: ");
for el in vec {
pretty_print(el, base + 1);
}
}
}
}
/// Call `tokenize` on a string
/// Create anew Reader with the tokens
/// Call read_from with the reader instance
/// TODO: catch errors
pub fn read_str(input: &str) -> MalType {
let ast = Reader::new(tokenize(input)).read_form();
// pretty_print(&ast, 0);

View File

@ -17,6 +17,7 @@ fn READ(input: &str) -> MalType {
#[allow(non_snake_case)]
/// Evaluate the generated ast
fn EVAL(ast: MalType) -> MalType {
println!("{:#?}", ast);
ast
}

View File

@ -1,9 +1,16 @@
// TODO: use enums for MalTypes
use std::collections::BTreeMap;
// All Mal types should inherit from this
#[derive(Debug)]
#[derive(Debug, Ord, Eq, PartialEq, PartialOrd, Clone)]
pub enum MalType {
List(Vec<MalType>),
Vector(Vec<MalType>),
// HashMap cannot implement Hash
Map(BTreeMap<MalType, MalType>),
Symbol(String),
Integer(i32),
Bool(bool),
Nil,
}