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::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 {
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() }; }
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
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