1
1
Fork 0
mirror of https://github.com/azur1s/bobbylisp.git synced 2024-10-16 02:37:40 -05:00

feat: quoting

This commit is contained in:
Natapat Samutpong 2022-02-06 17:14:15 +07:00
parent b3396832fe
commit c1975a40af
6 changed files with 76 additions and 29 deletions

View file

@ -93,6 +93,10 @@ impl Compiler {
result.push(Instr::Not); result.push(Instr::Not);
result.push(Instr::JumpIfFalse { to: -jump_length }); 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)?); 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 { fn len(vec: &Vec<Instr>) -> usize {
let mut result = 0; let mut result = 0;
for i in vec { for i in vec {

View file

@ -9,6 +9,7 @@ pub enum Sexpr {
Nil, Nil,
} }
// Used for error displaying
impl std::fmt::Display for Sexpr { impl std::fmt::Display for Sexpr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {
@ -58,7 +59,10 @@ impl Parser {
match self.peek() { match self.peek() {
Some(s) => match s.as_str() { Some(s) => match s.as_str() {
")" => Err(format!("Unexpected ')' at position {}", self.position)), ")" => 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_sequence(")"),
_ => self.parse_atom(), _ => self.parse_atom(),
} }
@ -92,12 +96,12 @@ impl Parser {
"true" | "True" => Ok(Boolean(true)), "true" | "True" => Ok(Boolean(true)),
"false" | "False" => Ok(Boolean(false)), "false" | "False" => Ok(Boolean(false)),
_ => { _ => {
if Regex::new(r#"[+-]?([0-9]*[.])?[0-9]+"#).unwrap().is_match(&token) { if Regex::new(r#""(?:\\.|[^\\"])*""#).unwrap().is_match(&token) {
Ok(Int(token.parse().unwrap())) Ok(Str(token[1..token.len() - 1].to_string()))
} else if Regex::new(r#"[+-]?([0-9]*[.])?[0-9]+"#).unwrap().is_match(&token) { } else if Regex::new(r#"[+-]?([0-9]*[.])?[0-9]+"#).unwrap().is_match(&token) {
Ok(Float(token.parse().unwrap())) Ok(Int(token.parse().unwrap()))
} else if Regex::new(r#""(?:\\.|[^\\"])*""#).unwrap().is_match(&token) { } else if Regex::new(r#"[+-]?([0-9]*[.])?[0-9]+"#).unwrap().is_match(&token) {
Ok(Str(token[1..token.len() - 1].to_string())) Ok(Float(token.parse().unwrap()))
} else { } else {
Ok(Symbol(token)) Ok(Symbol(token))
} }

View file

@ -2,7 +2,7 @@ use regex::Regex;
use crate::vm::{instr::*, types::Type}; 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! value { ($s:expr) => { $s.parse::<Type>().unwrap() }; }
macro_rules! register { ($s:expr) => { $s.parse::<Register>().unwrap() }; } macro_rules! register { ($s:expr) => { $s.parse::<Register>().unwrap() }; }

View file

@ -28,26 +28,20 @@ impl Type {
} }
} }
pub fn fmt(&self) -> String { pub fn print(&self) -> String {
match self { 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) => { Type::Cons(v) => {
let mut s = String::new(); let mut s = String::new();
s.push('('); s.push('(');
for (i, t) in v.iter().enumerate() { for (i, t) in v.iter().enumerate() {
if i != 0 { s.push(','); } if i != 0 { s.push(' '); }
s.push_str(&t.fmt()); s.push_str(&t.print().to_string());
} }
s.push(')'); s.push(')');
s 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::Float(fl) => write!(f, "{}", fl),
Type::Boolean(b) => write!(f, "{}", b), Type::Boolean(b) => write!(f, "{}", b),
Type::String(s) => write!(f, "\"{}\"", s), 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!(), _ => unreachable!(),
} }
} }
@ -140,14 +144,24 @@ impl FromStr for Type {
"true" => Ok(Type::Boolean(true)), "true" => Ok(Type::Boolean(true)),
"false" => Ok(Type::Boolean(false)), "false" => Ok(Type::Boolean(false)),
_ => { _ => {
if s.starts_with("(") { if s.starts_with("(") && s.ends_with(")") {
let elems = s[1..s.len() - 1] let mut v = Vec::new();
.split(',') let mut s = s[1..s.len() - 1].to_string();
.collect::<Vec<&str>>() // TODO: This is pretty messy :(
.iter() while !s.is_empty() {
.map(|s| s.trim().parse::<Type>()) let mut i = 0;
.collect::<Result<Vec<Type>, Self::Err>>()?; while i < s.len() && s.chars().nth(i).unwrap().is_whitespace() { i += 1; }
Ok(Type::Cons(elems)) 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 { } else {
let i = s.parse::<i64>(); let i = s.parse::<i64>();
if i.is_ok() { if i.is_ok() {

View file

@ -209,7 +209,7 @@ impl VM {
match function.as_str() { match function.as_str() {
"print" => { "print" => {
let value = self.stack.pop().unwrap(); let value = self.stack.pop().unwrap();
println!("{}", value.fmt()); println!("{}", value.print());
return Ok(()); return Ok(());
}, },
"read" => { "read" => {
@ -220,7 +220,7 @@ impl VM {
Ok(()) Ok(())
}, },
"slurp" => { "slurp" => {
let file_name = self.stack.pop().unwrap().fmt(); let file_name = self.stack.pop().unwrap().to_string();
let mut result = String::new(); let mut result = String::new();
match File::open(file_name).and_then(|mut f| f.read_to_string(&mut result)) { match File::open(file_name).and_then(|mut f| f.read_to_string(&mut result)) {
Ok(_) => Ok(self.stack.push(Type::String(result))), Ok(_) => Ok(self.stack.push(Type::String(result))),

6
example/quote.blsp Normal file
View file

@ -0,0 +1,6 @@
(fun main (do
(print (quote (a b c)))
(print (quote (+ 1 (+ 2 "3"))))
(print (quote a))
(print (quote "a"))
))