mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
feat: quoting
This commit is contained in:
parent
b3396832fe
commit
c1975a40af
|
@ -93,6 +93,10 @@ impl Compiler {
|
|||
result.push(Instr::Not);
|
||||
result.push(Instr::JumpIfFalse { to: -jump_length });
|
||||
},
|
||||
"quote" => {
|
||||
let value = quoted_sexpr(&cdr[0])?;
|
||||
result.push(Instr::Push { value });
|
||||
}
|
||||
_ => {
|
||||
result.append(&mut self.compile_intrinsic(call, &cdr)?);
|
||||
}
|
||||
|
@ -217,6 +221,25 @@ impl Compiler {
|
|||
}
|
||||
}
|
||||
|
||||
fn quoted_sexpr(cdr: &Sexpr) -> Result<Type, String> {
|
||||
match cdr {
|
||||
Cons(car, cdr) => {
|
||||
let mut vec = Vec::new();
|
||||
vec.push(quoted_sexpr(car)?);
|
||||
for item in cdr {
|
||||
vec.push(quoted_sexpr(item)?);
|
||||
}
|
||||
Ok(Type::Cons(vec))
|
||||
},
|
||||
Symbol(ref s) => Ok(Type::String(s.to_string())),
|
||||
Str(ref s) => Ok(Type::String(s.to_string())),
|
||||
Int(ref i) => Ok(Type::Int(*i)),
|
||||
Float(ref f) => Ok(Type::Float(*f)),
|
||||
Boolean(ref b) => Ok(Type::Boolean(*b)),
|
||||
Nil => Ok(Type::Null),
|
||||
}
|
||||
}
|
||||
|
||||
fn len(vec: &Vec<Instr>) -> usize {
|
||||
let mut result = 0;
|
||||
for i in vec {
|
||||
|
|
|
@ -9,6 +9,7 @@ pub enum Sexpr {
|
|||
Nil,
|
||||
}
|
||||
|
||||
// Used for error displaying
|
||||
impl std::fmt::Display for Sexpr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
|
@ -58,7 +59,10 @@ impl Parser {
|
|||
match self.peek() {
|
||||
Some(s) => match s.as_str() {
|
||||
")" => Err(format!("Unexpected ')' at position {}", self.position)),
|
||||
// TODO: Handle quote and that stuff.
|
||||
"'" => {
|
||||
self.next();
|
||||
Ok(Cons(Box::new(Symbol("quote".to_string())), vec![self.parse()?]))
|
||||
},
|
||||
"(" => self.parse_sequence(")"),
|
||||
_ => self.parse_atom(),
|
||||
}
|
||||
|
@ -92,12 +96,12 @@ impl Parser {
|
|||
"true" | "True" => Ok(Boolean(true)),
|
||||
"false" | "False" => Ok(Boolean(false)),
|
||||
_ => {
|
||||
if Regex::new(r#"[+-]?([0-9]*[.])?[0-9]+"#).unwrap().is_match(&token) {
|
||||
Ok(Int(token.parse().unwrap()))
|
||||
if Regex::new(r#""(?:\\.|[^\\"])*""#).unwrap().is_match(&token) {
|
||||
Ok(Str(token[1..token.len() - 1].to_string()))
|
||||
} else if Regex::new(r#"[+-]?([0-9]*[.])?[0-9]+"#).unwrap().is_match(&token) {
|
||||
Ok(Float(token.parse().unwrap()))
|
||||
} else if Regex::new(r#""(?:\\.|[^\\"])*""#).unwrap().is_match(&token) {
|
||||
Ok(Str(token[1..token.len() - 1].to_string()))
|
||||
Ok(Int(token.parse().unwrap()))
|
||||
} else if Regex::new(r#"[+-]?([0-9]*[.])?[0-9]+"#).unwrap().is_match(&token) {
|
||||
Ok(Float(token.parse().unwrap()))
|
||||
} else {
|
||||
Ok(Symbol(token))
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use regex::Regex;
|
|||
|
||||
use crate::vm::{instr::*, types::Type};
|
||||
|
||||
const REGEX: &str = r###"\([^)]*\)|[^\s\$";]+|"[^"]*"|;.*"###;
|
||||
const REGEX: &str = r###"\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)|[^\s\$";]+|"[^"]*"|;.*"###;
|
||||
|
||||
macro_rules! value { ($s:expr) => { $s.parse::<Type>().unwrap() }; }
|
||||
macro_rules! register { ($s:expr) => { $s.parse::<Register>().unwrap() }; }
|
||||
|
|
|
@ -28,26 +28,20 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fmt(&self) -> String {
|
||||
pub fn print(&self) -> String {
|
||||
match self {
|
||||
Type::Null => "null".to_string(),
|
||||
Type::Int(i) => i.to_string(),
|
||||
Type::Float(f) => f.to_string(),
|
||||
Type::Boolean(b) => match b {
|
||||
true => "true".to_string(),
|
||||
false => "false".to_string(),
|
||||
},
|
||||
Type::String(s) => s.clone(),
|
||||
Type::Cons(v) => {
|
||||
let mut s = String::new();
|
||||
s.push('(');
|
||||
for (i, t) in v.iter().enumerate() {
|
||||
if i != 0 { s.push(','); }
|
||||
s.push_str(&t.fmt());
|
||||
if i != 0 { s.push(' '); }
|
||||
s.push_str(&t.print().to_string());
|
||||
}
|
||||
s.push(')');
|
||||
s
|
||||
}
|
||||
},
|
||||
Type::String(s) => s.trim().to_string(),
|
||||
_ => self.clone().to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +121,16 @@ impl Display for Type {
|
|||
Type::Float(fl) => write!(f, "{}", fl),
|
||||
Type::Boolean(b) => write!(f, "{}", b),
|
||||
Type::String(s) => write!(f, "\"{}\"", s),
|
||||
Type::Cons(v) => {
|
||||
let mut s = String::new();
|
||||
s.push('(');
|
||||
for (i, t) in v.iter().enumerate() {
|
||||
if i != 0 { s.push(' '); }
|
||||
s.push_str(&t.to_string());
|
||||
}
|
||||
s.push(')');
|
||||
write!(f, "{}", s)
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -140,14 +144,24 @@ impl FromStr for Type {
|
|||
"true" => Ok(Type::Boolean(true)),
|
||||
"false" => Ok(Type::Boolean(false)),
|
||||
_ => {
|
||||
if s.starts_with("(") {
|
||||
let elems = s[1..s.len() - 1]
|
||||
.split(',')
|
||||
.collect::<Vec<&str>>()
|
||||
.iter()
|
||||
.map(|s| s.trim().parse::<Type>())
|
||||
.collect::<Result<Vec<Type>, Self::Err>>()?;
|
||||
Ok(Type::Cons(elems))
|
||||
if s.starts_with("(") && s.ends_with(")") {
|
||||
let mut v = Vec::new();
|
||||
let mut s = s[1..s.len() - 1].to_string();
|
||||
// TODO: This is pretty messy :(
|
||||
while !s.is_empty() {
|
||||
let mut i = 0;
|
||||
while i < s.len() && s.chars().nth(i).unwrap().is_whitespace() { i += 1; }
|
||||
s = s[i..s.len()].to_string();
|
||||
if s.is_empty() { break; }
|
||||
|
||||
let mut j = 0;
|
||||
while j < s.len() && !s.chars().nth(j).unwrap().is_whitespace() { j += 1; }
|
||||
let t = &s[0..j];
|
||||
|
||||
v.push(t.parse::<Type>()?);
|
||||
s = s[j..s.len()].to_string();
|
||||
}
|
||||
Ok(Type::Cons(v))
|
||||
} else {
|
||||
let i = s.parse::<i64>();
|
||||
if i.is_ok() {
|
||||
|
|
|
@ -209,7 +209,7 @@ impl VM {
|
|||
match function.as_str() {
|
||||
"print" => {
|
||||
let value = self.stack.pop().unwrap();
|
||||
println!("{}", value.fmt());
|
||||
println!("{}", value.print());
|
||||
return Ok(());
|
||||
},
|
||||
"read" => {
|
||||
|
@ -220,7 +220,7 @@ impl VM {
|
|||
Ok(())
|
||||
},
|
||||
"slurp" => {
|
||||
let file_name = self.stack.pop().unwrap().fmt();
|
||||
let file_name = self.stack.pop().unwrap().to_string();
|
||||
let mut result = String::new();
|
||||
match File::open(file_name).and_then(|mut f| f.read_to_string(&mut result)) {
|
||||
Ok(_) => Ok(self.stack.push(Type::String(result))),
|
||||
|
|
6
example/quote.blsp
Normal file
6
example/quote.blsp
Normal file
|
@ -0,0 +1,6 @@
|
|||
(fun main (do
|
||||
(print (quote (a b c)))
|
||||
(print (quote (+ 1 (+ 2 "3"))))
|
||||
(print (quote a))
|
||||
(print (quote "a"))
|
||||
))
|
Loading…
Reference in a new issue