feat: quoting

replace/7746dba3cc6b3860afe1faf69e86ed84ee46988d
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::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 {

View File

@ -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))
}

View File

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

View File

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

View File

@ -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
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"))
))