mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
refactor: simplify list
This commit is contained in:
parent
1859a9c4bb
commit
7040bbaa12
0
src/compile/mod.rs
Normal file
0
src/compile/mod.rs
Normal file
16
src/main.rs
16
src/main.rs
|
@ -1,6 +1,7 @@
|
||||||
use std::{process::exit, fs::read_to_string};
|
use std::{process::exit, fs::read_to_string};
|
||||||
|
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
pub mod compile;
|
||||||
|
|
||||||
const EXECUTABLE_NAME: &str = env!("CARGO_PKG_NAME");
|
const EXECUTABLE_NAME: &str = env!("CARGO_PKG_NAME");
|
||||||
const HELP_MESSAGE: &str = "\
|
const HELP_MESSAGE: &str = "\
|
||||||
|
@ -35,10 +36,19 @@ fn main() {
|
||||||
if args_index < args.len() {
|
if args_index < args.len() {
|
||||||
let file_path: &str = &args[args_index];
|
let file_path: &str = &args[args_index];
|
||||||
let file_content: String = read_to_string(file_path).unwrap();
|
let file_content: String = read_to_string(file_path).unwrap();
|
||||||
let ast = parser::parse(&file_content);
|
|
||||||
for node in ast {
|
let parsed = parser::parse(&file_content);
|
||||||
println!("{:?}", node);
|
let mut ast = Vec::new();
|
||||||
|
for node in parsed {
|
||||||
|
match node {
|
||||||
|
Ok(node) => { ast.push(node); },
|
||||||
|
Err(error) => {
|
||||||
|
eprintln!("ERROR: {}", error);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
println!("{:#?}", ast);
|
||||||
} else {
|
} else {
|
||||||
println!("No file provided.");
|
println!("No file provided.");
|
||||||
display_help(1);
|
display_help(1);
|
||||||
|
|
100
src/parser.rs
100
src/parser.rs
|
@ -2,25 +2,7 @@
|
||||||
// brundonsmith/rust_lisp (https://github.com/brundonsmith/rust_lisp)
|
// brundonsmith/rust_lisp (https://github.com/brundonsmith/rust_lisp)
|
||||||
// go check them out!
|
// go check them out!
|
||||||
|
|
||||||
use std::{ rc::Rc, cell::RefCell };
|
use std::{ rc::Rc, fmt };
|
||||||
|
|
||||||
/// A List in Sexpr
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct List {
|
|
||||||
pub value: Option<Rc<RefCell<Cons>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl List {
|
|
||||||
pub const NIL: List = List { value: None };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cons -> (car, [cdr])
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Cons {
|
|
||||||
pub car: Value,
|
|
||||||
pub cdr: Option<Rc<RefCell<Cons>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
|
@ -30,11 +12,9 @@ pub enum Value {
|
||||||
Int(i64), Float(f64),
|
Int(i64), Float(f64),
|
||||||
|
|
||||||
String(String), Symbol(String),
|
String(String), Symbol(String),
|
||||||
List(List),
|
List(Rc<Value>, Rc<Vec<Value>>),
|
||||||
}
|
|
||||||
|
|
||||||
impl Value {
|
Nil,
|
||||||
pub const NIL: Value = Value::List(List::NIL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -48,36 +28,25 @@ impl Tree {
|
||||||
match self {
|
match self {
|
||||||
Tree::Atom { atom, quote } => {
|
Tree::Atom { atom, quote } => {
|
||||||
if quote {
|
if quote {
|
||||||
Value::List(List {
|
Value::List(
|
||||||
value: Some(Rc::new(RefCell::new(Cons {
|
Rc::new(Value::Symbol(String::from("quote"))),
|
||||||
car: Value::Symbol(String::from("quote")),
|
Rc::new(vec![atom])
|
||||||
cdr: Some(Rc::new(RefCell::new(Cons {
|
)
|
||||||
car: atom, // car vroom vroom 🚗
|
|
||||||
cdr: None,
|
|
||||||
}))),
|
|
||||||
}))),
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
atom
|
atom
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Tree::List { vec, quote } => {
|
Tree::List { vec, quote } => {
|
||||||
let list = Value::List(
|
let list = Value::List(
|
||||||
vec.into_iter()
|
Rc::new(vec[0].clone().into_expr()),
|
||||||
.map(|tree| tree.into_expr())
|
Rc::new(vec[1..].iter().map(|a| a.clone().into_expr()).collect())
|
||||||
.collect::<List>(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if quote {
|
if quote {
|
||||||
Value::List(List {
|
Value::List(
|
||||||
value: Some(Rc::new(RefCell::new(Cons {
|
Rc::new(Value::Symbol(String::from("quote"))),
|
||||||
car: Value::Symbol(String::from("quote")),
|
Rc::new(vec![list])
|
||||||
cdr: Some(Rc::new(RefCell::new(Cons {
|
)
|
||||||
car: list, // car vroom vroom 🚗
|
|
||||||
cdr: None,
|
|
||||||
}))),
|
|
||||||
}))),
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
@ -86,30 +55,6 @@ impl Tree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<Value> for List {
|
|
||||||
fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
|
|
||||||
let mut list = List { value: None };
|
|
||||||
let mut tail: Option<Rc<RefCell<Cons>>> = None;
|
|
||||||
|
|
||||||
for value in iter {
|
|
||||||
let new_cons = Rc::new(RefCell::new(Cons {
|
|
||||||
car: value,
|
|
||||||
cdr: None,
|
|
||||||
}));
|
|
||||||
|
|
||||||
if list.value.is_none() {
|
|
||||||
list.value = Some(new_cons.clone());
|
|
||||||
} else if let Some(ref tail_cons) = tail {
|
|
||||||
tail_cons.as_ref().borrow_mut().cdr = Some(new_cons.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
tail = Some(new_cons);
|
|
||||||
}
|
|
||||||
|
|
||||||
list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Start tokenizer ---
|
// --- Start tokenizer ---
|
||||||
|
|
||||||
const SPECIAL_CHARS: [&str; 4] = ["(", ")", "'", "..."];
|
const SPECIAL_CHARS: [&str; 4] = ["(", ")", "'", "..."];
|
||||||
|
@ -205,16 +150,29 @@ pub fn tokenize(src: &str) -> impl Iterator<Item = (&str, (usize, usize))> {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParseErrorKind {
|
pub enum ParseErrorKind {
|
||||||
UnexpectedParenOpen,
|
|
||||||
UnexpectedParenClose,
|
UnexpectedParenClose,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ParseErrorKind {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ParseErrorKind::UnexpectedParenClose => write!(f, "Unexpected ')'"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParseError {
|
pub struct ParseError {
|
||||||
pub kind: ParseErrorKind,
|
pub kind: ParseErrorKind,
|
||||||
pub pos: (usize, usize),
|
pub pos: (usize, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ParseError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{} at {}", self.kind, self.pos.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ParseError {
|
impl ParseError {
|
||||||
fn new(kind: ParseErrorKind, pos: (usize, usize)) -> Self {
|
fn new(kind: ParseErrorKind, pos: (usize, usize)) -> Self {
|
||||||
ParseError { kind, pos }
|
ParseError { kind, pos }
|
||||||
|
@ -266,7 +224,7 @@ fn read<'a>(
|
||||||
if let Tree::List { vec, quote } = &finished {
|
if let Tree::List { vec, quote } = &finished {
|
||||||
if vec.is_empty() {
|
if vec.is_empty() {
|
||||||
finished = Tree::Atom {
|
finished = Tree::Atom {
|
||||||
atom: Value::NIL,
|
atom: Value::Nil,
|
||||||
quote: *quote,
|
quote: *quote,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -305,7 +263,7 @@ fn read_atom(token: &str) -> Value {
|
||||||
match lower.as_str() {
|
match lower.as_str() {
|
||||||
"true" => Value::True,
|
"true" => Value::True,
|
||||||
"false" => Value::False,
|
"false" => Value::False,
|
||||||
"nil" => Value::NIL,
|
"nil" => Value::Nil,
|
||||||
_ => {
|
_ => {
|
||||||
// Parse number
|
// Parse number
|
||||||
if let Ok(int) = token.parse::<i64>() { Value::Int(int) }
|
if let Ok(int) = token.parse::<i64>() { Value::Int(int) }
|
||||||
|
|
Loading…
Reference in a new issue