Implement Macros and Select.

Note: We change all our lifetimes in this.

It was getting too complicated for this first pass to avoid
copies. This makes lifetime management much easier to handle.

Each one of Val, Value, and Expression contain no references anymore.
This commit is contained in:
Jeremy Wall 2017-07-19 18:42:31 -05:00
parent 1ee7409367
commit c1c05cad7c
2 changed files with 416 additions and 199 deletions

View File

@ -16,9 +16,10 @@ use parse::{parse, Statement, Expression, Value, FieldList, SelectorList};
use std::error::Error;
use std::collections::{HashMap, VecDeque};
use std::collections::hash_map::Entry;
use std::rc::Rc;
use std::fmt;
use std::fmt::{Display,Formatter};
use std::ops::Deref;
use std::rc::Rc;
quick_error! {
#[derive(Debug,PartialEq)]
@ -35,6 +36,10 @@ quick_error! {
description("Eval Error")
display("No Such Variable {}", msg)
}
BadArgLen(msg: String) {
description("Eval Error")
display("Bad Argument Length {}", msg)
}
TODO(msg: String) {
description("TODO Error")
display("TODO Error {}", msg)
@ -45,31 +50,56 @@ quick_error! {
/// BuildResult is the result of a build.
type BuildResult = Result<(), Box<Error>>;
/// MacroDef is a pure function that always returns a Tuple.
///
/// MacroDef's are not closures. They can not reference
/// any values except what is defined in their arguments.
#[derive(PartialEq,Debug,Clone)]
pub struct MacroDef<'a> {
argdefs: Vec<&'a str>,
fields: FieldList<'a>,
pub struct MacroDef {
argdefs: Vec<String>,
fields: FieldList,
}
impl<'a> MacroDef<'a> {
fn eval(&'a self, args: Vec<Expression<'a>>) -> Result<Vec<(&'a str, Rc<Val<'a>>)>, Box<Error>> {
Err(Box::new(
BuildError::TODO(
"Macro Calls are not implemented yet".to_string())))
impl MacroDef {
fn eval(&self, mut args: Vec<Rc<Val>>) -> Result<Vec<(String, Rc<Val>)>, Box<Error>> {
// Error conditions. If the args don't match the length and types of the argdefs then this is
// macro call error.
if args.len() > self.argdefs.len() {
return Err(Box::new(
BuildError::BadArgLen(
"Macro called with too many args".to_string())));
}
// If the args don't match the types required by the expressions then that is a TypeFail.
// If the expressions reference Symbols not defined in the MacroDef that is also an error.
// TODO(jwall): We should probably enforce that the Expression Symbols must be in argdefs rules
// at Macro definition time not evaluation time.
let mut scope = HashMap::new();
for (i, arg) in args.drain(0..).enumerate() {
scope.entry(self.argdefs[i].clone()).or_insert(arg.clone());
}
let b = Builder::new_with_scope(scope);
let mut result: Vec<(String, Rc<Val>)> = Vec::new();
for &(ref key, ref expr) in self.fields.iter() {
// We clone the expressions here because this macro may be consumed
// multiple times in the future.
let val = try!(b.eval_expr(expr.clone()));
result.push((key.clone(), val.clone()));
}
Ok(result)
}
}
/// Val is the type of a value for a field in a Tuple.
#[derive(PartialEq,Debug,Clone)]
pub enum Val<'a> {
pub enum Val {
Int(i64),
Float(f64),
String(String),
Tuple(Vec<(&'a str, Rc<Val<'a>>)>),
Macro(MacroDef<'a>),
Tuple(Vec<(String, Rc<Val>)>),
Macro(MacroDef),
}
impl<'a> Val<'a> {
impl Val {
pub fn type_name(&self) -> String {
match self {
@ -91,7 +121,7 @@ impl<'a> Val<'a> {
}
}
pub fn get_fields(&self) -> Option<&Vec<(&'a str, Rc<Val<'a>>)>> {
pub fn get_fields(&self) -> Option<&Vec<(String, Rc<Val>)>> {
if let &Val::Tuple(ref fs) = self {
Some(fs)
} else {
@ -128,7 +158,7 @@ impl<'a> Val<'a> {
}
}
impl<'a> Display for Val<'a> {
impl Display for Val {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
// TODO(jwall): These should render better than this.
write!(f, "{}", self.type_name())
@ -137,19 +167,19 @@ impl<'a> Display for Val<'a> {
/// ValueMap defines a set of values in a parsed file.
#[derive(PartialEq,Debug)]
pub struct ValueMap<'a>(HashMap<&'a str, Rc<Val<'a>>>);
pub struct ValueMap(HashMap<String, Rc<Val>>);
/// Builder parses one or more statements into a out Tuple.
pub struct Builder<'a> {
pub struct Builder {
/// env is the immutable set of key value pairs provided at build time.
env: HashMap<&'a str, &'a str>,
env: HashMap<String, String>,
/// assets are other parsed files from import statements. They
/// are keyed by the normalized import path. This acts as a cache
/// so multiple imports of the same file don't have to be parsed
/// multiple times.
assets: HashMap<&'a str, ValueMap<'a>>,
assets: HashMap<String, ValueMap>,
/// out is our built output.
out: HashMap<&'a str, Rc<Val<'a>>>,
out: HashMap<String, Rc<Val>>,
}
macro_rules! eval_binary_expr {
@ -167,16 +197,16 @@ macro_rules! eval_binary_expr {
}
}
impl<'a> Builder<'a> {
impl Builder {
/// new_builder constructs Builder with initialized fields ready to parse.
fn from(&self, v: Value<'a>) -> Result<Rc<Val>, Box<Error>> {
fn from(&self, v: Value) -> Result<Rc<Val>, Box<Error>> {
match v {
Value::Int(i) => Ok(Rc::new(Val::Int(i))),
Value::Float(f) => Ok(Rc::new(Val::Float(f))),
Value::String(s) => Ok(Rc::new(Val::String(s.to_string()))),
Value::Symbol(s) => {
self.lookup_sym(s).ok_or(Box::new(
BuildError::NoSuchSymbol(s.to_string())))
self.lookup_sym(&s).ok_or(Box::new(
BuildError::NoSuchSymbol(format!("Unable to find {}", s))))
},
Value::Tuple(fields) => {
// TODO(jwall): We need to resolve the expressions here.
@ -200,6 +230,14 @@ impl<'a> Builder<'a> {
}
}
pub fn new_with_scope(scope: HashMap<String, Rc<Val>>) -> Self {
Builder {
env: HashMap::new(),
assets: HashMap::new(),
out: scope,
}
}
pub fn build_dir(&mut self, name: &str) -> BuildResult {
Ok(())
}
@ -216,7 +254,7 @@ impl<'a> Builder<'a> {
Ok(())
}
fn lookup_sym(&'a self, sym: &str) -> Option<Rc<Val>> {
fn lookup_sym(&self, sym: &str) -> Option<Rc<Val>> {
if self.out.contains_key(sym) {
Some(self.out[sym].clone())
} else {
@ -224,7 +262,7 @@ impl<'a> Builder<'a> {
}
}
fn find_in_fieldlist(target: &str, fs: &Vec<(&str, Rc<Val<'a>>)>) -> Option<Rc<Val<'a>>> {
fn find_in_fieldlist(target: &str, fs: &Vec<(String, Rc<Val>)>) -> Option<Rc<Val>> {
for (key, val) in fs.iter().cloned() {
if target == key {
return Some(val.clone())
@ -233,11 +271,11 @@ impl<'a> Builder<'a> {
return None
}
fn lookup_selector(&'a self, sl: SelectorList) -> Result<Rc<Val>, Box<Error>> {
fn lookup_selector(&self, sl: SelectorList) -> Result<Rc<Val>, Box<Error>> {
let len = sl.len();
if len > 0 {
println!("Looking up symbol {}", sl[0]);
if let Some(v) = self.lookup_sym(sl[0]) {
if let Some(v) = self.lookup_sym(&sl[0]) {
let mut it = sl.iter().skip(1).peekable();
if it.peek().is_none() {
return Ok(v.clone());
@ -290,7 +328,9 @@ impl<'a> Builder<'a> {
// eval_expr evals a single Expression in the context of a running Builder.
// It does not mutate the builders collected state at all.
pub fn eval_expr(&'a self, expr: Expression<'a>) -> Result<Rc<Val>, Box<Error>> {
pub fn eval_expr(&self, expr: Expression) -> Result<Rc<Val>, Box<Error>> {
// TODO(jwall): We probably don't want to consume these expressions.
// Take a reference instead?
match expr {
Expression::Simple(val) => {
self.from(val)
@ -387,10 +427,10 @@ impl<'a> Builder<'a> {
Expression::Copy(sel, mut fields) => {
let v = try!(self.lookup_selector(sel));
if let Val::Tuple(ref src_fields) = *v {
let mut m = HashMap::<&str, Rc<Val>>::new();
let mut m = HashMap::<String, Rc<Val>>::new();
// loop through fields and build up a hasmap
for &(ref key, ref val) in src_fields.iter() {
if let Entry::Vacant(v) = m.entry(*key) {
if let Entry::Vacant(v) = m.entry(key.to_string()) {
v.insert(val.clone());
} else {
// TODO(jwall): Is this an error?
@ -401,7 +441,7 @@ impl<'a> Builder<'a> {
}
for (key, val) in fields.drain(0..) {
let expr_result = try!(self.eval_expr(val));
match m.entry(key) {
match m.entry(key.clone()) {
Entry::Vacant(mut v) => {
v.insert(expr_result);
},
@ -421,10 +461,12 @@ impl<'a> Builder<'a> {
},
};
}
let mut new_fields: Vec<(&str, Rc<Val>)> = m.drain().collect();
let mut new_fields: Vec<(String, Rc<Val>)> = m.drain()
.map(|(s, v)| (s.to_string(), v))
.collect();
// We want a stable order for the fields to make comparing tuples
// easier in later code. So we sort by the field name before constructing a new tuple.
new_fields.sort_by(|a, b| a.0.cmp(b.0));
new_fields.sort_by(|a, b| a.0.cmp(&b.0));
return Ok(Rc::new(Val::Tuple(new_fields)));
}
Err(Box::new(
@ -434,20 +476,51 @@ impl<'a> Builder<'a> {
Expression::Grouped(expr) => {
return self.eval_expr(*expr);
},
Expression::Call{macroref: sel, arglist: args} => {
Expression::Call{macroref: sel, arglist: mut args} => {
let v = try!(self.lookup_selector(sel));
if let &Val::Macro(ref m) = v.deref() {
// Congratulations this is actually a macro.
let mut argvals: Vec<Rc<Val>> = Vec::new();
for arg in args.drain(0..) {
argvals.push(try!(self.eval_expr(arg)));
}
let fields = try!(m.eval(argvals));
return Ok(Rc::new(Val::Tuple(fields)));
}
Err(Box::new(
BuildError::TODO(
"TODO(jwall): Unimplemented Expression".to_string())))
BuildError::TypeFail(
// We should pretty print the selectors here.
format!("{} is not a Macro", v))))
},
Expression::Macro{arglist: args, tuple: fields} => {
Err(Box::new(
BuildError::TODO(
"TODO(jwall): Unimplemented Expression".to_string())))
// TODO(jwall): Walk the AST and verify that the symbols all
// exist as names in the arglist.
let md = MacroDef{
argdefs: args,
fields: fields,
};
Ok(Rc::new(Val::Macro(md)))
},
Expression::Select{val: target, default: def_expr, tuple: fields} => {
Err(Box::new(
BuildError::TODO(
"TODO(jwall): Unimplemented Expression".to_string())))
Expression::Select{val: target, default: def_expr, tuple: mut fields} => {
// First resolve the target expression.
let v = try!(self.eval_expr(*target));
// Second ensure that the expression resolves to a string.
if let &Val::String(ref name) = v.deref() {
// Third find the field with that name in the tuple.
for (fname, val_expr) in fields.drain(0..) {
if &fname == name {
// Fourth return the result of evaluating that field.
return self.eval_expr(val_expr);
}
}
// Otherwise return the default
return self.eval_expr(*def_expr);
} else {
return Err(Box::new(
BuildError::TypeFail(
format!("Expected String but got {} in Select expression",
v.type_name()))));
}
},
}
}
@ -470,7 +543,7 @@ impl<'a> Builder<'a> {
#[cfg(test)]
mod test {
use super::{Builder,Val};
use super::{Builder,Val,MacroDef};
use parse::{Expression, Value};
use std::rc::Rc;
@ -517,7 +590,8 @@ mod test {
fn test_eval_mul_expr_fail() {
let mut b = Builder::new();
test_expr_to_val(vec![
(Expression::Mul(Box::new(Value::Float(2.0)), Box::new(Expression::Simple(Value::Int(2)))),
(Expression::Mul(Box::new(Value::Float(2.0)),
Box::new(Expression::Simple(Value::Int(2)))),
Val::Float(1.0)),
], b);
}
@ -526,9 +600,11 @@ mod test {
fn test_eval_subtract_expr() {
let mut b = Builder::new();
test_expr_to_val(vec![
(Expression::Sub(Box::new(Value::Int(2)), Box::new(Expression::Simple(Value::Int(1)))),
(Expression::Sub(Box::new(Value::Int(2)),
Box::new(Expression::Simple(Value::Int(1)))),
Val::Int(1)),
(Expression::Sub(Box::new(Value::Float(2.0)), Box::new(Expression::Simple(Value::Float(1.0)))),
(Expression::Sub(Box::new(Value::Float(2.0)),
Box::new(Expression::Simple(Value::Float(1.0)))),
Val::Float(1.0)),
], b);
}
@ -538,7 +614,8 @@ mod test {
fn test_eval_subtract_expr_fail() {
let mut b = Builder::new();
test_expr_to_val(vec![
(Expression::Sub(Box::new(Value::Float(2.0)), Box::new(Expression::Simple(Value::Int(2)))),
(Expression::Sub(Box::new(Value::Float(2.0)),
Box::new(Expression::Simple(Value::Int(2)))),
Val::Float(1.0)),
], b);
}
@ -547,11 +624,14 @@ mod test {
fn test_eval_add_expr() {
let mut b = Builder::new();
test_expr_to_val(vec![
(Expression::Add(Box::new(Value::Int(1)), Box::new(Expression::Simple(Value::Int(1)))),
(Expression::Add(Box::new(Value::Int(1)),
Box::new(Expression::Simple(Value::Int(1)))),
Val::Int(2)),
(Expression::Add(Box::new(Value::Float(1.0)), Box::new(Expression::Simple(Value::Float(1.0)))),
(Expression::Add(Box::new(Value::Float(1.0)),
Box::new(Expression::Simple(Value::Float(1.0)))),
Val::Float(2.0)),
(Expression::Add(Box::new(Value::String("foo")), Box::new(Expression::Simple(Value::String("bar")))),
(Expression::Add(Box::new(Value::String("foo".to_string())),
Box::new(Expression::Simple(Value::String("bar".to_string())))),
Val::String("foobar".to_string())),
], b);
}
@ -561,7 +641,8 @@ mod test {
fn test_eval_add_expr_fail() {
let mut b = Builder::new();
test_expr_to_val(vec![
(Expression::Add(Box::new(Value::Float(2.0)), Box::new(Expression::Simple(Value::Int(2)))),
(Expression::Add(Box::new(Value::Float(2.0)),
Box::new(Expression::Simple(Value::Int(2)))),
Val::Float(1.0)),
], b);
}
@ -571,59 +652,67 @@ mod test {
test_expr_to_val(vec![
(Expression::Simple(Value::Int(1)), Val::Int(1)),
(Expression::Simple(Value::Float(2.0)), Val::Float(2.0)),
(Expression::Simple(Value::String("foo")), Val::String("foo".to_string())),
(Expression::Simple(Value::String("foo".to_string())), Val::String("foo".to_string())),
], Builder::new());
}
#[test]
fn test_eval_simple_lookup_expr() {
let mut b = Builder::new();
b.out.entry("var1").or_insert(Rc::new(Val::Int(1)));
b.out.entry("var1".to_string()).or_insert(Rc::new(Val::Int(1)));
test_expr_to_val(vec![
(Expression::Simple(Value::Symbol("var1")), Val::Int(1)),
(Expression::Simple(Value::Symbol("var1".to_string())), Val::Int(1)),
], b);
}
#[test]
fn test_eval_simple_lookup_error() {
let mut b = Builder::new();
b.out.entry("var1").or_insert(Rc::new(Val::Int(1)));
assert!(b.eval_expr(Expression::Simple(Value::Symbol("var"))).is_err());
b.out.entry("var1".to_string()).or_insert(Rc::new(Val::Int(1)));
assert!(b.eval_expr(Expression::Simple(Value::Symbol("var".to_string()))).is_err());
}
#[test]
fn test_eval_selector_expr() {
// TODO(jwall): Tests for this expression.
let mut b = Builder::new();
b.out.entry("var1").or_insert(Rc::new(Val::Tuple(vec![
("lvl1", Rc::new(Val::Tuple(
b.out.entry("var1".to_string()).or_insert(Rc::new(Val::Tuple(vec![
("lvl1".to_string(), Rc::new(Val::Tuple(
vec![
("lvl2", Rc::new(Val::Int(3))),
("lvl2".to_string(), Rc::new(Val::Int(3))),
]
))),
])));
b.out.entry("var2").or_insert(Rc::new(Val::Int(2)));
b.out.entry("var3").or_insert(Rc::new(Val::Tuple(vec![
("lvl1", Rc::new(Val::Int(4)))
b.out.entry("var2".to_string()).or_insert(Rc::new(Val::Int(2)));
b.out.entry("var3".to_string()).or_insert(Rc::new(Val::Tuple(vec![
("lvl1".to_string(), Rc::new(Val::Int(4)))
])));
test_expr_to_val(vec![
(Expression::Simple(Value::Selector(vec!["var1"])), Val::Tuple(
(Expression::Simple(Value::Selector(vec!["var1".to_string()])), Val::Tuple(
vec![
("lvl1", Rc::new(Val::Tuple(
("lvl1".to_string(), Rc::new(Val::Tuple(
vec![
("lvl2", Rc::new(Val::Int(3))),
("lvl2".to_string(), Rc::new(Val::Int(3))),
]
))),
]
)),
(Expression::Simple(Value::Selector(vec!["var1","lvl1"])), Val::Tuple(
(Expression::Simple(Value::Selector(vec!["var1".to_string(),
"lvl1".to_string()])),
Val::Tuple(
vec![
("lvl2", Rc::new(Val::Int(3))),
("lvl2".to_string(), Rc::new(Val::Int(3))),
]
)),
(Expression::Simple(Value::Selector(vec!["var1","lvl1", "lvl2"])), Val::Int(3)),
(Expression::Simple(Value::Selector(vec!["var2"])), Val::Int(2)),
(Expression::Simple(Value::Selector(vec!["var3", "lvl1"])), Val::Int(4)),
(Expression::Simple(Value::Selector(vec!["var1".to_string(),
"lvl1".to_string(),
"lvl2".to_string()])),
Val::Int(3)),
(Expression::Simple(Value::Selector(vec!["var2".to_string()])),
Val::Int(2)),
(Expression::Simple(Value::Selector(vec!["var3".to_string(),
"lvl1".to_string()])),
Val::Int(4)),
], b);
}
@ -632,7 +721,7 @@ mod test {
fn test_expr_copy_no_such_tuple() {
let mut b = Builder::new();
test_expr_to_val(vec![
(Expression::Copy(vec!["tpl1"], Vec::new()),
(Expression::Copy(vec!["tpl1".to_string()], Vec::new()),
Val::Tuple(Vec::new())),
], b);
}
@ -641,9 +730,9 @@ mod test {
#[should_panic(expected = "Expected Tuple got Integer")]
fn test_expr_copy_not_a_tuple() {
let mut b = Builder::new();
b.out.entry("tpl1").or_insert(Rc::new(Val::Int(1)));
b.out.entry("tpl1".to_string()).or_insert(Rc::new(Val::Int(1)));
test_expr_to_val(vec![
(Expression::Copy(vec!["tpl1"], Vec::new()),
(Expression::Copy(vec!["tpl1".to_string()], Vec::new()),
Val::Tuple(Vec::new())),
], b);
}
@ -652,15 +741,16 @@ mod test {
#[should_panic(expected = "Expected type Integer for field fld1 but got String")]
fn test_expr_copy_field_type_error() {
let mut b = Builder::new();
b.out.entry("tpl1").or_insert(Rc::new(Val::Tuple(vec![
("fld1", Rc::new(Val::Int(1))),
b.out.entry("tpl1".to_string()).or_insert(Rc::new(Val::Tuple(vec![
("fld1".to_string(), Rc::new(Val::Int(1))),
])));
test_expr_to_val(vec![
(Expression::Copy(vec!["tpl1"],
vec![("fld1", Expression::Simple(Value::String("2")))]),
(Expression::Copy(vec!["tpl1".to_string()],
vec![("fld1".to_string(),
Expression::Simple(Value::String("2".to_string())))]),
Val::Tuple(
vec![
("fld1", Rc::new(Val::String("2".to_string()))),
("fld1".to_string(), Rc::new(Val::String("2".to_string()))),
],
)),
], b);
@ -672,41 +762,132 @@ mod test {
fn test_expr_copy() {
// TODO(jwall): Tests for this expression.
let mut b = Builder::new();
b.out.entry("tpl1").or_insert(Rc::new(Val::Tuple(vec![
("fld1", Rc::new(Val::Int(1))),
b.out.entry("tpl1".to_string()).or_insert(Rc::new(Val::Tuple(vec![
("fld1".to_string(), Rc::new(Val::Int(1))),
])));
test_expr_to_val(vec![
(Expression::Copy(vec!["tpl1"],
vec![("fld2", Expression::Simple(Value::String("2")))]),
(Expression::Copy(vec!["tpl1".to_string()],
vec![("fld2".to_string(),
Expression::Simple(Value::String("2".to_string())))]),
// Add a new field to the copy
Val::Tuple(
// NOTE(jwall): The order of these is important in order to ensure
// that the compare assertion is correct. The ordering has no
// semantics though so at some point we should probably be less restrictive.
vec![
("fld1", Rc::new(Val::Int(1))),
("fld2", Rc::new(Val::String("2".to_string()))),
("fld1".to_string(), Rc::new(Val::Int(1))),
("fld2".to_string(), Rc::new(Val::String("2".to_string()))),
],
)),
// Overwrite a field in the copy
(Expression::Copy(vec!["tpl1"],
(Expression::Copy(vec!["tpl1".to_string()],
vec![
("fld1", Expression::Simple(Value::Int(3))),
("fld2", Expression::Simple(Value::String("2"))),
("fld1".to_string(),
Expression::Simple(Value::Int(3))),
("fld2".to_string(),
Expression::Simple(Value::String("2".to_string()))),
]),
Val::Tuple(
vec![
("fld1", Rc::new(Val::Int(3))),
("fld2", Rc::new(Val::String("2".to_string()))),
("fld1".to_string(), Rc::new(Val::Int(3))),
("fld2".to_string(), Rc::new(Val::String("2".to_string()))),
],
)),
// The source tuple is still unmodified.
(Expression::Simple(Value::Selector(vec!["tpl1"])),
(Expression::Simple(Value::Selector(vec!["tpl1".to_string()])),
Val::Tuple(
vec![
("fld1", Rc::new(Val::Int(1))),
("fld1".to_string(), Rc::new(Val::Int(1))),
],
)),
], b);
}
#[test]
fn test_macro_call() {
let mut b = Builder::new();
b.out.entry("tstmac".to_string()).or_insert(Rc::new(Val::Macro(MacroDef{
argdefs: vec!["arg1".to_string()],
fields: vec![
("foo".to_string(), Expression::Simple(Value::Symbol("arg1".to_string()))),
],
})));
test_expr_to_val(vec![
(Expression::Call{
macroref: vec!["tstmac".to_string()],
arglist: vec![Expression::Simple(Value::String("bar".to_string()))],
},
Val::Tuple(vec![
("foo".to_string(), Rc::new(Val::String("bar".to_string()))),
])),
], b);
}
#[test]
#[should_panic(expected = "Unable to find arg1")]
fn test_macro_hermetic() {
let mut b = Builder::new();
b.out.entry("arg1".to_string()).or_insert(Rc::new(Val::String("bar".to_string())));
b.out.entry("tstmac".to_string()).or_insert(Rc::new(Val::Macro(MacroDef{
argdefs: vec!["arg2".to_string()],
fields: vec![
("foo".to_string(), Expression::Simple(Value::Symbol("arg1".to_string()))),
],
})));
test_expr_to_val(vec![
(Expression::Call{
macroref: vec!["tstmac".to_string()],
arglist: vec![Expression::Simple(Value::String("bar".to_string()))],
},
Val::Tuple(vec![
("foo".to_string(), Rc::new(Val::String("bar".to_string()))),
])),
], b);
}
#[test]
fn test_select_expr() {
let mut b = Builder::new();
b.out.entry("foo".to_string()).or_insert(Rc::new(Val::String("bar".to_string())));
b.out.entry("baz".to_string()).or_insert(Rc::new(Val::String("boo".to_string())));
test_expr_to_val(vec![
(Expression::Select{
val: Box::new(Expression::Simple(Value::Symbol("foo".to_string()))),
default: Box::new(Expression::Simple(Value::Int(1))),
tuple: vec![
("bar".to_string(), Expression::Simple(Value::Int(2))),
("quux".to_string(), Expression::Simple(Value::String("2".to_string()))),
],
},
Val::Int(2)),
(Expression::Select{
val: Box::new(Expression::Simple(Value::Symbol("baz".to_string()))),
default: Box::new(Expression::Simple(Value::Int(1))),
tuple: vec![
("bar".to_string(), Expression::Simple(Value::Int(2))),
("quux".to_string(), Expression::Simple(Value::String("2".to_string()))),
],
},
// If the field doesn't exist then we get the default.
Val::Int(1)),
], b);
}
#[test]
#[should_panic(expected ="Expected String but got Integer in Select expression")]
fn test_select_expr_not_a_string() {
let mut b = Builder::new();
b.out.entry("foo".to_string()).or_insert(Rc::new(Val::Int(4)));
test_expr_to_val(vec![
(Expression::Select{
val: Box::new(Expression::Simple(Value::Symbol("foo".to_string()))),
default: Box::new(Expression::Simple(Value::Int(1))),
tuple: vec![
("bar".to_string(), Expression::Simple(Value::Int(2))),
("quux".to_string(), Expression::Simple(Value::String("2".to_string()))),
],
},
Val::Int(2)),
], b);
}
}

View File

@ -29,23 +29,23 @@ use nom::{alpha, is_alphanumeric, digit};
type ParseResult<O> = Result<O, Box<Error>>;
pub type FieldList<'a> = Vec<(&'a str, Expression<'a>)>; // str is expected to be a symbol
pub type SelectorList<'a> = Vec<&'a str>; // str is expected to always be a symbol.
pub type FieldList = Vec<(String, Expression)>; // str is expected to be a symbol
pub type SelectorList = Vec<String>; // str is expected to always be a symbol.
/// Value represents a Value in the UCG parsed AST.
#[derive(Debug,PartialEq,Clone)]
pub enum Value<'a> {
pub enum Value {
// Constant Values
Int(i64),
Float(f64),
String(&'a str),
Symbol(&'a str),
String(String),
Symbol(String),
// Complex Values
Tuple(FieldList<'a>),
Selector(SelectorList<'a>),
Tuple(FieldList),
Selector(SelectorList),
}
impl<'a> Value<'a> {
impl Value {
pub fn type_name(&self) -> String {
match self {
&Value::Int(_) => "Integer".to_string(),
@ -56,55 +56,78 @@ impl<'a> Value<'a> {
&Value::Selector(_) => "Selector".to_string(),
}
}
fn fields_to_string(v: &FieldList) -> String {
let mut buf = String::new();
buf.push_str("{\n");
for ref t in v.iter() {
buf.push_str("\t");
buf.push_str(&t.0);
buf.push_str("\n");
}
buf.push_str("}");
return buf;
}
pub fn to_string(&self) -> String {
match self {
&Value::Int(ref i) => format!("{}", i),
&Value::Float(ref f) => format!("{}", f),
&Value::String(ref s) => format!("{}", s),
&Value::Symbol(ref s) => format!("{}", s),
&Value::Tuple(ref fs) => format!("{}", Self::fields_to_string(fs)),
&Value::Selector(ref v) => v.join("."),
}
}
}
/// Expression encodes an expression. Expressions compute a value from operands.
#[derive(Debug,PartialEq,Clone)]
pub enum Expression<'a> {
pub enum Expression {
// Base Expression
Simple(Value<'a>),
Simple(Value),
// Binary Expressions
Add(Box<Value<'a>>, Box<Expression<'a>>),
Sub(Box<Value<'a>>, Box<Expression<'a>>),
Mul(Box<Value<'a>>, Box<Expression<'a>>),
Div(Box<Value<'a>>, Box<Expression<'a>>),
Add(Box<Value>, Box<Expression>),
Sub(Box<Value>, Box<Expression>),
Mul(Box<Value>, Box<Expression>),
Div(Box<Value>, Box<Expression>),
// Complex Expressions
Copy(SelectorList<'a>, FieldList<'a>),
Grouped(Box<Expression<'a>>),
Copy(SelectorList, FieldList),
Grouped(Box<Expression>),
Call {
macroref: SelectorList<'a>,
arglist: Vec<Expression<'a>>,
macroref: SelectorList,
arglist: Vec<Expression>,
},
Macro {
arglist: Vec<Value<'a>>,
tuple: FieldList<'a>,
arglist: Vec<String>,
tuple: FieldList,
},
Select {
val: Box<Expression<'a>>,
default: Box<Expression<'a>>,
tuple: FieldList<'a>,
val: Box<Expression>,
default: Box<Expression>,
tuple: FieldList,
},
}
/// Statement encodes a parsed Statement in the UCG AST.
#[derive(Debug,PartialEq)]
pub enum Statement<'a> {
pub enum Statement {
// simple expression
Expression(Expression<'a>),
Expression(Expression),
// Named bindings
Let {
name: &'a str,
value: Expression<'a>,
name: String,
value: Expression,
},
// Include a file.
Import {
path: &'a str,
name: &'a str,
path: String,
name: String,
},
}
@ -125,12 +148,13 @@ named!(semicolon, tag!(";"));
named!(fatcomma, tag!("=>"));
// a field is the building block of symbols and tuple field names.
named!(field<&str>,
named!(field<String>,
map_res!(preceded!(peek!(alpha), take_while!(is_alphanumeric)),
from_utf8)
|s| from_utf8(s).map(|s| s.to_string())
)
);
fn symbol_to_value<'a>(s: &'a str) -> ParseResult<Value<'a>> {
fn symbol_to_value(s: String) -> ParseResult<Value> {
Ok(Value::Symbol(s))
}
@ -138,13 +162,13 @@ fn symbol_to_value<'a>(s: &'a str) -> ParseResult<Value<'a>> {
named!(symbol<Value>, map_res!(field, symbol_to_value));
// quoted is a quoted string.
named!(quoted<&str>,
named!(quoted<String>,
map_res!(delimited!(doublequote, take_until!("\""), doublequote),
from_utf8
|s| from_utf8(s).map(|s| s.to_string())
)
);
fn str_to_value<'a>(s: &'a str) -> ParseResult<Value<'a>> {
fn str_to_value(s: String) -> ParseResult<Value> {
Ok(Value::String(s))
}
@ -154,8 +178,8 @@ named!(quoted_value<Value>,
);
// Helper function to make the return types work for down below.
fn triple_to_number<'a>(v: (Option<&'a [u8]>, Option<&'a [u8]>, Option<&'a [u8]>))
-> ParseResult<Value<'a>> {
fn triple_to_number(v: (Option<&[u8]>, Option<&[u8]>, Option<&[u8]>))
-> ParseResult<Value> {
let pref = match v.0 {
None => "",
Some(bs) => try!(from_utf8(bs)),
@ -223,7 +247,7 @@ named!(value<Value>, alt!(number | quoted_value | symbol | tuple));
named!(
#[doc="Capture a field and value pair composed of `<symbol> = <value>,`"],
field_value<(&str, Expression) >,
field_value<(String, Expression) >,
do_parse!(
field: field >>
ws!(equal) >>
@ -233,7 +257,7 @@ named!(
);
// Helper function to make the return types work for down below.
fn vec_to_tuple<'a>(v: FieldList<'a>) -> ParseResult<Value<'a>> {
fn vec_to_tuple(v: FieldList) -> ParseResult<Value> {
Ok(Value::Tuple(v))
}
@ -269,7 +293,7 @@ named!(simple_expression<Expression>,
)
);
fn tuple_to_add_expression<'a>(tpl: (Value<'a>, Expression<'a>)) -> ParseResult<Expression<'a>> {
fn tuple_to_add_expression(tpl: (Value, Expression)) -> ParseResult<Expression> {
Ok(Expression::Add(Box::new(tpl.0), Box::new(tpl.1)))
}
@ -285,7 +309,7 @@ named!(add_expression<Expression>,
)
);
fn tuple_to_sub_expression<'a>(tpl: (Value<'a>, Expression<'a>)) -> ParseResult<Expression<'a>> {
fn tuple_to_sub_expression(tpl: (Value, Expression)) -> ParseResult<Expression> {
Ok(Expression::Sub(Box::new(tpl.0), Box::new(tpl.1)))
}
@ -301,7 +325,7 @@ named!(sub_expression<Expression>,
)
);
fn tuple_to_mul_expression<'a>(tpl: (Value<'a>, Expression<'a>)) -> ParseResult<Expression<'a>> {
fn tuple_to_mul_expression(tpl: (Value, Expression)) -> ParseResult<Expression> {
Ok(Expression::Mul(Box::new(tpl.0), Box::new(tpl.1)))
}
@ -317,7 +341,7 @@ named!(mul_expression<Expression>,
)
);
fn tuple_to_div_expression<'a>(tpl: (Value<'a>, Expression<'a>)) -> ParseResult<Expression<'a>> {
fn tuple_to_div_expression(tpl: (Value, Expression)) -> ParseResult<Expression> {
Ok(Expression::Div(Box::new(tpl.0), Box::new(tpl.1)))
}
@ -333,7 +357,7 @@ named!(div_expression<Expression>,
)
);
fn expression_to_grouped_expression<'a>(e: Expression<'a>) -> ParseResult<Expression<'a>> {
fn expression_to_grouped_expression(e: Expression) -> ParseResult<Expression> {
Ok(Expression::Grouped(Box::new(e)))
}
@ -346,7 +370,7 @@ named!(grouped_expression<Expression>,
named!(selector_list<SelectorList>, separated_nonempty_list!(dot, field));
fn tuple_to_copy<'a>(t: (SelectorList<'a>, FieldList<'a>)) -> ParseResult<Expression<'a>> {
fn tuple_to_copy(t: (SelectorList, FieldList)) -> ParseResult<Expression> {
Ok(Expression::Copy(t.0, t.1))
}
@ -363,11 +387,15 @@ named!(copy_expression<Expression>,
)
);
fn tuple_to_macro<'a>(t: (Vec<Value<'a>>, Value<'a>)) -> ParseResult<Expression<'a>> {
fn value_to_string(v: Value) -> String {
v.to_string()
}
fn tuple_to_macro(mut t: (Vec<Value>, Value)) -> ParseResult<Expression> {
match t.1 {
Value::Tuple(v) => {
Ok(Expression::Macro {
arglist: t.0,
arglist: t.0.drain(0..).map(|s| s.to_string()).collect(),
tuple: v,
})
}
@ -395,8 +423,8 @@ named!(macro_expression<Expression>,
)
);
fn tuple_to_select<'a>(t: (Expression<'a>, Expression<'a>, Value<'a>))
-> ParseResult<Expression<'a>> {
fn tuple_to_select(t: (Expression, Expression, Value))
-> ParseResult<Expression> {
match t.2 {
Value::Tuple(v) => {
Ok(Expression::Select {
@ -425,7 +453,7 @@ named!(select_expression<Expression>,
)
);
fn tuple_to_call<'a>(t: (Value<'a>, Vec<Expression<'a>>)) -> ParseResult<Expression<'a>> {
fn tuple_to_call(t: (Value, Vec<Expression>)) -> ParseResult<Expression> {
if let Value::Selector(sl) = t.0 {
Ok(Expression::Call {
macroref: sl,
@ -436,7 +464,7 @@ fn tuple_to_call<'a>(t: (Value<'a>, Vec<Expression<'a>>)) -> ParseResult<Express
}
}
fn vec_to_selector_value<'a>(v: SelectorList<'a>) -> ParseResult<Value<'a>> {
fn vec_to_selector_value(v: SelectorList) -> ParseResult<Value> {
Ok(Value::Selector(v))
}
@ -496,9 +524,9 @@ named!(expression_statement<Statement>,
)
);
fn tuple_to_let<'a>(t: (&'a str, Expression<'a>)) -> ParseResult<Statement<'a>> {
fn tuple_to_let(t: (String, Expression)) -> ParseResult<Statement> {
Ok(Statement::Let {
name: t.0,
name: t.0.to_string(),
value: t.1,
})
}
@ -516,10 +544,10 @@ named!(let_statement<Statement>,
)
);
fn tuple_to_import<'a>(t: (&'a str, &'a str)) -> ParseResult<Statement<'a>> {
fn tuple_to_import(t: (String, String)) -> ParseResult<Statement> {
Ok(Statement::Import {
name: t.0,
path: t.1,
name: t.0.to_string(),
path: t.1.to_string(),
})
}
@ -552,7 +580,7 @@ named!(pub parse<Vec<Statement> >, many1!(ws!(statement)));
mod test {
use std::str::from_utf8;
use super::{Statement, Expression, Value};
use super::{number, parse, field_value, tuple, grouped_expression, copy_expression};
use super::{number, symbol, parse, field_value, tuple, grouped_expression, copy_expression};
use super::{arglist, macro_expression, select_expression, call_expression, expression};
use super::{expression_statement, let_statement, import_statement, statement};
use nom::IResult;
@ -562,8 +590,8 @@ mod test {
assert_eq!(statement(&b"import \"foo\" as foo;"[..]),
IResult::Done(&b""[..],
Statement::Import{
path: "foo",
name: "foo"
path: "foo".to_string(),
name: "foo".to_string()
}
)
);
@ -571,7 +599,7 @@ mod test {
assert_eq!(statement(&b"let foo = 1.0 ;"[..]),
IResult::Done(&b""[..],
Statement::Let{name: "foo",
Statement::Let{name: "foo".to_string(),
value: Expression::Simple(Value::Float(1.0))}));
assert_eq!(statement(&b"1.0;"[..]),
IResult::Done(&b""[..],
@ -589,8 +617,8 @@ mod test {
assert_eq!(import_statement(&b"import \"foo\" as foo;"[..]),
IResult::Done(&b""[..],
Statement::Import{
path: "foo",
name: "foo"
path: "foo".to_string(),
name: "foo".to_string()
}
)
);
@ -609,15 +637,15 @@ mod test {
assert_eq!(let_statement(&b"let foo = 1.0 ;"[..]),
IResult::Done(&b""[..],
Statement::Let{name: "foo",
Statement::Let{name: "foo".to_string(),
value: Expression::Simple(Value::Float(1.0))}));
assert_eq!(let_statement(&b"let foo= 1.0;"[..]),
IResult::Done(&b""[..],
Statement::Let{name: "foo",
Statement::Let{name: "foo".to_string(),
value: Expression::Simple(Value::Float(1.0))}));
assert_eq!(let_statement(&b"let foo =1.0;"[..]),
IResult::Done(&b""[..],
Statement::Let{name: "foo",
Statement::Let{name: "foo".to_string(),
value: Expression::Simple(Value::Float(1.0))}));
}
@ -639,33 +667,35 @@ mod test {
assert_eq!(expression_statement(&b"foo;"[..]),
IResult::Done(&b""[..],
Statement::Expression(
Expression::Simple(Value::Symbol("foo")))));
Expression::Simple(Value::Symbol("foo".to_string())))));
assert_eq!(expression_statement(&b"foo ;"[..]),
IResult::Done(&b""[..],
Statement::Expression(
Expression::Simple(Value::Symbol("foo")))));
Expression::Simple(Value::Symbol("foo".to_string())))));
assert_eq!(expression_statement(&b" foo;"[..]),
IResult::Done(&b""[..],
Statement::Expression(
Expression::Simple(Value::Symbol("foo")))));
Expression::Simple(Value::Symbol("foo".to_string())))));
assert_eq!(expression_statement(&b"\"foo\";"[..]),
IResult::Done(&b""[..],
Statement::Expression(
Expression::Simple(Value::String("foo")))));
Expression::Simple(Value::String("foo".to_string())))));
assert_eq!(expression_statement(&b"\"foo\" ;"[..]),
IResult::Done(&b""[..],
Statement::Expression(
Expression::Simple(Value::String("foo")))));
Expression::Simple(Value::String("foo".to_string())))));
assert_eq!(expression_statement(&b" \"foo\";"[..]),
IResult::Done(&b""[..],
Statement::Expression(
Expression::Simple(Value::String("foo")))));
Expression::Simple(Value::String("foo".to_string())))));
}
#[test]
fn test_expression_parse() {
assert_eq!(expression(&b"1"[..]),
IResult::Done(&b""[..], Expression::Simple(Value::Int(1))));
assert_eq!(expression(&b"foo"[..]),
IResult::Done(&b""[..], Expression::Simple(Value::Symbol("foo".to_string()))));
assert_eq!(expression(&b"1 + 1"[..]),
IResult::Done(&b""[..],
Expression::Add(Box::new(Value::Int(1)),
@ -703,11 +733,11 @@ mod test {
IResult::Done(&b""[..],
Expression::Macro{
arglist: vec![
Value::Symbol("arg1"),
Value::Symbol("arg2")
"arg1".to_string(),
"arg2".to_string(),
],
tuple: vec![
("foo", Expression::Simple(Value::Symbol("arg1"))),
("foo".to_string(), Expression::Simple(Value::Symbol("arg1".to_string()))),
],
}
)
@ -715,10 +745,10 @@ mod test {
assert_eq!(expression(&b"select foo, 1, { foo = 2 };"[..]),
IResult::Done(&b""[..],
Expression::Select{
val: Box::new(Expression::Simple(Value::Symbol("foo"))),
val: Box::new(Expression::Simple(Value::Symbol("foo".to_string()))),
default: Box::new(Expression::Simple(Value::Int(1))),
tuple: vec![
("foo", Expression::Simple(Value::Int(2)))
("foo".to_string(), Expression::Simple(Value::Int(2)))
]
}
)
@ -726,10 +756,10 @@ mod test {
assert_eq!(expression(&b"foo.bar (1, \"foo\")"[..]),
IResult::Done(&b""[..],
Expression::Call{
macroref: vec!["foo","bar"],
macroref: vec!["foo".to_string(),"bar".to_string()],
arglist: vec![
Expression::Simple(Value::Int(1)),
Expression::Simple(Value::String("foo")),
Expression::Simple(Value::String("foo".to_string())),
],
}
)
@ -759,10 +789,10 @@ mod test {
assert_eq!(call_expression(&b"foo (1, \"foo\")"[..]),
IResult::Done(&b""[..],
Expression::Call{
macroref: vec!["foo"],
macroref: vec!["foo".to_string()],
arglist: vec![
Expression::Simple(Value::Int(1)),
Expression::Simple(Value::String("foo")),
Expression::Simple(Value::String("foo".to_string())),
],
}
)
@ -771,10 +801,10 @@ mod test {
assert_eq!(call_expression(&b"foo.bar (1, \"foo\")"[..]),
IResult::Done(&b""[..],
Expression::Call{
macroref: vec!["foo","bar"],
macroref: vec!["foo".to_string(),"bar".to_string()],
arglist: vec![
Expression::Simple(Value::Int(1)),
Expression::Simple(Value::String("foo")),
Expression::Simple(Value::String("foo".to_string())),
],
}
)
@ -791,10 +821,10 @@ mod test {
assert_eq!(select_expression(&b"select foo, 1, { foo = 2 };"[..]),
IResult::Done(&b""[..],
Expression::Select{
val: Box::new(Expression::Simple(Value::Symbol("foo"))),
val: Box::new(Expression::Simple(Value::Symbol("foo".to_string()))),
default: Box::new(Expression::Simple(Value::Int(1))),
tuple: vec![
("foo", Expression::Simple(Value::Int(2)))
("foo".to_string(), Expression::Simple(Value::Int(2)))
]
}
)
@ -818,10 +848,10 @@ mod test {
assert_eq!(macro_expression(&b"macro (arg1, arg2) => {foo=1,bar=2}"[..]),
IResult::Done(&b""[..],
Expression::Macro{
arglist: vec![Value::Symbol("arg1"),
Value::Symbol("arg2")],
tuple: vec![("foo", Expression::Simple(Value::Int(1))),
("bar", Expression::Simple(Value::Int(2)))
arglist: vec!["arg1".to_string(),
"arg2".to_string()],
tuple: vec![("foo".to_string(), Expression::Simple(Value::Int(1))),
("bar".to_string(), Expression::Simple(Value::Int(2)))
]
}
)
@ -834,8 +864,8 @@ mod test {
assert!(arglist(&b"arg1, arg2"[..]).is_done());
assert_eq!(arglist(&b"arg1, arg2"[..]), IResult::Done(&b""[..],
vec![
Value::Symbol("arg1"),
Value::Symbol("arg2")
Value::Symbol("arg1".to_string()),
Value::Symbol("arg2".to_string())
]));
}
@ -846,14 +876,14 @@ mod test {
assert!(copy_expression(&b"foo{"[..]).is_incomplete() );
assert_eq!(copy_expression(&b"foo{}"[..]),
IResult::Done(&b""[..],
Expression::Copy(vec!["foo"],
Expression::Copy(vec!["foo".to_string()],
Vec::new())
)
);
assert_eq!(copy_expression(&b"foo{bar=1}"[..]),
IResult::Done(&b""[..],
Expression::Copy(vec!["foo"],
vec![("bar", Expression::Simple(Value::Int(1)))])
Expression::Copy(vec!["foo".to_string()],
vec![("bar".to_string(), Expression::Simple(Value::Int(1)))])
)
);
}
@ -867,7 +897,7 @@ mod test {
Expression::Grouped(
Box::new(
Expression::Simple(
Value::Symbol("foo")))))
Value::Symbol("foo".to_string())))))
);
assert_eq!(grouped_expression(&b"(1 + 1)"[..]),
IResult::Done(&b""[..],
@ -902,22 +932,22 @@ mod test {
IResult::Done(&b""[..],
Value::Tuple(
vec![
("foo", Expression::Simple(Value::Int(1)))
("foo".to_string(), Expression::Simple(Value::Int(1)))
])));
assert_eq!(tuple(&b"{ foo = 1, bar = \"1\" }"[..]),
IResult::Done(&b""[..],
Value::Tuple(
vec![
("foo", Expression::Simple(Value::Int(1))),
("bar", Expression::Simple(Value::String("1")))
("foo".to_string(), Expression::Simple(Value::Int(1))),
("bar".to_string(), Expression::Simple(Value::String("1".to_string())))
])));
assert_eq!(tuple(&b"{ foo = 1, bar = {} }"[..]),
IResult::Done(&b""[..],
Value::Tuple(
vec![
("foo", Expression::Simple(Value::Int(1))),
("bar", Expression::Simple(Value::Tuple(Vec::new())))
("foo".to_string(), Expression::Simple(Value::Int(1))),
("bar".to_string(), Expression::Simple(Value::Tuple(Vec::new())))
])));
}
@ -927,13 +957,13 @@ mod test {
assert!(field_value(&b"foo ="[..]).is_incomplete() );
assert_eq!(field_value(&b"foo = 1"[..]),
IResult::Done(&b""[..], ("foo", Expression::Simple(Value::Int(1)))) );
IResult::Done(&b""[..], ("foo".to_string(), Expression::Simple(Value::Int(1)))) );
assert_eq!(field_value(&b"foo = \"1\""[..]),
IResult::Done(&b""[..], ("foo", Expression::Simple(Value::String("1")))) );
IResult::Done(&b""[..], ("foo".to_string(), Expression::Simple(Value::String("1".to_string())))) );
assert_eq!(field_value(&b"foo = bar"[..]),
IResult::Done(&b""[..], ("foo", Expression::Simple(Value::Symbol("bar")))) );
IResult::Done(&b""[..], ("foo".to_string(), Expression::Simple(Value::Symbol("bar".to_string())))) );
assert_eq!(field_value(&b"foo = bar "[..]),
IResult::Done(&b""[..], ("foo", Expression::Simple(Value::Symbol("bar")))) );
IResult::Done(&b""[..], ("foo".to_string(), Expression::Simple(Value::Symbol("bar".to_string())))) );
}
#[test]
@ -950,6 +980,12 @@ mod test {
IResult::Done(&b""[..], Value::Float(0.1)) );
}
#[test]
fn test_symbol_parsing() {
assert_eq!(symbol(&b"foo"[..]),
IResult::Done(&b""[..], Value::Symbol("foo".to_string())) );
}
#[test]
fn test_parse() {
let bad_input = &b"import mylib as lib;"[..];
@ -967,11 +1003,11 @@ mod test {
assert_eq!(tpl.1,
vec![
Statement::Import{
path: "mylib",
name: "lib"
path: "mylib".to_string(),
name: "lib".to_string()
},
Statement::Let{
name: "foo",
name: "foo".to_string(),
value: Expression::Simple(Value::Int(1))
},
Statement::Expression(