DEV: The great Error message explosion.

This commit is contained in:
Jeremy Wall 2019-08-18 08:40:30 -05:00
parent 7a2a99b859
commit 33a5694aad
9 changed files with 596 additions and 316 deletions

View File

@ -16,11 +16,12 @@ use std::collections::BTreeMap;
use std::path::PathBuf;
use std::rc::Rc;
use super::{Op, OpPointer};
use super::translate::PositionMap;
use super::OpPointer;
/// A Cache of Op codes.
pub struct Ops {
ops: BTreeMap<String, Rc<Vec<Op>>>,
ops: BTreeMap<String, Rc<PositionMap>>,
}
impl Ops {
@ -35,10 +36,10 @@ impl Ops {
}
}
pub struct Entry<'a>(btree_map::Entry<'a, String, Rc<Vec<Op>>>);
pub struct Entry<'a>(btree_map::Entry<'a, String, Rc<PositionMap>>);
impl<'a> Entry<'a> {
pub fn get_pointer_or_else<F: FnOnce() -> Vec<Op>, P: Into<PathBuf>>(
pub fn get_pointer_or_else<F: FnOnce() -> PositionMap, P: Into<PathBuf>>(
self,
f: F,
path: P,

View File

@ -13,8 +13,22 @@
// limitations under the License.
use std::convert::From;
use crate::ast::Position;
#[derive(Debug)]
pub struct Error {}
pub struct Error {
message: String,
pos: Position,
}
impl Error {
pub fn new(msg: String, pos: Position) -> Self {
Self {
message: String::new(),
pos: pos,
}
}
}
impl<E> From<E> for Error
where
@ -22,6 +36,9 @@ where
{
fn from(_e: E) -> Self {
// FIXME(jwall): This should really have more information for debugging
Error {}
Error {
message: _e.description().to_owned(),
pos: Position::new(0, 0, 0),
}
}
}

View File

@ -250,7 +250,9 @@ impl TryFrom<&Value> for Val {
Val::List(els)
}
S(_) | F(_) | M(_) | T(_) => {
return Err(dbg!(Error {}));
return Err(dbg!(
Error::new(format!("Invalid Value {:?} to Val translation", val),
Position::new(0, 0, 0))));
}
})
}
@ -299,7 +301,7 @@ impl TryFrom<&Val> for Value {
}
// TODO(jwall): These can go away eventually when we replace the tree
// walking interpreter.
Val::Module(_) | Val::Func(_) => return Err(dbg!(Error {})),
Val::Module(_) | Val::Func(_) => return Err(dbg!(Error::new(format!("Invalid Translation from Val {} to Value", val), Position::new(0, 0, 0)))),
})
}
}

View File

@ -14,20 +14,23 @@
use std::path::PathBuf;
use std::rc::Rc;
use crate::ast::Position;
use super::translate::PositionMap;
use super::{Error, Op};
#[derive(Debug, PartialEq, Clone)]
pub struct OpPointer {
pub ops: Rc<Vec<Op>>,
pub pos_map: Rc<PositionMap>,
pub ptr: Option<usize>,
pub path: Option<PathBuf>,
}
impl OpPointer {
pub fn new(ops: Rc<Vec<Op>>) -> Self {
pub fn new(ops: Rc<PositionMap>) -> Self {
// If we load an empty program what happens?
Self {
ops: ops,
pos_map: ops,
ptr: None,
path: None,
}
@ -41,28 +44,41 @@ impl OpPointer {
pub fn next(&mut self) -> Option<&Op> {
if let Some(i) = self.ptr {
let nxt = i + 1;
if nxt < self.ops.len() {
if nxt < self.pos_map.len() {
self.ptr = Some(nxt);
} else {
return None;
}
} else if self.ops.len() != 0 {
} else if self.pos_map.len() != 0 {
self.ptr = Some(0);
}
self.op()
}
pub fn jump(&mut self, ptr: usize) -> Result<(), Error> {
if ptr < self.ops.len() {
if ptr < self.pos_map.len() {
self.ptr = Some(ptr);
return Ok(());
}
Err(dbg!(Error {}))
Err(dbg!(Error::new(
format!("FAULT!!! Invalid Jump!"),
match self.pos() {
Some(pos) => pos.clone(),
None => Position::new(0, 0, 0),
},
)))
}
pub fn op(&self) -> Option<&Op> {
if let Some(i) = self.ptr {
return self.ops.get(i);
return self.pos_map.ops.get(i);
}
None
}
pub fn pos(&self) -> Option<&Position> {
if let Some(i) = self.ptr {
return self.pos_map.pos.get(i);
}
None
}
@ -70,13 +86,16 @@ impl OpPointer {
pub fn idx(&self) -> Result<usize, Error> {
match self.ptr {
Some(ptr) => Ok(ptr),
None => dbg!(Err(Error {})),
None => dbg!(Err(Error::new(
format!("FAULT!!! Position Check failure!"),
Position::new(0, 0, 0),
))),
}
}
pub fn snapshot(&self) -> Self {
Self {
ops: self.ops.clone(),
pos_map: self.pos_map.clone(),
ptr: None,
path: self.path.clone(),
}

View File

@ -21,8 +21,7 @@ use std::rc::Rc;
use regex::Regex;
use super::environment::Environment;
use super::pointer::OpPointer;
use super::Value::{C, F, P, S};
use super::Value::{C, F, P};
use super::VM;
use super::{Composite, Error, Hook, Primitive, Value};
use crate::ast::Position;
@ -66,22 +65,23 @@ impl Builtins {
h: Hook,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
pos: &Position,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
match h {
Hook::Import => self.import(stack, env),
Hook::Include => self.include(stack, env),
Hook::Import => self.import(stack, env, pos),
Hook::Include => self.include(stack, env, pos),
Hook::Assert => self.assert(stack),
Hook::Convert => self.convert(stack, env),
Hook::Out => self.out(path, stack, env),
Hook::Map => self.map(stack, env),
Hook::Filter => self.filter(stack, env),
Hook::Reduce => self.reduce(stack, env),
Hook::Regex => self.regex(stack),
Hook::Range => self.range(stack),
Hook::Convert => self.convert(stack, env, pos),
Hook::Out => self.out(path, stack, env, pos),
Hook::Map => self.map(stack, env, pos),
Hook::Filter => self.filter(stack, env, pos),
Hook::Reduce => self.reduce(stack, env, pos),
Hook::Regex => self.regex(stack, pos),
Hook::Range => self.range(stack, pos),
Hook::Trace(pos) => self.trace(stack, pos, env),
}
}
@ -90,6 +90,7 @@ impl Builtins {
&self,
path: P,
use_import_path: bool,
pos: &Position,
) -> Result<PathBuf, Error> {
// Try a relative path first.
let path = path.into();
@ -114,22 +115,22 @@ impl Builtins {
}
match normalized.canonicalize() {
Ok(p) => Ok(p),
Err(_e) => Err(dbg!(Error {})),
Err(_e) => Err(dbg!(Error::new(
format!("Invalid path: {}", normalized.to_string_lossy()),
pos.clone(),
))),
}
}
fn get_file_as_string(&self, path: &str) -> Result<String, Error> {
fn get_file_as_string(&self, path: &str, pos: &Position) -> Result<String, Error> {
let sep = format!("{}", std::path::MAIN_SEPARATOR);
let raw_path = path.replace("/", &sep);
let normalized = match self.find_file(raw_path, false) {
Ok(p) => p,
Err(_e) => {
return Err(dbg!(Error {}));
}
};
let mut f = File::open(normalized).unwrap();
let normalized = self.find_file(raw_path, false, pos)?;
// TODO(jwall): Proper error here
let mut f = File::open(normalized)?;
let mut contents = String::new();
f.read_to_string(&mut contents).unwrap();
// TODO(jwall): Proper error here
f.read_to_string(&mut contents)?;
Ok(contents)
}
@ -137,6 +138,7 @@ impl Builtins {
&mut self,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
pos: &Position,
) -> Result<(), Error>
where
O: std::io::Write,
@ -176,14 +178,19 @@ impl Builtins {
}
return Ok(());
}
return Err(dbg!(Error::new(
format!("Invalid Path {:?}", val),
pos.clone(),
)));
}
return Err(dbg!(Error {}));
unreachable!();
}
fn include<O, E>(
&self,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
pos: &Position,
) -> Result<(), Error>
where
O: std::io::Write,
@ -195,42 +202,55 @@ impl Builtins {
if let &Value::P(Str(ref path)) = val.as_ref() {
path.clone()
} else {
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(
format!("Invalid Path {:?}", val),
pos.clone(),
)));
}
} else {
return Err(dbg!(Error {}));
unreachable!();
};
let typ = if let Some(val) = typ.as_ref() {
if let &Value::P(Str(ref typ)) = val.as_ref() {
typ.clone()
} else {
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(
format!("Expected conversion type but got {:?}", typ),
pos.clone(),
)));
}
} else {
return Err(dbg!(Error {}));
unreachable!();
};
if typ == "str" {
stack.push(Rc::new(P(Str(self.get_file_as_string(&path)?))));
stack.push(Rc::new(P(Str(self.get_file_as_string(&path, pos)?))));
} else {
stack.push(Rc::new(
match env.borrow().importer_registry.get_importer(&typ) {
Some(importer) => {
let contents = self.get_file_as_string(&path)?;
let contents = self.get_file_as_string(&path, pos)?;
if contents.len() == 0 {
eprintln!("including an empty file. Use NULL as the result");
P(Empty)
} else {
match importer.import(contents.as_bytes()) {
Ok(v) => v.try_into()?,
Err(_e) => return Err(dbg!(Error {})),
Err(e) => {
return Err(dbg!(Error::new(format!("{}", e), pos.clone(),)))
}
}
}
None => return Err(dbg!(Error {})),
}
None => {
return Err(dbg!(Error::new(
format!("No such conversion type {}", &typ),
pos.clone(),
)))
}
},
));
}
return Err(dbg!(Error {}));
Ok(())
}
fn assert(&mut self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
@ -272,15 +292,16 @@ impl Builtins {
path: Option<P>,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
pos: &Position,
) -> Result<(), Error>
where
O: std::io::Write,
E: std::io::Write,
{
let path = if let Some(path) = path {
path
let mut writer: Box<dyn std::io::Write> = if let Some(path) = path {
Box::new(File::create(path)?)
} else {
return Err(dbg!(Error {}));
Box::new(std::io::stdout())
};
let val = stack.pop();
if let Some(val) = val {
@ -288,24 +309,31 @@ impl Builtins {
if let Some(c_type_val) = stack.pop() {
if let &Value::S(ref c_type) = c_type_val.as_ref() {
if let Some(c) = env.borrow().converter_registry.get_converter(c_type) {
match c.convert(Rc::new(val), &mut File::create(path)?) {
Ok(_) => {
// noop
}
Err(_e) => return Err(dbg!(Error {})),
if let Err(e) = c.convert(Rc::new(val), &mut writer) {
return Err(dbg!(Error::new(format!("{}", e), pos.clone(),)));
}
return Ok(());
} else {
return Err(dbg!(Error::new(
format!("No such conversion type {:?}", c_type),
pos.clone()
)));
}
}
}
return Err(dbg!(Error::new(
format!("Not a conversion type {:?}", val),
pos.clone()
)));
}
return Err(dbg!(Error {}));
unreachable!();
}
fn convert<O, E>(
&self,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
pos: &Position,
) -> Result<(), Error>
where
O: std::io::Write,
@ -325,20 +353,30 @@ impl Builtins {
String::from_utf8_lossy(buf.as_slice()).to_string()
))));
}
Err(_e) => return Err(dbg!(Error {})),
Err(_e) => {
return Err(dbg!(Error::new(
format!("No such conversion type {:?}", c_type),
pos.clone()
)));
}
}
return Ok(());
}
}
}
return Err(dbg!(Error::new(
format!("Not a conversion type {:?}", val),
pos.clone()
)));
}
return Err(dbg!(Error {}));
unreachable!()
}
fn map<O, E>(
&self,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
pos: &Position,
) -> Result<(), Error>
where
O: std::io::Write,
@ -348,19 +386,19 @@ impl Builtins {
let list = if let Some(list) = stack.pop() {
list
} else {
return Err(dbg!(Error {}));
unreachable!();
};
// get the func ptr from the stack
let fptr = if let Some(ptr) = stack.pop() {
ptr
} else {
return Err(dbg!(Error {}));
unreachable!();
};
let f = if let &F(ref f) = fptr.as_ref() {
f
} else {
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(format!("Not a function!!"), pos.clone(),)));
};
match list.as_ref() {
@ -370,7 +408,7 @@ impl Builtins {
// push function argument on the stack.
stack.push(e.clone());
// call function and push it's result on the stack.
result_elems.push(VM::fcall_impl(f, stack, env.clone())?);
result_elems.push(VM::fcall_impl(f, stack, env.clone(), pos)?);
}
stack.push(Rc::new(C(List(result_elems))));
}
@ -379,15 +417,23 @@ impl Builtins {
for (ref name, ref val) in _flds {
stack.push(val.clone());
stack.push(Rc::new(P(Str(name.clone()))));
let result = VM::fcall_impl(f, stack, env.clone())?;
let result = VM::fcall_impl(f, stack, env.clone(), pos)?;
if let &C(List(ref fval)) = result.as_ref() {
// we expect them to be a list of exactly 2 items.
if fval.len() != 2 {
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(
format!(
"Map Functions over tuples must return a list of two items"
),
pos.clone(),
)));
}
let name = match fval[0].as_ref() {
&P(Str(ref name)) => name.clone(),
_ => return Err(dbg!(Error {})),
_ => return Err(dbg!(Error::new(
format!("Map functionss over tuples must return a String as the first list item"),
pos.clone(),
))),
};
new_fields.push((name, fval[1].clone()));
}
@ -399,16 +445,24 @@ impl Builtins {
for c in s.chars() {
stack.push(Rc::new(P(Str(c.to_string()))));
// call function and push it's result on the stack.
let result = VM::fcall_impl(f, stack, env.clone())?;
let result = VM::fcall_impl(f, stack, env.clone(), pos)?;
if let &P(Str(ref s)) = result.as_ref() {
buf.push_str(s);
} else {
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(
format!("Map functions over string should return strings"),
pos.clone()
)));
}
}
stack.push(Rc::new(P(Str(buf))));
}
_ => return Err(dbg!(Error {})),
_ => {
return Err(dbg!(Error::new(
format!("You can only map over lists, tuples, or strings"),
pos.clone(),
)))
}
};
Ok(())
}
@ -417,6 +471,7 @@ impl Builtins {
&self,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
pos: &Position,
) -> Result<(), Error>
where
O: std::io::Write,
@ -426,29 +481,29 @@ impl Builtins {
let list = if let Some(list) = stack.pop() {
list
} else {
return Err(dbg!(Error {}));
unreachable!();
};
// get the func ptr from the stack
let fptr = if let Some(ptr) = stack.pop() {
ptr
} else {
return Err(dbg!(Error {}));
unreachable!();
};
let f = if let &F(ref f) = fptr.as_ref() {
f
} else {
return dbg!(Err(Error {}));
return Err(dbg!(Error::new(format!("Not a function!!"), pos.clone(),)));
};
let elems = match list.as_ref() {
match list.as_ref() {
&C(List(ref elems)) => {
let mut result_elems = Vec::new();
for e in elems.iter() {
// push function argument on the stack.
stack.push(e.clone());
// call function and push it's result on the stack.
let condition = VM::fcall_impl(f, stack, env.clone())?;
let condition = VM::fcall_impl(f, stack, env.clone(), pos)?;
// Check for empty or boolean results and only push e back in
// if they are non empty and true
match condition.as_ref() {
@ -465,7 +520,7 @@ impl Builtins {
for (ref name, ref val) in _flds {
stack.push(val.clone());
stack.push(Rc::new(P(Str(name.clone()))));
let condition = VM::fcall_impl(f, stack, env.clone())?;
let condition = VM::fcall_impl(f, stack, env.clone(), pos)?;
// Check for empty or boolean results and only push e back in
// if they are non empty and true
match condition.as_ref() {
@ -482,7 +537,7 @@ impl Builtins {
for c in s.chars() {
stack.push(Rc::new(P(Str(c.to_string()))));
// call function and push it's result on the stack.
let condition = VM::fcall_impl(f, stack, env.clone())?;
let condition = VM::fcall_impl(f, stack, env.clone(), pos)?;
// Check for empty or boolean results and only push c back in
// if they are non empty and true
match condition.as_ref() {
@ -494,21 +549,29 @@ impl Builtins {
}
stack.push(Rc::new(P(Str(buf))));
}
_ => return Err(dbg!(Error {})),
};
_ => {
return Err(dbg!(Error::new(
format!("You can only filter over lists, tuples, or strings"),
pos.clone(),
)))
}
}
Ok(())
}
fn regex(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
fn regex(&self, stack: &mut Vec<Rc<Value>>, pos: &Position) -> Result<(), Error> {
// 1. get left side (string)
let left_str = if let Some(val) = stack.pop() {
if let &P(Str(ref s)) = val.as_ref() {
s.clone()
} else {
return dbg!(Err(Error {}));
return dbg!(Err(Error::new(
format!("Expected string bug got {:?}", val),
pos.clone(),
)));
}
} else {
return dbg!(Err(Error {}));
unreachable!();
};
// 2. get right side (string)
@ -516,10 +579,13 @@ impl Builtins {
if let &P(Str(ref s)) = val.as_ref() {
s.clone()
} else {
return dbg!(Err(Error {}));
return dbg!(Err(Error::new(
format!("Expected string bug got {:?}", val),
pos.clone(),
)));
}
} else {
return dbg!(Err(Error {}));
unreachable!();
};
// 3. compare via regex
@ -532,6 +598,7 @@ impl Builtins {
&self,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
pos: &Position,
) -> Result<(), Error>
where
O: std::io::Write,
@ -541,25 +608,25 @@ impl Builtins {
let list = if let Some(list) = stack.pop() {
list
} else {
return dbg!(Err(Error {}));
unreachable!();
};
// Get the accumulator from the stack
let mut acc = if let Some(acc) = stack.pop() {
acc
} else {
return dbg!(Err(Error {}));
unreachable!();
};
// get the func ptr from the stack
let fptr = if let Some(ptr) = stack.pop() {
ptr
} else {
return dbg!(Err(Error {}));
unreachable!();
};
let f = if let &F(ref f) = fptr.as_ref() {
f
} else {
return dbg!(Err(Error {}));
return dbg!(Err(Error::new(format!("Not a function!"), pos.clone(),)));
};
match list.as_ref() {
@ -569,7 +636,7 @@ impl Builtins {
stack.push(dbg!(e.clone()));
stack.push(dbg!(acc.clone()));
// call function and push it's result on the stack.
acc = VM::fcall_impl(f, stack, env.clone())?;
acc = VM::fcall_impl(f, stack, env.clone(), pos)?;
}
}
&C(Tuple(ref _flds)) => {
@ -579,7 +646,7 @@ impl Builtins {
stack.push(Rc::new(P(Str(name.clone()))));
stack.push(dbg!(acc.clone()));
// call function and push it's result on the stack.
acc = VM::fcall_impl(f, stack, env.clone())?;
acc = VM::fcall_impl(f, stack, env.clone(), pos)?;
}
}
&P(Str(ref _s)) => {
@ -588,10 +655,15 @@ impl Builtins {
stack.push(dbg!(Rc::new(P(Str(c.to_string())))));
stack.push(dbg!(acc.clone()));
// call function and push it's result on the stack.
acc = VM::fcall_impl(f, stack, env.clone())?;
acc = VM::fcall_impl(f, stack, env.clone(), pos)?;
}
}
_ => return Err(dbg!(Error {})),
_ => {
return Err(dbg!(Error::new(
format!("You can only reduce over lists, tuples, or strings"),
pos.clone()
)))
}
};
// push the acc on the stack as our result
@ -599,11 +671,11 @@ impl Builtins {
Ok(())
}
fn range(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
fn range(&self, stack: &mut Vec<Rc<Value>>, pos: &Position) -> Result<(), Error> {
let start = if let Some(start) = stack.pop() {
start
} else {
return dbg!(Err(Error {}));
unreachable!();
};
let step = if let Some(step) = stack.pop() {
if let &P(Empty) = step.as_ref() {
@ -612,12 +684,12 @@ impl Builtins {
step
}
} else {
return dbg!(Err(Error {}));
unreachable!();
};
let end = if let Some(end) = stack.pop() {
end
} else {
return dbg!(Err(Error {}));
unreachable!();
};
let mut elems = Vec::new();
@ -633,7 +705,10 @@ impl Builtins {
}
}
_ => {
return dbg!(Err(Error {}));
return dbg!(Err(Error::new(
format!("Ranges can only be created with Ints"),
pos.clone(),
)));
}
}
stack.push(Rc::new(C(List(elems))));
@ -653,25 +728,25 @@ impl Builtins {
let val = if let Some(val) = dbg!(stack.pop()) {
val
} else {
return Err(dbg!(Error {}));
unreachable!();
};
let expr = stack.pop();
let expr_pretty = match expr {
Some(ref expr) => match dbg!(expr.as_ref()) {
&P(Str(ref expr)) => expr.clone(),
_ => return Err(dbg!(Error {})),
_ => unreachable!(),
},
_ => return Err(dbg!(Error {})),
_ => unreachable!(),
};
let writable_val: Val = TryFrom::try_from(val.clone())?;
if let Err(_) = writeln!(
if let Err(e) = writeln!(
&mut env.borrow_mut().stderr,
"TRACE: {} = {} at {}",
expr_pretty,
writable_val,
pos
) {
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(format!("{}", e), pos.clone(),)));
};
stack.push(val);
Ok(())

View File

@ -15,7 +15,7 @@ use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
use std::rc::Rc;
use super::{Error, Value};
use super::Value;
#[derive(Clone, PartialEq, Debug)]
pub enum Bindings {
@ -115,12 +115,12 @@ impl Stack {
std::mem::swap(&mut tmp, &mut self.curr);
}
pub fn pop(&mut self) -> Result<(), Error> {
pub fn pop(&mut self) -> Result<(), String> {
if let Some(parent) = self.prev.pop() {
self.curr = parent;
Ok(())
} else {
dbg!(Err(Error {}))
dbg!(Err(format!("Exceeded Stack depth!!")))
}
}

View File

@ -16,6 +16,7 @@ use std::rc::Rc;
use super::environment::Environment;
use super::scope::Stack;
use super::translate::PositionMap;
use super::Composite::{List, Tuple};
use super::Op::{
Add, Bang, Bind, BindOver, Cp, DeRef, Div, Element, Equal, FCall, Field, Func, Index, InitList,
@ -25,12 +26,21 @@ use super::Op::{
use super::Primitive::{Bool, Empty, Float, Int, Str};
use super::Value::{C, P};
use super::VM;
use crate::ast::Position;
macro_rules! assert_cases {
(__impl__ $cases:expr) => {
for case in $cases.drain(0..) {
let env = Rc::new(RefCell::new(Environment::new(Vec::new(), Vec::new())));
let mut vm = VM::new(Rc::new(case.0), env);
let mut positions = Vec::with_capacity(case.0.len());
for i in 0..case.0.len() {
positions.push(Position::new(0, 0, 0));
}
let map = PositionMap{
ops: case.0,
pos: positions,
};
let mut vm = VM::new(Rc::new(map), env);
vm.run().unwrap();
assert_eq!(dbg!(vm.pop()).unwrap(), Rc::new(case.1));
}
@ -120,10 +130,18 @@ fn bind_op() {
for case in cases.drain(0..) {
let env = Rc::new(RefCell::new(Environment::new(Vec::new(), Vec::new())));
let mut vm = VM::new(Rc::new(case.0), env);
let mut positions = Vec::with_capacity(case.0.len());
for i in 0..case.0.len() {
positions.push(Position::new(0, 0, 0));
}
let map = PositionMap {
ops: case.0,
pos: positions,
};
let mut vm = VM::new(Rc::new(map), env);
vm.run().unwrap();
let (name, result) = case.1;
let v = vm.get_binding(name).unwrap();
let v = vm.get_binding(name, &Position::new(0, 0, 0)).unwrap();
assert_eq!(&result, v.as_ref());
}
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
use std::path::Path;
use crate::ast::{BinaryExprType, Expression, FormatArgs, Statement, Value};
use crate::ast::{BinaryExprType, Expression, FormatArgs, Position, Statement, Value};
use crate::ast::{FuncOpDef, TemplatePart};
use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser};
use crate::build::opcode::Primitive;
@ -21,14 +21,38 @@ use crate::build::opcode::{Hook, Op};
pub struct AST();
#[derive(Debug, PartialEq)]
pub struct PositionMap {
pub ops: Vec<Op>,
pub pos: Vec<Position>,
}
impl PositionMap {
pub fn len(&self) -> usize {
self.ops.len()
}
pub fn push(&mut self, op: Op, pos: Position) {
self.ops.push(op);
self.pos.push(pos);
}
pub fn replace(&mut self, idx: usize, op: Op) {
self.ops[idx] = op;
}
}
impl AST {
pub fn translate<P: AsRef<Path>>(stmts: Vec<Statement>, root: &P) -> Vec<Op> {
let mut ops = Vec::new();
pub fn translate<P: AsRef<Path>>(stmts: Vec<Statement>, root: &P) -> PositionMap {
let mut ops = PositionMap {
ops: Vec::new(),
pos: Vec::new(),
};
Self::translate_stmts(stmts, &mut ops, root.as_ref());
return ops;
}
fn translate_stmts(stmts: Vec<Statement>, mut ops: &mut Vec<Op>, root: &Path) {
fn translate_stmts(stmts: Vec<Statement>, mut ops: &mut PositionMap, root: &Path) {
for stmt in stmts {
match stmt {
Statement::Expression(expr) => Self::translate_expr(expr, &mut ops, root),
@ -37,9 +61,9 @@ impl AST {
}
Statement::Let(def) => {
let binding = def.name.fragment;
ops.push(Op::Sym(binding));
ops.push(Op::Sym(binding), def.name.pos);
Self::translate_expr(def.value, &mut ops, root);
ops.push(Op::Bind);
ops.push(Op::Bind, def.pos);
}
Statement::Output(_, _, _) => {
unimplemented!("Out statements are not implmented yet")
@ -51,7 +75,7 @@ impl AST {
}
}
fn translate_expr(expr: Expression, mut ops: &mut Vec<Op>, root: &Path) {
fn translate_expr(expr: Expression, mut ops: &mut PositionMap, root: &Path) {
match expr {
Expression::Simple(v) => {
Self::translate_value(v, &mut ops, root);
@ -61,92 +85,91 @@ impl AST {
BinaryExprType::Add => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Add);
ops.push(Op::Add, def.pos);
}
BinaryExprType::Sub => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Sub);
ops.push(Op::Sub, def.pos);
}
BinaryExprType::Div => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Div);
ops.push(Op::Div, def.pos);
}
BinaryExprType::Mul => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Mul);
ops.push(Op::Mul, def.pos);
}
BinaryExprType::Equal => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Equal);
ops.push(Op::Equal, def.pos);
}
BinaryExprType::GT => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Gt);
ops.push(Op::Gt, def.pos);
}
BinaryExprType::LT => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Lt);
ops.push(Op::Lt, def.pos);
}
BinaryExprType::GTEqual => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::GtEq);
ops.push(Op::GtEq, def.pos);
}
BinaryExprType::LTEqual => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::LtEq);
ops.push(Op::LtEq, def.pos);
}
BinaryExprType::NotEqual => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Equal);
ops.push(Op::Not);
ops.push(Op::Equal, def.pos.clone());
ops.push(Op::Not, def.pos);
}
BinaryExprType::REMatch => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Runtime(Hook::Regex));
ops.push(Op::Runtime(Hook::Regex), def.pos);
}
BinaryExprType::NotREMatch => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Runtime(Hook::Regex));
ops.push(Op::Not);
ops.push(Op::Runtime(Hook::Regex), def.pos.clone());
ops.push(Op::Not, def.pos);
}
BinaryExprType::IS => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Typ);
ops.push(Op::Equal);
ops.push(Op::Typ, def.pos.clone());
ops.push(Op::Equal, def.pos);
}
BinaryExprType::AND => {
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Noop);
ops.push(Op::Noop, def.pos);
let idx = ops.len() - 1;
Self::translate_expr(*def.right, &mut ops, root);
let jptr = (ops.len() - 1 - idx) as i32;
ops[idx] = Op::And(dbg!(jptr));
dbg!(ops);
ops.replace(idx, Op::And(dbg!(jptr)));
}
BinaryExprType::OR => {
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Noop); // Placeholder
ops.push(Op::Noop, def.pos); // Placeholder
let idx = ops.len() - 1;
Self::translate_expr(*def.right, &mut ops, root);
let jptr = (ops.len() - 1 - idx) as i32;
ops[idx] = Op::Or(jptr);
ops.replace(idx, Op::Or(dbg!(jptr)));
}
BinaryExprType::Mod => {
Self::translate_expr(*def.right, &mut ops, root);
Self::translate_expr(*def.left, &mut ops, root);
ops.push(Op::Mod);
ops.push(Op::Mod, def.pos);
}
BinaryExprType::IN => {
// Dot expressions expect the left side to be pushed first
@ -165,10 +188,10 @@ impl AST {
Self::translate_expr(expr, &mut ops, root);
}
}
ops.push(Op::SafeIndex);
ops.push(Op::Val(Primitive::Empty));
ops.push(Op::Equal);
ops.push(Op::Not);
ops.push(Op::SafeIndex, def.pos.clone());
ops.push(Op::Val(Primitive::Empty), def.pos.clone());
ops.push(Op::Equal, def.pos.clone());
ops.push(Op::Not, def.pos);
}
BinaryExprType::DOT => {
// Dot expressions expect the left side to be pushed first
@ -187,7 +210,7 @@ impl AST {
Self::translate_expr(expr, &mut ops, root);
}
}
ops.push(Op::Index);
ops.push(Op::Index, def.pos);
}
};
}
@ -196,7 +219,7 @@ impl AST {
}
Expression::Fail(def) => {
Self::translate_expr(*def.message, &mut ops, root);
ops.push(Op::Bang);
ops.push(Op::Bang, def.pos);
}
Expression::Format(def) => {
match def.args {
@ -212,6 +235,7 @@ impl AST {
let mut elems_iter = elems.drain(0..);
let mut parts_iter = parts.drain(0..);
Self::translate_template_part(
def.pos.clone(),
parts_iter.next().unwrap(),
&mut elems_iter,
&mut ops,
@ -219,8 +243,17 @@ impl AST {
root,
);
for p in parts_iter {
Self::translate_template_part(p, &mut elems_iter, &mut ops, true, root);
ops.push(Op::Add);
Self::translate_template_part(
def.pos.clone(),
p,
&mut elems_iter,
&mut ops,
true,
root,
);
// TODO(jwall): We could get a little more helpful about where
// these positions are.
ops.push(Op::Add, def.pos.clone());
}
}
FormatArgs::Single(expr) => {
@ -230,17 +263,19 @@ impl AST {
let mut parts = formatter.parse(&def.template).unwrap();
parts.reverse();
let mut parts_iter = parts.drain(0..);
ops.push(Op::Noop);
ops.push(Op::Noop, expr.pos().clone());
let scope_idx = ops.len() - 1;
// Add our item binding shadowing any binding that already
// existed.
ops.push(Op::Sym("item".to_owned()));
let expr_pos = expr.pos().clone();
ops.push(Op::Sym("item".to_owned()), expr.pos().clone());
Self::translate_expr(*expr, &mut ops, root);
ops.push(Op::BindOver);
ops.push(Op::BindOver, expr_pos.clone());
let mut elems = Vec::new();
let mut elems_iter = elems.drain(0..);
Self::translate_template_part(
def.pos.clone(),
parts_iter.next().unwrap(),
&mut elems_iter,
&mut ops,
@ -249,32 +284,33 @@ impl AST {
);
for p in parts_iter {
Self::translate_template_part(
def.pos.clone(),
p,
&mut elems_iter,
&mut ops,
false,
root,
);
ops.push(Op::Add);
ops.push(Op::Add, expr_pos.clone());
}
ops.push(Op::Return);
ops.push(Op::Return, expr_pos);
let jump_idx = (ops.len() - 1 - scope_idx) as i32;
ops[scope_idx] = Op::NewScope(jump_idx);
ops.replace(scope_idx, Op::NewScope(jump_idx));
}
}
}
Expression::Func(def) => {
ops.push(Op::InitList);
ops.push(Op::InitList, def.pos.clone());
for b in def.argdefs {
ops.push(Op::Sym(b.val));
ops.push(Op::Element);
ops.push(Op::Sym(b.val), b.pos.clone());
ops.push(Op::Element, b.pos);
}
ops.push(Op::Noop);
ops.push(Op::Noop, def.pos.clone());
let idx = ops.len() - 1;
Self::translate_expr(*def.fields, &mut ops, root);
ops.push(Op::Return);
ops.push(Op::Return, def.pos);
let jptr = ops.len() - 1 - idx;
ops[idx] = Op::Func(jptr as i32);
ops.replace(idx, Op::Func(jptr as i32));
}
Expression::FuncOp(def) => {
match def {
@ -284,7 +320,7 @@ impl AST {
// push the target on the stack third
Self::translate_expr(*def.target, &mut ops, root);
// finally push the Hook::Map opcode
ops.push(Op::Runtime(Hook::Map));
ops.push(Op::Runtime(Hook::Map), def.pos);
}
FuncOpDef::Filter(def) => {
// push the function on the stack first.
@ -292,7 +328,7 @@ impl AST {
// push the target on the stack third
Self::translate_expr(*def.target, &mut ops, root);
// finally push the Hook::Map opcode
ops.push(Op::Runtime(Hook::Filter));
ops.push(Op::Runtime(Hook::Filter), def.pos);
}
FuncOpDef::Reduce(def) => {
// push the function on the stack first.
@ -302,18 +338,18 @@ impl AST {
// push the target on the stack third
Self::translate_expr(*def.target, &mut ops, root);
// finally push the Hook::Map opcode
ops.push(Op::Runtime(Hook::Reduce));
ops.push(Op::Runtime(Hook::Reduce), def.pos);
}
}
}
Expression::Import(def) => {
ops.push(Op::Val(Primitive::Str(def.path.fragment)));
ops.push(Op::Runtime(Hook::Import));
ops.push(Op::Val(Primitive::Str(def.path.fragment)), def.path.pos);
ops.push(Op::Runtime(Hook::Import), def.pos);
}
Expression::Include(def) => {
ops.push(Op::Val(Primitive::Str(def.typ.fragment)));
ops.push(Op::Val(Primitive::Str(def.path.fragment)));
ops.push(Op::Runtime(Hook::Include));
ops.push(Op::Val(Primitive::Str(def.typ.fragment)), def.typ.pos);
ops.push(Op::Val(Primitive::Str(def.path.fragment)), def.path.pos);
ops.push(Op::Runtime(Hook::Include), def.pos);
}
Expression::Module(mut def) => {
def.imports_to_absolute(root.to_path_buf());
@ -321,74 +357,75 @@ impl AST {
let out_expr = def.out_expr;
let stmts = def.statements;
// Init our module tuple bindings
ops.push(Op::InitTuple);
ops.push(Op::InitTuple, def.pos.clone());
for (t, e) in argset {
ops.push(Op::Sym(t.fragment));
ops.push(Op::Sym(t.fragment), t.pos.clone());
Self::translate_expr(e, &mut ops, root);
ops.push(Op::Field);
ops.push(Op::Field, t.pos);
}
// If there is one then emit our return expression
if let Some(expr) = out_expr {
// Insert placeholder until we know jptr for this thunk
ops.push(Op::Noop);
let expr_pos = expr.pos().clone();
ops.push(Op::Noop, expr.pos().clone());
let idx = ops.len() - 1;
Self::translate_expr(*expr, &mut ops, root);
ops.push(Op::Return);
ops.push(Op::Return, expr_pos.clone());
let jptr = ops.len() - idx - 1;
ops[idx] = Op::InitThunk(jptr as i32);
ops.replace(idx, Op::InitThunk(jptr as i32));
}
// Insert a placeholder Opcode until we know jptr for the
// module.
ops.push(Op::Noop);
ops.push(Op::Noop, def.pos.clone());
let idx = ops.len() - 1;
// Bind our mod tuple.
ops.push(Op::Bind);
ops.push(Op::Bind, def.pos.clone());
// emit all of our statements;
Self::translate_stmts(stmts, &mut ops, root);
// Return from the module
ops.push(Op::Return);
ops.push(Op::Return, def.pos);
let jptr = ops.len() - idx - 1;
ops[idx] = Op::Module(jptr as i32);
ops.replace(idx, Op::Module(jptr as i32));
}
Expression::Not(def) => {
Self::translate_expr(*def.expr, &mut ops, root);
ops.push(Op::Not);
ops.push(Op::Not, def.pos);
}
Expression::Range(def) => {
Self::translate_expr(*def.end, &mut ops, root);
if let Some(expr) = def.step {
Self::translate_expr(*expr, &mut ops, root);
} else {
ops.push(Op::Val(Primitive::Empty));
ops.push(Op::Val(Primitive::Empty), def.pos.clone());
}
Self::translate_expr(*def.start, &mut ops, root);
ops.push(Op::Runtime(Hook::Range));
ops.push(Op::Runtime(Hook::Range), def.pos);
}
Expression::Select(def) => {
Self::translate_expr(*def.val, &mut ops, root);
let mut jumps = Vec::new();
for (key, val) in def.tuple {
ops.push(Op::Sym(key.fragment));
ops.push(Op::Noop);
ops.push(Op::Sym(key.fragment), key.pos.clone());
ops.push(Op::Noop, key.pos);
let idx = ops.len() - 1;
let expr_pos = val.pos().clone();
Self::translate_expr(val, &mut ops, root);
ops.push(Op::Noop);
ops.push(Op::Noop, expr_pos);
jumps.push(ops.len() - 1);
let jptr = ops.len() - idx - 1;
ops[idx] = Op::SelectJump(jptr as i32);
ops.replace(idx, Op::SelectJump(jptr as i32));
}
ops.push(Op::Pop);
ops.push(Op::Pop, def.pos.clone());
let end = ops.len() - 1;
for i in jumps {
let idx = end - i;
ops[i] = Op::Jump(idx as i32);
ops.replace(i, Op::Jump(idx as i32));
}
if let Some(default) = def.default {
Self::translate_expr(*default, &mut ops, root);
} else {
ops.push(Op::Bang);
ops.push(Op::Bang, def.pos);
}
dbg!(&ops);
}
Expression::Call(def) => {
// first push our arguments.
@ -396,19 +433,19 @@ impl AST {
Self::translate_expr(e, &mut ops, root);
}
// then push the func reference
let func_pos = def.funcref.pos().clone();
Self::translate_value(def.funcref, &mut ops, root);
ops.push(Op::FCall);
dbg!(ops);
ops.push(Op::FCall, func_pos);
}
Expression::Copy(def) => {
ops.push(Op::InitTuple);
ops.push(Op::InitTuple, def.pos.clone());
for (t, e) in def.fields {
ops.push(Op::Sym(t.fragment));
ops.push(Op::Sym(t.fragment), t.pos.clone());
Self::translate_expr(e, &mut ops, root);
ops.push(Op::Field);
ops.push(Op::Field, t.pos.clone());
}
Self::translate_value(def.selector, &mut ops, root);
ops.push(Op::Cp);
ops.push(Op::Cp, def.pos);
}
Expression::Debug(def) => {
let mut buffer: Vec<u8> = Vec::new();
@ -417,23 +454,24 @@ impl AST {
let _ = printer.render_expr(&def.expr);
}
let expr_pretty = String::from_utf8(buffer).unwrap();
ops.push(Op::Val(Primitive::Str(expr_pretty)));
ops.push(Op::Val(Primitive::Str(expr_pretty)), def.pos.clone());
Self::translate_expr(*def.expr, &mut ops, root);
ops.push(Op::Runtime(Hook::Trace(def.pos)));
ops.push(Op::Runtime(Hook::Trace(def.pos.clone())), def.pos);
}
}
}
fn translate_template_part<EI: Iterator<Item = Expression>>(
pos: Position,
part: TemplatePart,
elems: &mut EI,
mut ops: &mut Vec<Op>,
mut ops: &mut PositionMap,
place_holder: bool,
root: &Path,
) {
match part {
TemplatePart::Str(s) => {
ops.push(Op::Val(Primitive::Str(s.into_iter().collect())));
ops.push(Op::Val(Primitive::Str(s.into_iter().collect())), pos);
}
TemplatePart::PlaceHolder(_idx) => {
if !place_holder {
@ -441,7 +479,7 @@ impl AST {
unreachable!();
} else {
Self::translate_expr(elems.next().unwrap(), &mut ops, root);
ops.push(Op::Render);
ops.push(Op::Render, pos);
}
}
TemplatePart::Expression(expr) => {
@ -449,35 +487,36 @@ impl AST {
unreachable!();
} else {
Self::translate_expr(expr, &mut ops, root);
ops.push(Op::Render);
ops.push(Op::Render, pos);
}
}
}
}
fn translate_value(value: Value, mut ops: &mut Vec<Op>, root: &Path) {
fn translate_value(value: Value, mut ops: &mut PositionMap, root: &Path) {
match value {
Value::Int(i) => ops.push(Op::Val(Primitive::Int(i.val))),
Value::Float(f) => ops.push(Op::Val(Primitive::Float(f.val))),
Value::Str(s) => ops.push(Op::Val(Primitive::Str(s.val))),
Value::Empty(_pos) => ops.push(Op::Val(Primitive::Empty)),
Value::Boolean(b) => ops.push(Op::Val(Primitive::Bool(b.val))),
Value::Int(i) => ops.push(Op::Val(Primitive::Int(i.val)), i.pos),
Value::Float(f) => ops.push(Op::Val(Primitive::Float(f.val)), f.pos),
Value::Str(s) => ops.push(Op::Val(Primitive::Str(s.val)), s.pos),
Value::Empty(pos) => ops.push(Op::Val(Primitive::Empty), pos),
Value::Boolean(b) => ops.push(Op::Val(Primitive::Bool(b.val)), b.pos),
Value::Symbol(s) => {
ops.push(Op::DeRef(s.val));
ops.push(Op::DeRef(s.val), s.pos);
}
Value::Tuple(flds) => {
ops.push(Op::InitTuple);
ops.push(Op::InitTuple, flds.pos);
for (k, v) in flds.val {
ops.push(Op::Sym(k.fragment));
ops.push(Op::Sym(k.fragment), k.pos.clone());
Self::translate_expr(v, &mut ops, root);
ops.push(Op::Field);
ops.push(Op::Field, k.pos.clone());
}
}
Value::List(els) => {
ops.push(Op::InitList);
ops.push(Op::InitList, els.pos);
for el in els.elems {
let el_pos = el.pos().clone();
Self::translate_expr(el, &mut ops, root);
ops.push(Op::Element);
ops.push(Op::Element, el_pos);
}
}
}

View File

@ -15,10 +15,13 @@ use std::cell::RefCell;
use std::path::PathBuf;
use std::rc::Rc;
use crate::ast::Position;
use super::environment::Environment;
use super::pointer::OpPointer;
use super::runtime;
use super::scope::Stack;
use super::translate::PositionMap;
use super::Composite::{List, Tuple};
use super::Hook;
use super::Primitive::{Bool, Empty, Float, Int, Str};
@ -43,7 +46,7 @@ where
O: std::io::Write,
E: std::io::Write,
{
pub fn new(ops: Rc<Vec<Op>>, env: Rc<RefCell<Environment<O, E>>>) -> Self {
pub fn new(ops: Rc<PositionMap>, env: Rc<RefCell<Environment<O, E>>>) -> Self {
Self::with_pointer(OpPointer::new(ops), env)
}
@ -79,38 +82,39 @@ where
pub fn run(&mut self) -> Result<(), Error> {
loop {
let op = if let Some(op) = self.ops.next() {
let op = if let Some(op) = dbg!(self.ops.next()) {
op.clone()
} else {
break;
};
let pos = self.ops.pos().unwrap().clone();
let idx = self.ops.idx()?;
match op {
Op::Val(p) => self.push(Rc::new(P(p.clone())))?,
Op::Sym(s) => self.push(Rc::new(S(s.clone())))?,
Op::DeRef(s) => self.op_deref(s.clone())?,
Op::Add => self.op_add()?,
Op::Mod => self.op_mod()?,
Op::Sub => self.op_sub()?,
Op::Mul => self.op_mul()?,
Op::Div => self.op_div()?,
Op::Bind => self.op_bind(true)?,
Op::BindOver => self.op_bind(false)?,
Op::DeRef(s) => self.op_deref(s.clone(), &pos)?,
Op::Add => self.op_add(&pos)?,
Op::Mod => self.op_mod(&pos)?,
Op::Sub => self.op_sub(&pos)?,
Op::Mul => self.op_mul(&pos)?,
Op::Div => self.op_div(&pos)?,
Op::Bind => self.op_bind(true, &pos)?,
Op::BindOver => self.op_bind(false, &pos)?,
Op::Equal => self.op_equal()?,
Op::Not => self.op_not()?,
Op::Gt => self.op_gt()?,
Op::Lt => self.op_lt()?,
Op::GtEq => self.op_gteq()?,
Op::LtEq => self.op_lteq()?,
Op::Not => self.op_not(&pos)?,
Op::Gt => self.op_gt(&pos)?,
Op::Lt => self.op_lt(&pos)?,
Op::GtEq => self.op_gteq(&pos)?,
Op::LtEq => self.op_lteq(&pos)?,
// Add a Composite list value to the stack
Op::InitList => self.push(Rc::new(C(List(Vec::new()))))?,
// Add a composite tuple value to the stack
Op::InitTuple => self.push(Rc::new(C(Tuple(Vec::new()))))?,
Op::Field => self.op_field()?,
Op::Element => self.op_element()?,
Op::Index => self.op_index(false)?,
Op::SafeIndex => self.op_index(true)?,
Op::Cp => self.op_copy()?,
Op::Index => self.op_index(false, &pos)?,
Op::SafeIndex => self.op_index(true, &pos)?,
Op::Cp => self.op_copy(&pos)?,
//FIXME(jwall): Should this take a user provided message?
Op::Bang => self.op_bang()?,
Op::InitThunk(jp) => self.op_thunk(idx, jp)?,
@ -118,14 +122,14 @@ where
// Do nothing
}
Op::Jump(jp) => self.op_jump(jp)?,
Op::JumpIfTrue(jp) => self.op_jump_if_true(jp)?,
Op::JumpIfFalse(jp) => self.op_jump_if_false(jp)?,
Op::JumpIfTrue(jp) => self.op_jump_if_true(jp, &pos)?,
Op::JumpIfFalse(jp) => self.op_jump_if_false(jp, &pos)?,
Op::SelectJump(jp) => self.op_select_jump(jp)?,
Op::And(jp) => self.op_and(jp)?,
Op::Or(jp) => self.op_or(jp)?,
Op::Module(mptr) => self.op_module(idx, mptr)?,
Op::Func(jptr) => self.op_func(idx, jptr)?,
Op::FCall => self.op_fcall()?,
Op::And(jp) => self.op_and(jp, &pos)?,
Op::Or(jp) => self.op_or(jp, &pos)?,
Op::Module(mptr) => self.op_module(idx, mptr, &pos)?,
Op::Func(jptr) => self.op_func(idx, jptr, &pos)?,
Op::FCall => self.op_fcall(&pos)?,
Op::NewScope(jp) => self.op_new_scope(jp, self.ops.clone())?,
Op::Return => {
dbg!(&self.stack);
@ -135,7 +139,7 @@ where
self.pop()?;
}
Op::Typ => self.op_typ()?,
Op::Runtime(h) => self.op_runtime(h)?,
Op::Runtime(h) => self.op_runtime(h, &pos)?,
Op::Render => self.op_render()?,
};
}
@ -154,17 +158,16 @@ where
C(List(_)) => "list",
F(_) => "func",
M(_) => "module",
S(_) | T(_) => {
return Err(dbg!(Error {}));
}
S(_) => "sym",
T(_) => "thunk",
}
.to_owned();
self.push(Rc::new(P(Str(typ_name))))?;
Ok(())
}
fn op_deref(&mut self, name: String) -> Result<(), Error> {
let val = self.get_binding(&name)?.clone();
fn op_deref(&mut self, name: String, pos: &Position) -> Result<(), Error> {
let val = self.get_binding(&name, pos)?.clone();
self.push(val)
}
@ -178,7 +181,7 @@ where
Ok(())
}
fn op_and(&mut self, jp: i32) -> Result<(), Error> {
fn op_and(&mut self, jp: i32, pos: &Position) -> Result<(), Error> {
let cond = self.pop()?;
let cc = cond.clone();
if let &P(Bool(cond)) = cond.as_ref() {
@ -187,41 +190,57 @@ where
self.op_jump(jp)?;
}
} else {
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(
format!("Not a boolean condition {:?} in && expression!", cond),
pos.clone(),
)));
}
Ok(())
}
fn op_or(&mut self, jp: i32) -> Result<(), Error> {
fn op_or(&mut self, jp: i32, pos: &Position) -> Result<(), Error> {
let cond = self.pop()?;
let cc = cond.clone();
let cc = dbg!(cond.clone());
if let &P(Bool(cond)) = cond.as_ref() {
if cond {
if dbg!(cond) {
self.push(cc)?;
self.op_jump(jp)?;
}
} else {
return Err(dbg!(Error::new(
format!("Not a boolean condition {:?} in || expression!", cond),
pos.clone(),
)));
}
Ok(())
}
fn op_jump_if_true(&mut self, jp: i32) -> Result<(), Error> {
fn op_jump_if_true(&mut self, jp: i32, pos: &Position) -> Result<(), Error> {
let cond = self.pop()?;
if let &P(Bool(cond)) = cond.as_ref() {
if cond {
self.op_jump(jp)?;
}
} else {
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(
format!("Expected boolean but got {:?}!", cond),
pos.clone(),
)));
}
Ok(())
}
fn op_jump_if_false(&mut self, jp: i32) -> Result<(), Error> {
fn op_jump_if_false(&mut self, jp: i32, pos: &Position) -> Result<(), Error> {
let cond = self.pop()?;
if let &P(Bool(cond)) = cond.as_ref() {
if !cond {
self.op_jump(jp)?;
}
} else {
return Err(dbg!(Error::new(
format!("Expected boolean but got {:?}!", cond),
pos.clone(),
)));
}
Ok(())
}
@ -244,7 +263,7 @@ where
Ok(())
}
fn op_module(&'a mut self, idx: usize, jptr: i32) -> Result<(), Error> {
fn op_module(&'a mut self, idx: usize, jptr: i32, pos: &Position) -> Result<(), Error> {
let mod_val = dbg!(self.pop())?;
let (result_ptr, flds) = match mod_val.as_ref() {
&C(Tuple(ref flds)) => (None, flds.clone()),
@ -253,14 +272,21 @@ where
if let &C(Tuple(ref flds)) = tpl_val.as_ref() {
(Some(ptr), flds.clone())
} else {
return dbg!(Err(Error {}));
return dbg!(Err(Error::new(
format!("Expected tuple but got {:?}", tpl_val),
pos.clone(),
)));
}
}
_ => {
return dbg!(Err(Error {}));
return dbg!(Err(Error::new(
format!("Expected tuple but got {:?}", mod_val),
pos.clone(),
)));
}
};
let mut ops = self.ops.clone();
let pkg_pos = self.ops.pos().unwrap().clone();
ops.jump(idx)?;
let pkg_ptr = if let Some(ref path) = self.ops.path {
let pkg_ops = vec![
@ -270,7 +296,17 @@ where
Op::Runtime(Hook::Import),
Op::Return,
];
Some(OpPointer::new(Rc::new(pkg_ops)))
let pos_list = vec![
pkg_pos.clone(),
pkg_pos.clone(),
pkg_pos.clone(),
pkg_pos.clone(),
pkg_pos.clone(),
];
Some(OpPointer::new(Rc::new(PositionMap {
ops: pkg_ops,
pos: pos_list,
})))
} else {
None
};
@ -283,7 +319,7 @@ where
self.op_jump(jptr)
}
fn op_func(&mut self, idx: usize, jptr: i32) -> Result<(), Error> {
fn op_func(&mut self, idx: usize, jptr: i32, pos: &Position) -> Result<(), Error> {
// get arity from stack
let mut scope_snapshot = self.symbols.snapshot();
scope_snapshot.push();
@ -297,13 +333,18 @@ where
if let &S(ref sym) = e.as_ref() {
bindings.push(sym.clone());
} else {
return dbg!(Err(Error {}));
return dbg!(Err(Error::new(
format!("Not an argument name {:?}", e),
pos.clone(),
)));
}
}
} else {
return dbg!(Err(Error {}));
return dbg!(Err(Error::new(
format!("Fault!!! Bad Argument List"),
pos.clone(),
)));
}
eprintln!("Pushing function definition on stack");
let mut ops = self.ops.clone();
ops.jump(idx)?;
self.push(Rc::new(F(Func {
@ -319,6 +360,7 @@ where
f: &Func,
stack: &mut Vec<Rc<Value>>,
env: Rc<RefCell<Environment<O, E>>>,
pos: &Position,
) -> Result<Rc<Value>, Error> {
let Func {
ref ptr,
@ -332,7 +374,7 @@ where
// TODO(jwall): This should do a better error if there is
// nothing on the stack.
let val = stack.pop().unwrap();
vm.binding_push(nm.clone(), val, false)?;
vm.binding_push(nm.clone(), val, false, pos)?;
}
// proceed to the function body
vm.run()?;
@ -351,10 +393,10 @@ where
Ok(())
}
fn op_fcall(&mut self) -> Result<(), Error> {
fn op_fcall(&mut self, pos: &Position) -> Result<(), Error> {
let f = dbg!(self.pop())?;
if let &F(ref f) = f.as_ref() {
let val = Self::fcall_impl(f, &mut self.stack, self.env.clone())?;
let val = Self::fcall_impl(f, &mut self.stack, self.env.clone(), pos)?;
self.push(dbg!(val))?;
}
Ok(())
@ -365,13 +407,16 @@ where
self.op_jump(jp)
}
fn op_not(&mut self) -> Result<(), Error> {
fn op_not(&mut self, pos: &Position) -> Result<(), Error> {
let operand = self.pop()?;
if let P(Bool(val)) = operand.as_ref() {
self.push(Rc::new(P(Bool(!val))))?;
return Ok(());
}
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(
format!("Expected Boolean but got {:?}", operand),
pos.clone(),
)));
}
fn op_equal(&mut self) -> Result<(), Error> {
@ -381,7 +426,7 @@ where
Ok(())
}
fn op_gt(&mut self) -> Result<(), Error> {
fn op_gt(&mut self, pos: &Position) -> Result<(), Error> {
let left = self.pop()?;
let right = self.pop()?;
match (left.as_ref(), right.as_ref()) {
@ -391,12 +436,17 @@ where
(&P(Float(f)), &P(Float(ff))) => {
self.push(Rc::new(P(Bool(f > ff))))?;
}
_ => return Err(dbg!(Error {})),
_ => {
return Err(dbg!(Error::new(
format!("Expected Numeric values of the same type but got {:?} and {:?}", left, right),
pos.clone(),
)));
},
}
Ok(())
}
fn op_lt(&mut self) -> Result<(), Error> {
fn op_lt(&mut self, pos: &Position) -> Result<(), Error> {
let left = self.pop()?;
let right = self.pop()?;
match (left.as_ref(), right.as_ref()) {
@ -406,12 +456,17 @@ where
(&P(Float(f)), &P(Float(ff))) => {
self.push(Rc::new(P(Bool(f < ff))))?;
}
_ => return Err(dbg!(Error {})),
_ => {
return Err(dbg!(Error::new(
format!("Expected Numeric values of the same type but got {:?} and {:?}", left, right),
pos.clone(),
)));
},
}
Ok(())
}
fn op_lteq(&mut self) -> Result<(), Error> {
fn op_lteq(&mut self, pos: &Position) -> Result<(), Error> {
let left = self.pop()?;
let right = self.pop()?;
match (left.as_ref(), right.as_ref()) {
@ -421,12 +476,17 @@ where
(&P(Float(f)), &P(Float(ff))) => {
self.push(Rc::new(P(Bool(f <= ff))))?;
}
_ => return Err(dbg!(Error {})),
_ => {
return Err(dbg!(Error::new(
format!("Expected Numeric values of the same type but got {:?} and {:?}", left, right),
pos.clone(),
)));
},
}
Ok(())
}
fn op_gteq(&mut self) -> Result<(), Error> {
fn op_gteq(&mut self, pos: &Position) -> Result<(), Error> {
let left = self.pop()?;
let right = self.pop()?;
match (left.as_ref(), right.as_ref()) {
@ -436,65 +496,70 @@ where
(&P(Float(f)), &P(Float(ff))) => {
self.push(Rc::new(P(Bool(f >= ff))))?;
}
_ => return Err(dbg!(Error {})),
_ => {
return Err(dbg!(Error::new(
format!("Expected Numeric values of the same type but got {:?} and {:?}", left, right),
pos.clone(),
)));
},
}
Ok(())
}
fn op_mod(&mut self) -> Result<(), Error> {
fn op_mod(&mut self, pos: &Position) -> Result<(), Error> {
// Adds the previous two items in the stack.
let left = self.pop()?;
let right = self.pop()?;
// Then pushes the result onto the stack.
self.push(Rc::new(P(self.modulus(&left, &right)?)))?;
self.push(Rc::new(P(self.modulus(&left, &right, pos)?)))?;
Ok(())
}
fn op_add(&mut self) -> Result<(), Error> {
fn op_add(&mut self, pos: &Position) -> Result<(), Error> {
// Adds the previous two items in the stack.
let left = self.pop()?;
let right = self.pop()?;
// Then pushes the result onto the stack.
self.push(Rc::new(self.add(&left, &right)?))?;
self.push(Rc::new(self.add(&left, &right, pos)?))?;
Ok(())
}
fn op_sub(&mut self) -> Result<(), Error> {
fn op_sub(&mut self, pos: &Position) -> Result<(), Error> {
// Subtracts the previous two items in the stack.
let left = self.pop()?;
let right = self.pop()?;
// Then pushes the result onto the stack.
self.push(Rc::new(P(self.sub(&left, &right)?)))?;
self.push(Rc::new(P(self.sub(&left, &right, pos)?)))?;
Ok(())
}
fn op_mul(&mut self) -> Result<(), Error> {
fn op_mul(&mut self, pos: &Position) -> Result<(), Error> {
// Multiplies the previous two items in the stack.
let left = self.pop()?;
let right = self.pop()?;
// Then pushes the result onto the stack.
self.push(Rc::new(P(self.mul(&left, &right)?)))?;
self.push(Rc::new(P(self.mul(&left, &right, pos)?)))?;
Ok(())
}
fn op_div(&mut self) -> Result<(), Error> {
fn op_div(&mut self, pos: &Position) -> Result<(), Error> {
// Divides the previous two items in the stack.
let left = self.pop()?;
let right = self.pop()?;
// Then pushes the result onto the stack.
self.push(Rc::new(P(self.div(&left, &right)?)))?;
self.push(Rc::new(P(self.div(&left, &right, pos)?)))?;
Ok(())
}
fn op_bind(&mut self, strict: bool) -> Result<(), Error> {
fn op_bind(&mut self, strict: bool, pos: &Position) -> Result<(), Error> {
// pop val off stack.
let val = self.pop()?;
// pop name off stack.
let name = self.pop()?;
if let &S(ref name) = name.as_ref() {
self.binding_push(name.clone(), val, strict)?;
self.binding_push(name.clone(), val, strict, pos)?;
} else {
return Err(dbg!(Error {}));
unreachable!();
}
Ok(())
}
@ -508,7 +573,7 @@ where
let name = if let &S(ref s) | &P(Str(ref s)) = name_val.as_ref() {
s
} else {
return Err(dbg!(Error {}));
unreachable!();
};
// get composite tuple from stack
let tpl = self.pop()?;
@ -519,7 +584,7 @@ where
// place composite tuple back on stack
self.push(Rc::new(C(Tuple(flds))))?;
} else {
return Err(dbg!(Error {}));
unreachable!();
};
Ok(())
}
@ -536,19 +601,25 @@ where
// Add that value to the list and put list back on stack.
self.push(Rc::new(C(List(elems))))?;
} else {
return Err(dbg!(Error {}));
unreachable!();
};
Ok(())
}
fn find_in_list(&self, index: &Value, elems: &Vec<Rc<Value>>) -> Result<Rc<Value>, Error> {
fn find_in_list(&self, index: &Value, elems: &Vec<Rc<Value>>, pos: &Position) -> Result<Rc<Value>, Error> {
let idx = match index {
P(Int(i)) => i.clone(),
_ => return dbg!(Err(Error {})),
_ => return Err(dbg!(Error::new(
format!("Expected int for index but got {:?}", index),
pos.clone(),
))),
};
match elems.get(idx as usize) {
Some(v) => Ok(v.clone()),
None => Err(dbg!(Error {})),
None => return Err(dbg!(Error::new(
format!("No such index {}", idx),
pos.clone(),
))),
}
}
@ -556,25 +627,35 @@ where
&self,
index: &Value,
flds: &Vec<(String, Rc<Value>)>,
pos: &Position,
) -> Result<Rc<Value>, Error> {
let idx = match index {
S(p) => p,
P(Str(p)) => p,
_ => return dbg!(Err(Error {})),
_ => return Err(dbg!(Error::new(
format!("Expected String or Symbol for index but got {:?}", index),
pos.clone(),
))),
};
for f in flds.iter() {
if idx == &f.0 {
return Ok(f.1.clone());
}
}
Err(dbg!(Error {}))
Err(dbg!(Error::new(
format!("No such field {}", idx),
pos.clone()
)))
}
fn find_in_value(&self, index: &Value, target: &Value) -> Result<Rc<Value>, Error> {
fn find_in_value(&self, index: &Value, target: &Value, pos: &Position) -> Result<Rc<Value>, Error> {
match target {
C(Tuple(flds)) => self.find_in_flds(index, flds),
C(List(elements)) => self.find_in_list(index, elements),
_ => return Err(dbg!(Error {})),
C(Tuple(flds)) => self.find_in_flds(index, flds, pos),
C(List(elements)) => self.find_in_list(index, elements, pos),
_ => return Err(dbg!(Error::new(
format!("Expected tuple for list but got {:?}", target),
pos.clone(),
))),
}
}
@ -582,7 +663,7 @@ where
Ok(())
}
fn op_index(&mut self, safe: bool) -> Result<(), Error> {
fn op_index(&mut self, safe: bool, pos: &Position) -> Result<(), Error> {
// left and then right
let right = dbg!(self.pop()?);
let left = dbg!(self.pop()?);
@ -613,10 +694,13 @@ where
self.push(Rc::new(P(Empty)))?;
return Ok(());
}
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(
format!("Invalid selector index: {:?} target: {:?}", right, left),
pos.clone(),
)));
}
fn op_copy(&mut self) -> Result<(), Error> {
fn op_copy(&mut self, pos: &Position) -> Result<(), Error> {
// get next value. It should be a Module or Tuple.
let tgt = dbg!(self.pop()?);
// This value should always be a tuple
@ -624,7 +708,7 @@ where
let overrides = if let &C(Tuple(ref oflds)) = override_val.as_ref() {
oflds.clone()
} else {
return Err(dbg!(Error {}));
unreachable!();
};
match tgt.as_ref() {
&C(Tuple(ref flds)) => {
@ -674,7 +758,10 @@ where
}
}
_ => {
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(
format!("Expected a Tuple or a Module but got {:?}", tgt),
pos.clone(),
)));
}
}
Ok(())
@ -706,61 +793,80 @@ where
name: String,
val: Rc<Value>,
strict: bool,
pos: &Position,
) -> Result<(), Error> {
if self.symbols.is_bound(&name) && strict {
return Err(dbg!(Error {}));
return Err(dbg!(Error::new(
format!("Binding {} already exists", name),
pos.clone(),
)));
}
self.symbols.add(name, val);
Ok(())
}
pub fn get_binding(&'a self, name: &str) -> Result<Rc<Value>, Error> {
pub fn get_binding(&'a self, name: &str, pos: &Position) -> Result<Rc<Value>, Error> {
match self.symbols.get(name) {
Some(v) => Ok(v),
None => Err(dbg!(Error {})),
None => Err(dbg!(Error::new(
format!("No such binding {}", name),
pos.clone()
))),
}
}
pub fn pop(&mut self) -> Result<Rc<Value>, Error> {
match self.stack.pop() {
Some(v) => Ok(v),
None => Err(dbg!(Error {})),
None => unreachable!(),
}
}
fn mul(&self, left: &Value, right: &Value) -> Result<Primitive, Error> {
fn mul(&self, left: &Value, right: &Value, pos: &Position) -> Result<Primitive, Error> {
Ok(match (left, right) {
(P(Int(i)), P(Int(ii))) => Int(i * ii),
(P(Float(f)), P(Float(ff))) => Float(f * ff),
_ => return Err(dbg!(Error {})),
_ => return Err(dbg!(Error::new(
format!("Expected numeric values of the same type but got {:?} and {:?}", left, right),
pos.clone(),
))),
})
}
fn div(&self, left: &Value, right: &Value) -> Result<Primitive, Error> {
fn div(&self, left: &Value, right: &Value, pos: &Position) -> Result<Primitive, Error> {
Ok(match (left, right) {
(P(Int(i)), P(Int(ii))) => Int(i / ii),
(P(Float(f)), P(Float(ff))) => Float(f / ff),
_ => return Err(dbg!(Error {})),
_ => return Err(dbg!(Error::new(
format!("Expected numeric values of the same type but got {:?} and {:?}", left, right),
pos.clone(),
))),
})
}
fn sub(&self, left: &Value, right: &Value) -> Result<Primitive, Error> {
fn sub(&self, left: &Value, right: &Value, pos: &Position) -> Result<Primitive, Error> {
Ok(match (left, right) {
(P(Int(i)), Value::P(Int(ii))) => Int(i - ii),
(P(Float(f)), Value::P(Float(ff))) => Float(f - ff),
_ => return Err(dbg!(Error {})),
_ => return Err(dbg!(Error::new(
format!("Expected numeric values of the same type but got {:?} and {:?}", left, right),
pos.clone(),
))),
})
}
fn modulus(&self, left: &Value, right: &Value) -> Result<Primitive, Error> {
fn modulus(&self, left: &Value, right: &Value, pos: &Position) -> Result<Primitive, Error> {
Ok(match (left, right) {
(P(Int(i)), Value::P(Int(ii))) => Int(i % ii),
(P(Float(f)), Value::P(Float(ff))) => Float(f % ff),
_ => return Err(dbg!(Error {})),
_ => return Err(dbg!(Error::new(
format!("Expected numeric values of the same type but got {:?} and {:?}", left, right),
pos.clone(),
))),
})
}
fn add(&self, left: &Value, right: &Value) -> Result<Value, Error> {
fn add(&self, left: &Value, right: &Value, pos: &Position) -> Result<Value, Error> {
Ok(match (left, right) {
(P(Int(i)), Value::P(Int(ii))) => P(Int(i + ii)),
(P(Float(f)), Value::P(Float(ff))) => P(Float(f + ff)),
@ -780,13 +886,16 @@ where
}
C(List(new_list))
}
_ => return Err(dbg!(Error {})),
_ => return Err(dbg!(Error::new(
format!("You can not add {:?} and {:?}", left, right),
pos.clone()
))),
})
}
fn op_runtime(&mut self, h: Hook) -> Result<(), Error> {
fn op_runtime(&mut self, h: Hook, pos: &Position) -> Result<(), Error> {
self.runtime
.handle(self.ops.path.as_ref(), h, &mut self.stack, self.env.clone())
.handle(self.ops.path.as_ref(), h, &mut self.stack, self.env.clone(), pos)
}
fn op_render(&mut self) -> Result<(), Error> {