DEV: Plugin the VM to our FileBuilder.

Most of the tests do not yet pass and the main.rs doesn't compile
but we are snapshotting here so we can start fixing unit tests
before we hook directly into the main.rs.
This commit is contained in:
Jeremy Wall 2019-08-26 21:24:17 -05:00
parent 156b55271e
commit e256abfee6
21 changed files with 553 additions and 2588 deletions

View File

@ -23,37 +23,39 @@ use crate::convert::ConverterRegistry;
fn assert_build(input: &str) {
let i_paths = Vec::new();
let cache = MemoryCache::new();
let registry = ConverterRegistry::make_registry();
let mut b = FileBuilder::new("<Eval>", &i_paths, Rc::new(RefCell::new(cache)), &registry);
let out_buffer: Vec<u8> = Vec::new();
let err_buffer: Vec<u8> = Vec::new();
let mut b = FileBuilder::new("<Eval>", &i_paths, out_buffer, err_buffer);
b.enable_validate_mode();
b.eval_string(input).unwrap();
if !b.assert_collector.success {
assert!(false, b.assert_collector.failures);
}
// FIXME(jwall): What do we want to do with the assert collector?
//if !b.assert_collector.success {
// assert!(false, b.assert_collector.failures);
//}
}
fn assert_build_failure(input: &str, expect: Vec<Regex>) {
let i_paths = Vec::new();
let cache = MemoryCache::new();
let registry = ConverterRegistry::make_registry();
let mut b = FileBuilder::new("<Eval>", &i_paths, Rc::new(RefCell::new(cache)), &registry);
let out_buffer: Vec<u8> = Vec::new();
let err_buffer: Vec<u8> = Vec::new();
let mut b = FileBuilder::new("<Eval>", &i_paths, out_buffer, err_buffer);
b.enable_validate_mode();
let err = b.eval_string(input);
match err {
Ok(_) => {
for r in expect.iter() {
if !b.assert_collector.success {
if let None = r.find(&b.assert_collector.failures) {
assert!(
false,
"[{}] was not found in Assertion Failures:\n{}",
r, b.assert_collector.failures
);
}
} else {
assert!(false, "Building input Did not panic!");
}
// FIXME(jwall): Assert collector...
//if !b.assert_collector.success {
// if let None = r.find(&b.assert_collector.failures) {
// assert!(
// false,
// "[{}] was not found in Assertion Failures:\n{}",
// r, b.assert_collector.failures
// );
// }
//} else {
// assert!(false, "Building input Did not panic!");
//}
}
}
Err(ref err) => {

View File

@ -13,8 +13,6 @@
// limitations under the License.
//! The format string logic for ucg format expressions.
use std::cell::RefCell;
use std::clone::Clone;
use std::error::Error;
use std::str::Chars;
@ -22,9 +20,6 @@ use abortable_parser::iter::SliceIter;
use abortable_parser::Result as ParseResult;
use crate::ast::*;
use crate::build::assets;
use crate::build::{FileBuilder, Val};
use crate::error;
use crate::iter;
use crate::parse;
use crate::tokenizer;
@ -47,29 +42,13 @@ impl SimpleTemplate {
}
}
/// Implements the logic for format strings in UCG format expressions.
pub struct SimpleFormatter<V: Into<String> + Clone> {
tmpl: String,
args: Vec<V>,
}
impl<V: Into<String> + Clone> SimpleFormatter<V> {
/// Constructs a Formatter with a template and args.
pub fn new<S: Into<String>>(tmpl: S, args: Vec<V>) -> Self {
SimpleFormatter {
tmpl: tmpl.into(),
args: args,
}
}
}
impl TemplateParser for SimpleTemplate {
fn parse(&self, input: &str) -> TemplateResult {
let mut result = Vec::new();
let mut count = 0;
let mut should_escape = false;
let mut buf: Vec<char> = Vec::new();
for c in dbg!(input).chars() {
for c in input.chars() {
if c == '@' && !should_escape {
result.push(TemplatePart::Str(buf));
buf = Vec::new();
@ -81,7 +60,6 @@ impl TemplateParser for SimpleTemplate {
continue;
} else {
buf.push(c);
dbg!(&buf);
}
should_escape = false;
}
@ -92,59 +70,6 @@ impl TemplateParser for SimpleTemplate {
}
}
impl<V: Into<String> + Clone> FormatRenderer for SimpleFormatter<V> {
/// Renders a formatter to a string or returns an error.
///
/// If the formatter has the wrong number of arguments for the number of replacements
/// it will return an error. Otherwise it will return the formatted string.
fn render(&self, pos: &Position) -> Result<String, Box<dyn Error>> {
let mut buf = String::new();
let mut count = 0;
let parser = SimpleTemplate::new();
let parts = parser.parse(&self.tmpl)?;
for p in parts {
match p {
TemplatePart::PlaceHolder(idx) => {
if idx == self.args.len() {
return Err(error::BuildError::with_pos(
"Too few arguments to string \
formatter.",
error::ErrorType::FormatError,
pos.clone(),
)
.to_boxed());
}
let arg = self.args[count].clone();
let strval = arg.into();
buf.push_str(&strval);
count += 1;
}
TemplatePart::Str(cs) => {
buf.reserve(cs.len());
for c in cs {
buf.push(c);
}
}
TemplatePart::Expression(_) => unreachable!(),
}
}
if self.args.len() != count {
return Err(error::BuildError::with_pos(
format!(
"Too many arguments to string \
formatter. Expected {} got {}",
count,
self.args.len()
),
error::ErrorType::FormatError,
pos.clone(),
)
.to_boxed());
}
return Ok(buf);
}
}
pub struct ExpressionTemplate();
impl ExpressionTemplate {
@ -226,157 +151,3 @@ impl TemplateParser for ExpressionTemplate {
Ok(parts)
}
}
pub struct ExpressionFormatter<'a, C>
where
C: assets::Cache,
{
tmpl: String,
builder: RefCell<FileBuilder<'a, C>>,
}
impl<'a, C> ExpressionFormatter<'a, C>
where
C: assets::Cache,
{
pub fn new<S: Into<String>>(tmpl: S, builder: FileBuilder<'a, C>) -> Self {
ExpressionFormatter {
tmpl: tmpl.into(),
builder: RefCell::new(builder),
}
}
fn consume_expr(
&self,
builder: &mut FileBuilder<'a, C>,
iter: &mut Chars,
pos: &Position,
) -> Result<Val, Box<dyn Error>> {
// we expect the next char to be { or we error.
let mut expr_string = String::new();
let mut brace_count = 0;
match iter.next() {
Some(c) => {
if c == '{' {
brace_count += 1;
} else {
return Err(error::BuildError::with_pos(
format!(
"Invalid syntax for format string expected '{{' but got {}",
c
),
error::ErrorType::FormatError,
pos.clone(),
)
.to_boxed());
}
}
None => {
return Err(error::BuildError::with_pos(
"Invalid syntax for format string expected '{' but string ended",
error::ErrorType::FormatError,
pos.clone(),
)
.to_boxed());
}
};
loop {
let c = match iter.next() {
Some(c) => c,
None => break,
};
if c == '{' {
brace_count += 1;
}
if c == '}' {
brace_count -= 1;
// if brace_count is 0 then this is the end of expression.
if brace_count != 0 {
// if it is not zero then this character is just part of
// the embedded expression.
expr_string.push(c);
continue;
}
// empty expressions are an error
if expr_string.is_empty() {
return Err(error::BuildError::with_pos(
"Got an empty expression in format string",
error::ErrorType::FormatError,
pos.clone(),
)
.to_boxed());
}
if !expr_string.ends_with(";") {
expr_string.push(';');
}
// we are done and it is time to compute the expression and return it.
return Ok(builder.eval_string(&expr_string)?.as_ref().clone());
} else {
expr_string.push(c);
}
}
return Err(error::BuildError::with_pos(
"Expected '}' but got end of string",
error::ErrorType::FormatError,
pos.clone(),
)
.to_boxed());
}
}
impl<'a, C> FormatRenderer for ExpressionFormatter<'a, C>
where
C: assets::Cache,
{
fn render(&self, pos: &Position) -> Result<String, Box<dyn Error>> {
let mut buf = String::new();
let mut should_escape = false;
let mut iter = self.tmpl.chars();
loop {
let c = match iter.next() {
Some(c) => c,
None => break,
};
if c == '@' && !should_escape {
// This is kind of wasteful. Can we do better?
let val = self.consume_expr(&mut self.builder.borrow_mut(), &mut iter, pos)?;
let strval: String = val.into();
buf.push_str(&strval);
should_escape = false;
} else if c == '\\' && !should_escape {
should_escape = true;
} else {
buf.push(c);
should_escape = false;
}
}
return Ok(buf);
}
}
#[cfg(test)]
mod test {
use super::{FormatRenderer, SimpleFormatter};
use crate::ast::Position;
#[test]
fn test_format_happy_path() {
let formatter = SimpleFormatter::new("foo @ @ \\@", vec!["bar", "quux"]);
let pos = Position::new(0, 0, 0);
assert_eq!(formatter.render(&pos).unwrap(), "foo bar quux @");
}
#[test]
fn test_format_happy_wrong_too_few_args() {
let formatter = SimpleFormatter::new("foo @ @ \\@", vec!["bar"]);
let pos = Position::new(0, 0, 0);
assert!(formatter.render(&pos).is_err());
}
#[test]
fn test_format_happy_wrong_too_many_args() {
let formatter = SimpleFormatter::new("foo @ @ \\@", vec!["bar", "quux", "baz"]);
let pos = Position::new(0, 0, 0);
assert!(formatter.render(&pos).is_err());
}
}

View File

@ -20,8 +20,6 @@ pub enum Val {
List(Vec<Rc<Val>>),
Tuple(Vec<(String, Rc<Val>)>),
Env(Vec<(String, String)>),
Func(FuncDef),
Module(ModuleDef),
}
impl Val {
@ -36,8 +34,6 @@ impl Val {
&Val::List(_) => "List".to_string(),
&Val::Tuple(_) => "Tuple".to_string(),
&Val::Env(_) => "Env".to_string(),
&Val::Func(_) => "Func".to_string(),
&Val::Module(_) => "Module".to_string(),
}
}
@ -53,9 +49,7 @@ impl Val {
&Val::Str(_),
&Val::List(_),
&Val::Tuple(_),
&Val::Env(_),
&Val::Func(_),
&Val::Module(_)
&Val::Env(_)
)
}
@ -99,14 +93,6 @@ impl Val {
Ok(true)
}
}
(&Val::Func(_), &Val::Func(_)) => Err(error::BuildError::new(
"Func are not comparable",
error::ErrorType::TypeFail,
)),
(&Val::Module(_), &Val::Module(_)) => Err(error::BuildError::new(
"Module are not comparable",
error::ErrorType::TypeFail,
)),
// EMPTY is always comparable for equality.
(&Val::Empty, _) => Ok(false),
(_, &Val::Empty) => Ok(false),
@ -182,25 +168,12 @@ impl Val {
return false;
}
pub fn is_func(&self) -> bool {
if let &Val::Func(_) = self {
return true;
}
return false;
}
pub fn is_str(&self) -> bool {
if let &Val::Str(_) = self {
return true;
}
return false;
}
pub fn is_module(&self) -> bool {
if let &Val::Module(_) = self {
return true;
}
return false;
}
}
impl Display for Val {
@ -218,8 +191,6 @@ impl Display for Val {
}
write!(f, "]")
}
&Val::Func(_) => write!(f, "Func(..)"),
&Val::Module(_) => write!(f, "Module{{..}}"),
&Val::Tuple(ref def) => {
write!(f, "{{\n")?;
for v in def.iter() {

File diff suppressed because it is too large Load Diff

53
src/build/opcode/debug.rs Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2019 Jeremy Wall
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::fmt;
use super::Composite;
use super::Primitive;
use super::Value;
use Composite::{List, Tuple};
use Primitive::{Bool, Empty, Float, Int, Str};
use Value::{C, F, M, P, S, T};
impl fmt::Debug for Value {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
match self {
P(Bool(v)) => write!(w, "Bool({})", v),
P(Int(v)) => write!(w, "Int({})", v),
P(Float(v)) => write!(w, "Float({})", v),
P(Str(v)) => write!(w, "String({})", v),
P(Empty) => write!(w, "NULL"),
C(List(ref els)) => {
write!(w, "List[")?;
for e in els {
write!(w, "{:?},", e)?;
}
write!(w, "]")
}
C(Tuple(ref flds)) => {
write!(w, "Tuple(")?;
for (k, v) in flds {
write!(w, "\"{}\"={:?},", k, v)?;
}
write!(w, ")")
}
F(_) => write!(w, "<Func>"),
M(_) => write!(w, "<Module>"),
T(_) => write!(w, "<Expression>"),
S(v) => write!(w, "Symbol({})", v),
}
}
}

View File

@ -12,12 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::BTreeMap;
use std::io::Write;
use std::io::{Write, Read};
use std::rc::Rc;
use std::path::PathBuf;
use std::fs::File;
use super::pointer::OpPointer;
use super::cache;
use super::Value;
use super::Error;
use crate::convert::{ConverterRegistry, ImporterRegistry};
use crate::iter::OffsetStrIter;
use crate::parse::parse;
// Shared Environmental between VM's for runtime usage.
pub struct Environment<Stdout, Stderr>
@ -26,18 +32,23 @@ where
Stderr: Write,
{
pub val_cache: BTreeMap<String, Rc<Value>>,
pub op_cache: cache::Ops, // Shared environment
pub converter_registry: ConverterRegistry, // Shared environment
pub importer_registry: ImporterRegistry, // Shared environment
pub stdout: Stdout, // Shared environment
pub stderr: Stderr, // Shared environment
// TODO(jwall): Environment Variables
pub op_cache: cache::Ops,
pub converter_registry: ConverterRegistry,
pub importer_registry: ImporterRegistry,
pub stdout: Stdout,
pub stderr: Stderr,
pub env_vars: BTreeMap<String, String>, // Environment Variables
}
impl<Stdout: Write, Stderr: Write> Environment<Stdout, Stderr> {
pub fn new(out: Stdout, err: Stderr) -> Self {
Self::new_with_vars(out, err, BTreeMap::new())
}
pub fn new_with_vars(out: Stdout, err: Stderr, vars: BTreeMap<String, String>) -> Self {
Self {
val_cache: BTreeMap::new(),
env_vars: vars,
op_cache: cache::Ops::new(),
converter_registry: ConverterRegistry::make_registry(),
importer_registry: ImporterRegistry::make_registry(),
@ -45,4 +56,34 @@ impl<Stdout: Write, Stderr: Write> Environment<Stdout, Stderr> {
stderr: err,
}
}
pub fn get_cached_path_val(&self, path: &String) -> Option<Rc<Value>> {
self.val_cache.get(path).cloned()
}
pub fn update_path_val(&mut self, path: &String, val: Rc<Value>) {
self.val_cache.insert(path.clone(), val);
}
pub fn get_ops_for_path(&mut self, path: &String) -> Result<OpPointer, Error> {
let op_pointer = self.op_cache.entry(path).get_pointer_or_else(
|| {
// FIXME(jwall): We need to do proper error handling here.
let p = PathBuf::from(&path);
let root = p.parent().unwrap();
// first we read in the file
let mut f = File::open(&path).unwrap();
// then we parse it
let mut contents = String::new();
f.read_to_string(&mut contents).unwrap();
let iter = OffsetStrIter::new(&contents).with_src_file(&p);
let stmts = parse(iter, None).unwrap();
// then we create an ops from it
let ops = super::translate::AST::translate(stmts, &root);
ops
},
&path,
);
Ok(op_pointer)
}
}

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::convert::From;
use std::fmt;
use std::fmt::Display;
use crate::ast::Position;
@ -30,14 +32,32 @@ impl Error {
}
}
impl<E> From<E> for Error
where
E: std::error::Error + Sized,
{
fn from(e: E) -> Self {
impl From<regex::Error> for Error {
fn from(e: regex::Error) -> Self {
Error {
message: e.description().to_owned(),
message: format!("{}", e),
pos: None,
}
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Error {
message: format!("{}", e),
pos: None,
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ref pos) = self.pos {
write!(f, "{} at {}", self.message, pos)
} else {
write!(f, "{}", self.message)
}
}
}
impl std::error::Error for Error {}

View File

@ -15,14 +15,16 @@ use std::convert::{TryFrom, TryInto};
use std::rc::Rc;
mod cache;
mod environment;
mod debug;
pub mod environment;
mod error;
pub mod pointer;
mod runtime;
pub mod scope;
mod translate;
pub mod translate;
mod vm;
pub use environment::Environment;
pub use error::Error;
pub use vm::VM;
@ -43,6 +45,24 @@ pub enum Primitive {
use Primitive::{Bool, Empty, Float, Int, Str};
impl Value {
fn type_name(&self) -> &'static str {
match self {
P(Int(_)) => "Int",
P(Float(_)) => "Float",
P(Str(_)) => "String",
P(Bool(_)) => "Bool",
P(Empty) => "NULL",
C(List(_)) => "List",
C(Tuple(_)) => "Tuple",
F(_) => "Func",
M(_) => "Func",
T(_) => "Expression",
S(_) => "Symbol",
}
}
}
impl From<&Primitive> for String {
fn from(p: &Primitive) -> Self {
match p {
@ -107,7 +127,7 @@ pub struct Module {
pkg_ptr: Option<OpPointer>,
}
#[derive(Debug, PartialEq, Clone)]
#[derive(PartialEq, Clone)]
pub enum Value {
// Binding names.
S(String),
@ -218,29 +238,30 @@ pub enum Op {
use super::ir::Val;
impl TryFrom<Rc<Value>> for Val {
type Error = Error;
fn try_from(val: Rc<Value>) -> Result<Val, Self::Error> {
val.as_ref().try_into()
impl From<Rc<Value>> for Val {
fn from(val: Rc<Value>) -> Val {
val.as_ref().into()
}
}
impl TryFrom<&Value> for Val {
type Error = Error;
impl From<Value> for Val {
fn from(val: Value) -> Val {
(&val).into()
}
}
fn try_from(val: &Value) -> Result<Val, Self::Error> {
Ok(match val {
impl From<&Value> for Val {
fn from(val: &Value) -> Val {
match val {
P(Int(i)) => Val::Int(*i),
P(Float(f)) => Val::Float(*f),
P(Str(s)) => Val::Str(s.clone()),
P(Bool(b)) => Val::Boolean(*b),
P(Empty) => Val::Empty,
C(Tuple(fs)) => {
let mut flds = Vec::new();
for &(ref k, ref v) in fs.iter() {
let v = v.clone();
flds.push((k.clone(), Rc::new(v.try_into()?)));
flds.push((k.clone(), Rc::new(v.into())));
}
Val::Tuple(flds)
}
@ -248,33 +269,30 @@ impl TryFrom<&Value> for Val {
let mut els = Vec::new();
for e in elems.iter() {
let e = e.clone();
els.push(Rc::new(e.try_into()?));
els.push(Rc::new(e.into()));
}
Val::List(els)
}
S(_) | F(_) | M(_) | T(_) => {
return Err(dbg!(Error::new(
format!("Invalid Value {:?} to Val translation", val),
Position::new(0, 0, 0)
)));
}
})
S(_) | F(_) | M(_) | T(_) | P(Empty) => Val::Empty,
}
}
}
impl TryFrom<Rc<Val>> for Value {
type Error = Error;
fn try_from(val: Rc<Val>) -> Result<Self, Self::Error> {
val.as_ref().try_into()
impl From<Rc<Val>> for Value {
fn from(val: Rc<Val>) -> Self {
val.as_ref().into()
}
}
impl TryFrom<&Val> for Value {
type Error = Error;
impl From<Val> for Value {
fn from(val: Val) -> Self {
(&val).into()
}
}
fn try_from(val: &Val) -> Result<Self, Self::Error> {
Ok(match val {
impl From<&Val> for Value {
fn from(val: &Val) -> Self {
match val {
Val::Int(i) => P(Int(*i)),
Val::Float(f) => P(Float(*f)),
Val::Boolean(b) => P(Bool(*b)),
@ -284,7 +302,7 @@ impl TryFrom<&Val> for Value {
let mut lst = Vec::new();
for e in els.iter() {
let e = e.clone();
lst.push(Rc::new(e.try_into()?));
lst.push(Rc::new(e.into()));
}
C(List(lst))
}
@ -292,7 +310,7 @@ impl TryFrom<&Val> for Value {
let mut field_list = Vec::new();
for &(ref key, ref val) in flds.iter() {
let val = val.clone();
field_list.push((key.clone(), Rc::new(val.try_into()?)));
field_list.push((key.clone(), Rc::new(val.into())));
}
C(Tuple(field_list))
}
@ -303,15 +321,7 @@ impl TryFrom<&Val> for Value {
}
C(Tuple(field_list))
}
// TODO(jwall): These can go away eventually when we replace the tree
// walking interpreter.
Val::Module(_) | Val::Func(_) => {
return Err(dbg!(Error::new(
format!("Invalid Translation from Val {} to Value", val),
Position::new(0, 0, 0)
)))
}
})
}
}
}

View File

@ -60,13 +60,13 @@ impl OpPointer {
self.ptr = Some(ptr);
return Ok(());
}
Err(dbg!(Error::new(
Err(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> {
@ -86,10 +86,10 @@ impl OpPointer {
pub fn idx(&self) -> Result<usize, Error> {
match self.ptr {
Some(ptr) => Ok(ptr),
None => dbg!(Err(Error::new(
None => Err(Error::new(
format!("FAULT!!! Position Check failure!"),
Position::new(0, 0, 0),
))),
)),
}
}

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::cell::RefCell;
use std::convert::{TryFrom, TryInto};
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
@ -27,8 +26,6 @@ use super::{Composite, Error, Hook, Primitive, Value};
use crate::ast::Position;
use crate::build::ir::Val;
use crate::build::AssertCollector;
use crate::iter::OffsetStrIter;
use crate::parse::parse;
use Composite::{List, Tuple};
use Primitive::{Bool, Empty, Int, Str};
@ -36,6 +33,7 @@ pub struct Builtins {
assert_results: AssertCollector,
working_dir: PathBuf,
import_path: Vec<PathBuf>,
validate_mode: bool,
}
impl Builtins {
@ -47,7 +45,9 @@ impl Builtins {
Self {
assert_results: AssertCollector::new(),
working_dir: path.into(),
// FIXME(jwall): This should probably be injected in.
import_path: Vec::new(),
validate_mode: false,
}
}
@ -56,9 +56,14 @@ impl Builtins {
assert_results: AssertCollector::new(),
working_dir: self.working_dir.clone(),
import_path: self.import_path.clone(),
validate_mode: self.validate_mode,
}
}
pub fn enable_validate_mode(&mut self) {
self.validate_mode = true;
}
pub fn handle<P: AsRef<Path>, O, E>(
&mut self,
path: Option<P>,
@ -115,10 +120,10 @@ impl Builtins {
}
match normalized.canonicalize() {
Ok(p) => Ok(p),
Err(_e) => Err(dbg!(Error::new(
Err(_e) => Err(Error::new(
format!("Invalid path: {}", normalized.to_string_lossy()),
pos.clone(),
))),
)),
}
}
@ -134,6 +139,14 @@ impl Builtins {
Ok(contents)
}
// FIXME(jwall): Should probably move this to the runtime.
//fn detect_import_cycle(&self, path: &str) -> bool {
// self.scope
// .import_stack
// .iter()
// .find(|p| *p == path)
// .is_some()
//}
fn import<O, E>(
&mut self,
stack: &mut Vec<(Rc<Value>, Position)>,
@ -148,37 +161,22 @@ impl Builtins {
if let Some((val, path_pos)) = path {
if let &Value::P(Str(ref path)) = val.as_ref() {
let mut borrowed_env = env.borrow_mut();
let val_cache = &mut borrowed_env.val_cache;
if val_cache.contains_key(path) {
stack.push((val_cache[path].clone(), path_pos));
} else {
let op_pointer = env.borrow_mut().op_cache.entry(path).get_pointer_or_else(
|| {
// FIXME(jwall): We need to do proper error handling here.
let p = PathBuf::from(&path);
let root = p.parent().unwrap();
// first we read in the file
let mut f = File::open(&path).unwrap();
// then we parse it
let mut contents = String::new();
f.read_to_string(&mut contents).unwrap();
let iter = OffsetStrIter::new(&contents).with_src_file(&p);
let stmts = parse(iter, None).unwrap();
// then we create an ops from it
let ops = super::translate::AST::translate(stmts, &root);
ops
},
&path,
);
let mut vm = VM::with_pointer(op_pointer, env.clone());
vm.run()?;
let result = Rc::new(vm.symbols_to_tuple(true));
val_cache.insert(path.clone(), result.clone());
stack.push((result, pos));
match borrowed_env.get_cached_path_val(path) {
Some(v) => {
stack.push((v, path_pos));
}
None => {
let op_pointer = borrowed_env.get_ops_for_path(path)?;
let mut vm = VM::with_pointer(op_pointer, env.clone());
vm.run()?;
let result = Rc::new(vm.symbols_to_tuple(true));
borrowed_env.update_path_val(&path, result.clone());
stack.push((result, pos));
}
}
return Ok(());
}
return Err(dbg!(Error::new(format!("Invalid Path {:?}", val), pos,)));
return Err(Error::new(format!("Invalid Path {:?}", val), pos));
}
unreachable!();
}
@ -199,10 +197,7 @@ impl Builtins {
if let &Value::P(Str(ref path)) = val.as_ref() {
path.clone()
} else {
return Err(dbg!(Error::new(
format!("Invalid Path {:?}", val),
path_pos,
)));
return Err(Error::new(format!("Invalid Path {:?}", val), path_pos));
}
} else {
unreachable!();
@ -211,10 +206,10 @@ impl Builtins {
if let &Value::P(Str(ref typ)) = val.as_ref() {
typ.clone()
} else {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("Expected conversion type but got {:?}", val),
typ_pos,
)));
));
}
} else {
unreachable!();
@ -234,16 +229,13 @@ impl Builtins {
P(Empty)
} else {
match importer.import(contents.as_bytes()) {
Ok(v) => v.try_into()?,
Err(e) => return Err(dbg!(Error::new(format!("{}", e), pos,))),
Ok(v) => v.into(),
Err(e) => return Err(Error::new(format!("{}", e), pos)),
}
}
}
None => {
return Err(dbg!(Error::new(
format!("No such conversion type {}", &typ),
pos,
)))
return Err(Error::new(format!("No such conversion type {}", &typ), pos))
}
}),
pos,
@ -306,26 +298,26 @@ impl Builtins {
};
let val = stack.pop();
if let Some((val, val_pos)) = val {
let val = val.try_into()?;
let val = val.into();
let c_type = stack.pop();
if let Some((c_type_val, c_type_pos)) = c_type {
if let &Value::S(ref c_type) = c_type_val.as_ref() {
if let Some(c) = env.borrow().converter_registry.get_converter(c_type) {
if let Err(e) = c.convert(Rc::new(val), &mut writer) {
return Err(dbg!(Error::new(format!("{}", e), pos.clone(),)));
return Err(Error::new(format!("{}", e), pos.clone()));
}
return Ok(());
} else {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("No such conversion type {:?}", c_type),
c_type_pos,
)));
));
}
}
return Err(dbg!(Error::new(
return Err(Error::new(
format!("Not a conversion type {:?}", c_type_val),
val_pos,
)));
));
}
}
unreachable!();
@ -343,7 +335,7 @@ impl Builtins {
{
let val = stack.pop();
if let Some((val, val_pos)) = val {
let val = val.try_into()?;
let val = val.into();
if let Some((c_type_val, c_typ_pos)) = 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) {
@ -358,20 +350,20 @@ impl Builtins {
));
}
Err(_e) => {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("No such conversion type {:?}", c_type),
c_typ_pos,
)));
));
}
}
return Ok(());
}
}
}
return Err(dbg!(Error::new(
return Err(Error::new(
format!("Not a conversion type {:?}", val),
val_pos,
)));
));
}
unreachable!()
}
@ -402,7 +394,7 @@ impl Builtins {
let f = if let &F(ref f) = fptr.as_ref() {
f
} else {
return Err(dbg!(Error::new(format!("Not a function!!"), fptr_pos)));
return Err(Error::new(format!("Not a function!!"), fptr_pos));
};
match list.as_ref() {
@ -426,24 +418,24 @@ impl Builtins {
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::new(
return Err(Error::new(
format!(
"Map Functions over tuples must return a list of two items"
),
result_pos,
)));
));
}
let name = match fval[0].as_ref() {
&P(Str(ref name)) => name.clone(),
_ => return Err(dbg!(Error::new(
_ => return Err(Error::new(
format!("Map functions over tuples must return a String as the first list item"),
result_pos,
))),
)),
};
new_fields.push((name, fval[1].clone()));
}
}
stack.push((Rc::new(C(Tuple(dbg!(new_fields)))), pos));
stack.push((Rc::new(C(Tuple(new_fields))), pos));
}
&P(Str(ref s)) => {
let mut buf = String::new();
@ -454,19 +446,19 @@ impl Builtins {
if let &P(Str(ref s)) = result.as_ref() {
buf.push_str(s);
} else {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("Map functions over string should return strings"),
result_pos
)));
result_pos,
));
}
}
stack.push((Rc::new(P(Str(buf))), pos));
}
_ => {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("You can only map over lists, tuples, or strings"),
pos,
)))
))
}
};
Ok(())
@ -498,7 +490,7 @@ impl Builtins {
let f = if let &F(ref f) = fptr.as_ref() {
f
} else {
return Err(dbg!(Error::new(format!("Not a function!!"), fptr_pos)));
return Err(Error::new(format!("Not a function!!"), fptr_pos));
};
match list.as_ref() {
@ -535,7 +527,7 @@ impl Builtins {
_ => new_fields.push((name.clone(), val.clone())),
}
}
stack.push((Rc::new(C(Tuple(dbg!(new_fields)))), pos));
stack.push((Rc::new(C(Tuple(new_fields))), pos));
}
&P(Str(ref s)) => {
let mut buf = String::new();
@ -555,10 +547,10 @@ impl Builtins {
stack.push((Rc::new(P(Str(buf))), pos));
}
_ => {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("You can only filter over lists, tuples, or strings"),
pos,
)))
))
}
}
Ok(())
@ -570,10 +562,10 @@ impl Builtins {
if let &P(Str(ref s)) = val.as_ref() {
s.clone()
} else {
return dbg!(Err(Error::new(
return Err(Error::new(
format!("Expected string bug got {:?}", val),
val_pos,
)));
));
}
} else {
unreachable!();
@ -584,10 +576,10 @@ impl Builtins {
if let &P(Str(ref s)) = val.as_ref() {
s.clone()
} else {
return dbg!(Err(Error::new(
return Err(Error::new(
format!("Expected string bug got {:?}", val),
val_pos,
)));
));
}
} else {
unreachable!();
@ -631,15 +623,15 @@ impl Builtins {
let f = if let &F(ref f) = fptr.as_ref() {
f
} else {
return dbg!(Err(Error::new(format!("Not a function!"), fptr_pos)));
return Err(Error::new(format!("Not a function!"), fptr_pos));
};
match list.as_ref() {
&C(List(ref elems)) => {
for e in dbg!(elems).iter() {
for e in elems.iter() {
// push function arguments on the stack.
stack.push((dbg!(e.clone()), list_pos.clone()));
stack.push((dbg!(acc.clone()), acc_pos.clone()));
stack.push((e.clone(), list_pos.clone()));
stack.push((acc.clone(), acc_pos.clone()));
// call function and push it's result on the stack.
let (new_acc, new_acc_pos) = VM::fcall_impl(f, stack, env.clone())?;
acc = new_acc;
@ -651,7 +643,7 @@ impl Builtins {
// push function arguments on the stack.
stack.push((val.clone(), list_pos.clone()));
stack.push((Rc::new(P(Str(name.clone()))), list_pos.clone()));
stack.push((dbg!(acc.clone()), acc_pos.clone()));
stack.push((acc.clone(), acc_pos.clone()));
// call function and push it's result on the stack.
let (new_acc, new_acc_pos) = VM::fcall_impl(f, stack, env.clone())?;
acc = new_acc;
@ -661,8 +653,8 @@ impl Builtins {
&P(Str(ref _s)) => {
for c in _s.chars() {
// push function arguments on the stack.
stack.push((dbg!(Rc::new(P(Str(c.to_string())))), list_pos.clone()));
stack.push((dbg!(acc.clone()), acc_pos.clone()));
stack.push((Rc::new(P(Str(c.to_string()))), list_pos.clone()));
stack.push((acc.clone(), acc_pos.clone()));
// call function and push it's result on the stack.
let (new_acc, new_acc_pos) = VM::fcall_impl(f, stack, env.clone())?;
acc = new_acc;
@ -670,15 +662,15 @@ impl Builtins {
}
}
_ => {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("You can only reduce over lists, tuples, or strings"),
pos.clone()
)))
pos.clone(),
))
}
};
// push the acc on the stack as our result
stack.push((dbg!(acc), pos));
stack.push((acc, pos));
Ok(())
}
@ -716,10 +708,10 @@ impl Builtins {
}
}
_ => {
return dbg!(Err(Error::new(
return Err(Error::new(
format!("Ranges can only be created with Ints"),
pos,
)));
));
}
}
stack.push((Rc::new(C(List(elems))), pos));
@ -736,20 +728,20 @@ impl Builtins {
O: std::io::Write,
E: std::io::Write,
{
let (val, val_pos) = if let Some(val) = dbg!(stack.pop()) {
let (val, val_pos) = if let Some(val) = stack.pop() {
val
} else {
unreachable!();
};
let expr = stack.pop();
let expr_pretty = match expr {
Some((ref expr, _)) => match dbg!(expr.as_ref()) {
Some((ref expr, _)) => match expr.as_ref() {
&P(Str(ref expr)) => expr.clone(),
_ => unreachable!(),
},
_ => unreachable!(),
};
let writable_val: Val = TryFrom::try_from(val.clone())?;
let writable_val: Val = val.clone().into();
if let Err(e) = writeln!(
&mut env.borrow_mut().stderr,
"TRACE: {} = {} at {}",
@ -757,7 +749,7 @@ impl Builtins {
writable_val,
&val_pos
) {
return Err(dbg!(Error::new(format!("{}", e), pos)));
return Err(Error::new(format!("{}", e), pos));
};
stack.push((val, val_pos));
Ok(())

View File

@ -41,7 +41,7 @@ macro_rules! assert_cases {
};
let mut vm = VM::new(Rc::new(map), env);
vm.run().unwrap();
assert_eq!(dbg!(vm.pop()).unwrap().0, Rc::new(case.1));
assert_eq!(vm.pop().unwrap().0, Rc::new(case.1));
}
};
@ -792,9 +792,30 @@ fn simple_selects() {
];
}
#[test]
#[should_panic]
fn select_fails() {
assert_parse_cases![
"select \"quux\", { foo = 1, bar = 2, };" => P(Int(1)),
];
}
#[test]
fn select_compound_expressions() {
assert_parse_cases![
"select \"foo\", { foo = 1, bar = 2, } == 1;" => P(Bool(true)),
"select \"foo\", { foo = 1, bar = 2, } == 2;" => P(Bool(false)),
"select \"foo\", 3, { foo = 1, bar = 2, } == 2;" => P(Bool(false)),
"select \"quux\", 3, { foo = 1, bar = 2, } == 3;" => P(Bool(true)),
"let want = \"foo\"; select want, { foo = 1, bar = 2, } == 1;" => P(Bool(true)),
"let want = \"foo\"; select want, 3, { foo = 1, bar = 2, } == 1;" => P(Bool(true)),
"{ok = select \"foo\", { foo = 1, bar = 2, } == 2}.ok;" => P(Bool(false)),
];
}
#[test]
fn simple_trace() {
let stmts = parse(OffsetStrIter::from(dbg!("TRACE 1+1;")), None).unwrap();
let stmts = parse(OffsetStrIter::from("TRACE 1+1;"), None).unwrap();
let root = std::env::current_dir().unwrap();
let ops = Rc::new(translate::AST::translate(stmts, &root));
assert!(ops.len() > 0);

View File

@ -52,36 +52,40 @@ impl AST {
return ops;
}
pub fn translate_stmt(stmt: Statement, mut ops: &mut PositionMap, root: &Path) {
match stmt {
Statement::Expression(expr) => {
let expr_pos = expr.pos().clone();
Self::translate_expr(expr, &mut ops, root);
ops.push(Op::Pop, expr_pos);
}
Statement::Assert(pos, expr) => {
Self::translate_expr(expr, &mut ops, root);
ops.push(Op::Runtime(Hook::Assert), pos);
}
Statement::Let(def) => {
let binding = def.name.fragment;
ops.push(Op::Sym(binding), def.name.pos);
Self::translate_expr(def.value, &mut ops, root);
ops.push(Op::Bind, def.pos);
}
Statement::Output(pos, tok, expr) => {
ops.push(Op::Val(Primitive::Str(tok.fragment)), tok.pos);
Self::translate_expr(expr, &mut ops, root);
ops.push(Op::Runtime(Hook::Out), pos);
}
Statement::Print(pos, tok, expr) => {
ops.push(Op::Val(Primitive::Str(tok.fragment)), tok.pos);
Self::translate_expr(expr, &mut ops, root);
ops.push(Op::Runtime(Hook::Convert), pos.clone());
ops.push(Op::Pop, pos);
}
}
}
fn translate_stmts(stmts: Vec<Statement>, mut ops: &mut PositionMap, root: &Path) {
for stmt in stmts {
match stmt {
Statement::Expression(expr) => {
let expr_pos = expr.pos().clone();
Self::translate_expr(expr, &mut ops, root);
ops.push(Op::Pop, expr_pos);
}
Statement::Assert(pos, expr) => {
Self::translate_expr(expr, &mut ops, root);
ops.push(Op::Runtime(Hook::Assert), pos);
}
Statement::Let(def) => {
let binding = def.name.fragment;
ops.push(Op::Sym(binding), def.name.pos);
Self::translate_expr(def.value, &mut ops, root);
ops.push(Op::Bind, def.pos);
}
Statement::Output(pos, tok, expr) => {
ops.push(Op::Val(Primitive::Str(tok.fragment)), tok.pos);
Self::translate_expr(expr, &mut ops, root);
ops.push(Op::Runtime(Hook::Out), pos);
}
Statement::Print(pos, tok, expr) => {
ops.push(Op::Val(Primitive::Str(tok.fragment)), tok.pos);
Self::translate_expr(expr, &mut ops, root);
ops.push(Op::Runtime(Hook::Convert), pos.clone());
ops.push(Op::Pop, pos);
}
}
Self::translate_stmt(stmt, &mut ops, root);
}
}
@ -166,7 +170,7 @@ impl AST {
let idx = ops.len() - 1;
Self::translate_expr(*def.right, &mut ops, root);
let jptr = (ops.len() - 1 - idx) as i32;
ops.replace(idx, Op::And(dbg!(jptr)));
ops.replace(idx, Op::And(jptr));
}
BinaryExprType::OR => {
Self::translate_expr(*def.left, &mut ops, root);
@ -174,7 +178,7 @@ impl AST {
let idx = ops.len() - 1;
Self::translate_expr(*def.right, &mut ops, root);
let jptr = (ops.len() - 1 - idx) as i32;
ops.replace(idx, Op::Or(dbg!(jptr)));
ops.replace(idx, Op::Or(jptr));
}
BinaryExprType::Mod => {
Self::translate_expr(*def.right, &mut ops, root);
@ -208,7 +212,7 @@ impl AST {
Self::translate_expr(*def.left, &mut ops, root);
// Symbols on the right side should be converted to strings to satisfy
// the Index operation contract.
match dbg!(*def.right) {
match *def.right {
Expression::Copy(copy_def) => {
// first handle the selector
match copy_def.selector {
@ -460,16 +464,16 @@ impl AST {
ops.replace(idx, Op::SelectJump(jptr as i32));
}
ops.push(Op::Pop, def.pos.clone());
let end = ops.len() - 1;
for i in jumps {
let idx = end - i;
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, def.pos);
}
let end = ops.len() - 1;
for i in jumps {
let idx = end - i;
ops.replace(i, Op::Jump(idx as i32));
}
}
Expression::Call(def) => {
// first push our arguments.

View File

@ -77,6 +77,10 @@ where
}
}
pub fn enable_validate_mode(&mut self) {
self.runtime.enable_validate_mode();
}
pub fn to_scoped(self, symbols: Stack) -> Self {
Self {
stack: Vec::new(),
@ -153,7 +157,7 @@ where
Op::FCall => self.op_fcall(pos)?,
Op::NewScope(jp) => self.op_new_scope(jp, self.ops.clone())?,
Op::Return => {
dbg!(&self.stack);
&self.stack;
return Ok(());
}
Op::Pop => {
@ -213,33 +217,33 @@ where
self.op_jump(jp)?;
}
} else {
return Err(dbg!(Error::new(
return Err(Error::new(
format!(
"Not a boolean condition {:?} in && expression at {}",
cond, pos
),
cond_pos.clone(),
)));
));
}
Ok(())
}
fn op_or(&mut self, jp: i32, pos: Position) -> Result<(), Error> {
let (cond, cond_pos) = self.pop()?;
let cc = dbg!(cond.clone());
let cc = cond.clone();
if let &P(Bool(cond)) = cond.as_ref() {
if dbg!(cond) {
if cond {
self.push(cc, cond_pos)?;
self.op_jump(jp)?;
}
} else {
return Err(dbg!(Error::new(
return Err(Error::new(
format!(
"Not a boolean condition {:?} in || expression at {}!",
cond, pos
),
cond_pos.clone(),
)));
));
}
Ok(())
}
@ -251,10 +255,10 @@ where
self.op_jump(jp)?;
}
} else {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("Expected boolean but got {:?}!", cond),
cond_pos.clone(),
)));
));
}
Ok(())
}
@ -266,19 +270,19 @@ where
self.op_jump(jp)?;
}
} else {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("Expected boolean but got {:?}!", cond),
pos.clone(),
)));
));
}
Ok(())
}
fn op_select_jump(&'a mut self, jp: i32) -> Result<(), Error> {
// pop field value off
let (field_name, _) = dbg!(self.pop())?;
let (field_name, _) = self.pop()?;
// pop search value off
let (search, srch_pos) = dbg!(self.pop())?;
let (search, srch_pos) = self.pop()?;
// compare them.
let matched = match (field_name.as_ref(), search.as_ref()) {
(&S(ref fname), &P(Str(ref sname))) | (&S(ref fname), &S(ref sname)) => fname == sname,
@ -286,14 +290,14 @@ where
};
if !matched {
// if they aren't equal then push search value back on and jump
self.push(dbg!(search), srch_pos)?;
self.op_jump(dbg!(jp))?;
self.push(search, srch_pos)?;
self.op_jump(jp)?;
}
Ok(())
}
fn op_module(&'a mut self, idx: usize, jptr: i32, pos: Position) -> Result<(), Error> {
let (mod_val, mod_val_pos) = dbg!(self.pop())?;
let (mod_val, mod_val_pos) = self.pop()?;
let (result_ptr, flds) = match mod_val.as_ref() {
&C(Tuple(ref flds)) => (None, flds.clone()),
&T(ptr) => {
@ -301,17 +305,17 @@ where
if let &C(Tuple(ref flds)) = tpl_val.as_ref() {
(Some(ptr), flds.clone())
} else {
return dbg!(Err(Error::new(
return Err(Error::new(
format!("Expected tuple but got {:?}", tpl_val),
tpl_val_pos,
)));
));
}
}
_ => {
return dbg!(Err(Error::new(
return Err(Error::new(
format!("Expected tuple but got {:?}", mod_val),
mod_val_pos,
)));
));
}
};
let mut ops = self.ops.clone();
@ -362,17 +366,14 @@ where
if let &S(ref sym) = e.as_ref() {
bindings.push(sym.clone());
} else {
return dbg!(Err(Error::new(
return Err(Error::new(
format!("Not an argument name {:?}", e),
args_pos,
)));
));
}
}
} else {
return dbg!(Err(Error::new(
format!("Fault!!! Bad Argument List"),
args_pos,
)));
return Err(Error::new(format!("Fault!!! Bad Argument List"), args_pos));
}
let mut ops = self.ops.clone();
ops.jump(idx)?;
@ -422,10 +423,10 @@ where
}
fn op_fcall(&mut self, pos: Position) -> Result<(), Error> {
let (f, _) = dbg!(self.pop())?;
let (f, _) = self.pop()?;
if let &F(ref f) = f.as_ref() {
let (val, _) = Self::fcall_impl(f, &mut self.stack, self.env.clone())?;
self.push(dbg!(val), pos.clone())?;
self.push(val, pos.clone())?;
}
Ok(())
}
@ -441,18 +442,19 @@ where
self.push(Rc::new(P(Bool(!val))), operand_pos)?;
return Ok(());
}
return Err(dbg!(Error::new(
return Err(Error::new(
format!(
"Expected Boolean but got {:?} in expression at {}",
operand, pos
),
operand_pos,
)));
));
}
fn op_equal(&mut self, pos: Position) -> Result<(), Error> {
let (left, _) = self.pop()?;
let (right, _) = self.pop()?;
// FIXME(jwall): We need to enforce our equality rules here.
self.push(Rc::new(P(Bool(left == right))), pos)?;
Ok(())
}
@ -468,13 +470,13 @@ where
self.push(Rc::new(P(Bool(f > ff))), pos.clone())?;
}
_ => {
return Err(dbg!(Error::new(
return Err(Error::new(
format!(
"Expected Numeric values of the same type but got {:?} and {:?}",
left, right
),
pos.clone(),
)));
));
}
}
Ok(())
@ -491,13 +493,13 @@ where
self.push(Rc::new(P(Bool(f < ff))), pos.clone())?;
}
_ => {
return Err(dbg!(Error::new(
return Err(Error::new(
format!(
"Expected Numeric values of the same type but got {:?} and {:?}",
left, right
),
pos.clone(),
)));
));
}
}
Ok(())
@ -514,13 +516,13 @@ where
self.push(Rc::new(P(Bool(f <= ff))), pos)?;
}
_ => {
return Err(dbg!(Error::new(
return Err(Error::new(
format!(
"Expected Numeric values of the same type but got {:?} and {:?}",
left, right
),
pos,
)));
));
}
}
Ok(())
@ -537,13 +539,13 @@ where
self.push(Rc::new(P(Bool(f >= ff))), pos)?;
}
_ => {
return Err(dbg!(Error::new(
return Err(Error::new(
format!(
"Expected Numeric values of the same type but got {:?} and {:?}",
left, right
),
pos,
)));
));
}
}
Ok(())
@ -597,7 +599,7 @@ where
fn op_push_self(&mut self) -> Result<(), Error> {
// We'll need a self stack.
let (val, pos) = self.pop()?;
self.self_stack.push((dbg!(val.clone()), pos.clone()));
self.self_stack.push((val.clone(), pos.clone()));
self.push(val.clone(), pos)?;
Ok(())
}
@ -625,12 +627,15 @@ where
fn op_field(&mut self) -> Result<(), Error> {
// Add a Composite field value to a tuple on the stack
// get value from stack
//dbg!(&self.stack);
let (val, _) = self.pop()?;
// get name from stack.
let (name_val, _) = self.pop()?;
let name = if let &S(ref s) | &P(Str(ref s)) = name_val.as_ref() {
s
} else {
//dbg!(name_val);
//dbg!(val);
unreachable!();
};
// get composite tuple from stack
@ -649,9 +654,9 @@ where
fn op_element(&mut self) -> Result<(), Error> {
// get element from stack.
let (val, _) = dbg!(self.pop()?);
let (val, _) = self.pop()?;
// get next value. It should be a Composite list.
let (list, pos) = dbg!(self.pop()?);
let (list, pos) = self.pop()?;
if let &C(List(ref elems)) = list.as_ref() {
// add value to list
let mut elems = elems.clone();
@ -670,8 +675,8 @@ where
fn op_index(&mut self, safe: bool, pos: Position) -> Result<(), Error> {
// left and then right
let (right, right_pos) = dbg!(self.pop()?);
let (left, _) = dbg!(self.pop()?);
let (right, right_pos) = self.pop()?;
let (left, _) = self.pop()?;
match right.as_ref() {
&P(Int(i)) => {
if let &C(List(ref elems)) = left.as_ref() {
@ -699,17 +704,17 @@ where
self.push(Rc::new(P(Empty)), pos)?;
return Ok(());
}
return Err(dbg!(Error::new(
return Err(Error::new(
format!("Invalid selector index: {:?} target: {:?}", right, left),
pos,
)));
));
}
fn op_copy(&mut self, pos: Position) -> Result<(), Error> {
// This value should always be a tuple
let (override_val, _) = dbg!(self.pop()?);
let (override_val, _) = self.pop()?;
// get targett value. It should be a Module or Tuple.
let (tgt, tgt_pos) = dbg!(self.pop()?);
let (tgt, tgt_pos) = self.pop()?;
let overrides = if let &C(Tuple(ref oflds)) = override_val.as_ref() {
oflds.clone()
} else {
@ -758,17 +763,16 @@ where
vm.ops.jump(ptr.clone())?;
vm.run()?;
let (result_val, result_pos) = vm.pop()?;
self.push(dbg!(result_val), result_pos)?;
self.push(result_val, result_pos)?;
} else {
dbg!(&vm.symbols);
self.push(Rc::new(dbg!(vm.symbols_to_tuple(false))), pos)?;
self.push(Rc::new(vm.symbols_to_tuple(false)), pos)?;
}
}
_ => {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("Expected a Tuple or a Module but got {:?}", tgt),
pos,
)));
));
}
}
Ok(())
@ -804,16 +808,16 @@ where
name_pos: &Position,
) -> Result<(), Error> {
if self.reserved_words.contains(name.as_str()) {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("{} is a reserved word.", name),
name_pos.clone(),
)));
));
}
if self.symbols.is_bound(&name) && strict {
return Err(dbg!(Error::new(
return Err(Error::new(
format!("Binding {} already exists", name),
pos.clone(),
)));
));
}
self.symbols.add(name, val, pos.clone());
Ok(())
@ -826,20 +830,14 @@ where
) -> Result<(Rc<Value>, Position), Error> {
if name == "self" {
if let Some((val, pos)) = self.self_stack.last() {
return Ok((dbg!(val.clone()), pos.clone()));
return Ok((val.clone(), pos.clone()));
}
return Err(dbg!(Error::new(
format!("No such binding {}", name),
pos.clone()
)));
return Err(Error::new(format!("No such binding {}", name), pos.clone()));
}
match self.symbols.get(name) {
Some((ref v, ref pos)) => Ok((v.clone(), pos.clone())),
None => {
return Err(dbg!(Error::new(
format!("No such binding {}", name),
pos.clone()
)));
return Err(Error::new(format!("No such binding {}", name), pos.clone()));
}
}
}
@ -859,13 +857,10 @@ where
(P(Int(i)), P(Int(ii))) => Int(i * ii),
(P(Float(f)), P(Float(ff))) => Float(f * ff),
_ => {
return Err(dbg!(Error::new(
format!(
"Expected numeric values of the same type but got {:?} and {:?}",
left, right
),
return Err(Error::new(
format!("Expected {} but got {:?}", left.type_name(), right),
pos.clone(),
)))
))
}
})
}
@ -875,13 +870,10 @@ where
(P(Int(i)), P(Int(ii))) => Int(i / ii),
(P(Float(f)), P(Float(ff))) => Float(f / ff),
_ => {
return Err(dbg!(Error::new(
format!(
"Expected numeric values of the same type but got {:?} and {:?}",
left, right
),
return Err(Error::new(
format!("Expected {} but got {:?}", left.type_name(), right),
pos.clone(),
)))
))
}
})
}
@ -891,13 +883,10 @@ where
(P(Int(i)), Value::P(Int(ii))) => Int(i - ii),
(P(Float(f)), Value::P(Float(ff))) => Float(f - ff),
_ => {
return Err(dbg!(Error::new(
format!(
"Expected numeric values of the same type but got {:?} and {:?}",
left, right
),
return Err(Error::new(
format!("Expected {} but got {:?}", left.type_name(), right),
pos.clone(),
)))
))
}
})
}
@ -907,13 +896,10 @@ where
(P(Int(i)), Value::P(Int(ii))) => Int(i % ii),
(P(Float(f)), Value::P(Float(ff))) => Float(f % ff),
_ => {
return Err(dbg!(Error::new(
format!(
"Expected numeric values of the same type but got {:?} and {:?}",
left, right
),
return Err(Error::new(
format!("Expected {} but got {:?}", left.type_name(), right),
pos.clone(),
)))
))
}
})
}
@ -939,10 +925,10 @@ where
C(List(new_list))
}
_ => {
return Err(dbg!(Error::new(
format!("You can not add {:?} and {:?}", left, right),
pos.clone()
)))
return Err(Error::new(
format!("Expected {} but got {:?}", left.type_name(), right),
pos.clone(),
))
}
})
}

View File

@ -169,9 +169,7 @@ impl Scope {
| Val::Empty
| Val::Float(_)
| Val::Int(_)
| Val::Module(_)
| Val::Str(_)
| Val::Func(_) => {
| Val::Str(_) => {
// noop
}
};

View File

@ -21,15 +21,13 @@ use std;
use std::cell::RefCell;
use std::rc::Rc;
fn test_expr_to_val<'a, C: assets::Cache>(
mut cases: Vec<(Expression, Val)>,
b: FileBuilder<'a, C>,
) {
fn test_expr_to_val<'a, O, E>(mut cases: Vec<(Expression, Val)>, mut b: FileBuilder<'a, O, E>)
where
O: std::io::Write,
E: std::io::Write,
{
for tpl in cases.drain(0..) {
assert_eq!(
b.eval_expr(&tpl.0, &b.scope.spawn_child()).unwrap(),
Rc::new(tpl.1)
);
assert_eq!(b.eval_expr(tpl.0).unwrap(), Rc::new(tpl.1));
}
}
@ -39,7 +37,9 @@ fn test_eval_div_expr_fail() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache, &registry);
let out: Vec<u8> = Vec::new();
let err: Vec<u8> = Vec::new();
let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -64,9 +64,9 @@ fn test_eval_div_expr_fail() {
#[should_panic(expected = "Expected Float")]
fn test_eval_mul_expr_fail() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache, &registry);
let out: Vec<u8> = Vec::new();
let err: Vec<u8> = Vec::new();
let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -91,9 +91,9 @@ fn test_eval_mul_expr_fail() {
#[should_panic(expected = "Expected Float")]
fn test_eval_subtract_expr_fail() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache, &registry);
let out: Vec<u8> = Vec::new();
let err: Vec<u8> = Vec::new();
let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -117,9 +117,9 @@ fn test_eval_subtract_expr_fail() {
#[should_panic(expected = "Expected Float")]
fn test_eval_add_expr_fail() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache, &registry);
let out: Vec<u8> = Vec::new();
let err: Vec<u8> = Vec::new();
let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err);
test_expr_to_val(
vec![(
Expression::Binary(BinaryOpDef {
@ -140,31 +140,14 @@ fn test_eval_add_expr_fail() {
);
}
#[test]
fn test_eval_simple_lookup_error() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache, &registry);
b.scope
.build_output
.entry(value_node!("var1".to_string(), Position::new(1, 0, 0)))
.or_insert(Rc::new(Val::Int(1)));
let expr = Expression::Simple(Value::Symbol(value_node!(
"var".to_string(),
Position::new(1, 1, 1)
)));
assert!(b.eval_expr(&expr, &b.scope.spawn_child()).is_err());
}
// Include nested for each.
#[test]
#[should_panic(expected = "Unable to find binding tpl1")]
#[should_panic(expected = "No such binding tpl1")]
fn test_expr_copy_no_such_tuple() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache, &registry);
let out: Vec<u8> = Vec::new();
let err: Vec<u8> = Vec::new();
let b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err);
test_expr_to_val(
vec![(
Expression::Copy(CopyDef {
@ -180,46 +163,3 @@ fn test_expr_copy_no_such_tuple() {
b,
);
}
#[test]
#[should_panic(expected = "Expected String but got Integer in Select expression")]
fn test_select_expr_not_a_string() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache, &registry);
b.scope
.build_output
.entry(value_node!("foo".to_string(), Position::new(1, 0, 0)))
.or_insert(Rc::new(Val::Int(4)));
test_expr_to_val(
vec![(
Expression::Select(SelectDef {
val: Box::new(Expression::Simple(Value::Symbol(value_node!(
"foo".to_string(),
Position::new(1, 1, 1)
)))),
default: Some(Box::new(Expression::Simple(Value::Int(value_node!(
1,
Position::new(1, 1, 1)
))))),
tuple: vec![
(
make_tok!("bar", Position::new(1, 1, 1)),
Expression::Simple(Value::Int(value_node!(2, Position::new(1, 1, 1)))),
),
(
make_tok!("quux", Position::new(1, 1, 1)),
Expression::Simple(Value::Str(value_node!(
"2".to_string(),
Position::new(1, 1, 1)
))),
),
],
pos: Position::new(1, 0, 0),
}),
Val::Int(2),
)],
b,
);
}

View File

@ -73,18 +73,10 @@ impl EnvConverter {
&Val::Tuple(ref flds) => {
self.convert_tuple(flds, w)?;
}
&Val::Func(ref _def) => {
// This is ignored
eprintln!("Skipping func...");
}
&Val::Env(ref _fs) => {
// This is ignored
eprintln!("Skipping env...");
}
&Val::Module(ref _def) => {
// This is ignored
eprintln!("Skipping module...");
}
}
Ok(())
}

View File

@ -194,21 +194,18 @@ impl Converter for ExecConverter {
#[cfg(test)]
mod exec_test {
use super::*;
use crate::build::assets::MemoryCache;
use crate::build::FileBuilder;
use crate::convert::traits::Converter;
use crate::convert::ConverterRegistry;
use std;
use std::cell::RefCell;
use std::io::Cursor;
#[test]
fn convert_just_command_test() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache, &registry);
let out: Vec<u8> = Vec::new();
let err: Vec<u8> = Vec::new();
let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err);
let conv = ExecConverter::new();
b.eval_string(
"let script = {
@ -229,9 +226,9 @@ mod exec_test {
#[test]
fn convert_command_with_env_test() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache, &registry);
let out: Vec<u8> = Vec::new();
let err: Vec<u8> = Vec::new();
let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err);
let conv = ExecConverter::new();
b.eval_string(
"let script = {
@ -259,9 +256,9 @@ mod exec_test {
#[test]
fn convert_command_with_arg_test() {
let i_paths = Vec::new();
let cache = Rc::new(RefCell::new(MemoryCache::new()));
let registry = ConverterRegistry::make_registry();
let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, cache, &registry);
let out: Vec<u8> = Vec::new();
let err: Vec<u8> = Vec::new();
let mut b = FileBuilder::new(std::env::current_dir().unwrap(), &i_paths, out, err);
let conv = ExecConverter::new();
b.eval_string(
"let script = {

View File

@ -55,7 +55,7 @@ impl FlagConverter {
// first of all we need to make sure that each &Val is only a primitive type.
for v in def.iter() {
let vref = v.as_ref();
if vref.is_list() || vref.is_tuple() || vref.is_func() || vref.is_module() {
if vref.is_list() || vref.is_tuple() {
eprintln!(
"Skipping non primitive val in list for flag {}{}",
pfx, name
@ -86,7 +86,7 @@ impl FlagConverter {
&Val::Str(ref s) => {
write!(w, "'{}' ", s)?;
}
&Val::List(_) | &Val::Tuple(_) | &Val::Func(_) | &Val::Env(_) | &Val::Module(_) => {
&Val::List(_) | &Val::Tuple(_) | &Val::Env(_) => {
// This is ignored
eprintln!("Skipping {}...", v.type_name());
}
@ -101,7 +101,7 @@ impl FlagConverter {
continue;
}
match val.as_ref() {
&Val::Tuple(_) | &Val::Module(_) | &Val::Func(_) | &Val::Env(_) => {
&Val::Tuple(_) | &Val::Env(_) => {
eprintln!("Skipping {} in flag output tuple.", val.type_name());
}
&Val::List(ref def) => {

View File

@ -72,14 +72,6 @@ impl JsonConverter {
serde_json::Value::Number(n)
}
&Val::Str(ref s) => serde_json::Value::String(s.clone()),
&Val::Func(_) => {
eprintln!("Skipping func encoding as null...");
serde_json::Value::Null
}
&Val::Module(_) => {
eprintln!("Skipping module encoding as null...");
serde_json::Value::Null
}
&Val::Env(ref fs) => self.convert_env(fs)?,
&Val::List(ref l) => self.convert_list(l)?,
&Val::Tuple(ref t) => self.convert_tuple(t)?,

View File

@ -68,14 +68,6 @@ impl TomlConverter {
&Val::Float(f) => toml::Value::Float(f),
&Val::Int(i) => toml::Value::Integer(i),
&Val::Str(ref s) => toml::Value::String(s.clone()),
&Val::Func(_) => {
let err = SimpleError::new("Functions are not allowed in Toml Conversions!");
return Err(Box::new(err));
}
&Val::Module(_) => {
let err = SimpleError::new("Modules are not allowed in Toml Conversions!");
return Err(Box::new(err));
}
&Val::Env(ref fs) => self.convert_env(fs)?,
&Val::List(ref l) => self.convert_list(l)?,
&Val::Tuple(ref t) => self.convert_tuple(t)?,

View File

@ -57,14 +57,6 @@ impl YamlConverter {
_ => panic!("Int is too large or not a Number {}", i),
},
&Val::Str(ref s) => serde_yaml::Value::String(s.clone()),
&Val::Func(_) => {
eprintln!("Skipping func encoding as null...");
serde_yaml::Value::Null
}
&Val::Module(_) => {
eprintln!("Skipping module encoding as null...");
serde_yaml::Value::Null
}
&Val::Env(ref fs) => self.convert_env(fs)?,
&Val::List(ref l) => self.convert_list(l)?,
&Val::Tuple(ref t) => self.convert_tuple(t)?,