mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
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:
parent
156b55271e
commit
e256abfee6
@ -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)), ®istry);
|
||||
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)), ®istry);
|
||||
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) => {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
1979
src/build/mod.rs
1979
src/build/mod.rs
File diff suppressed because it is too large
Load Diff
53
src/build/opcode/debug.rs
Normal file
53
src/build/opcode/debug.rs
Normal 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),
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 {}
|
@ -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)
|
||||
)))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
))),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(())
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -169,9 +169,7 @@ impl Scope {
|
||||
| Val::Empty
|
||||
| Val::Float(_)
|
||||
| Val::Int(_)
|
||||
| Val::Module(_)
|
||||
| Val::Str(_)
|
||||
| Val::Func(_) => {
|
||||
| Val::Str(_) => {
|
||||
// noop
|
||||
}
|
||||
};
|
||||
|
@ -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, ®istry);
|
||||
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, ®istry);
|
||||
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, ®istry);
|
||||
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, ®istry);
|
||||
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, ®istry);
|
||||
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, ®istry);
|
||||
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, ®istry);
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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, ®istry);
|
||||
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, ®istry);
|
||||
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, ®istry);
|
||||
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 = {
|
||||
|
@ -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) => {
|
||||
|
@ -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)?,
|
||||
|
@ -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)?,
|
||||
|
@ -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)?,
|
||||
|
Loading…
x
Reference in New Issue
Block a user