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::error::Error;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::rc::Rc;
use std::fmt; use std::fmt;
use std::fmt::{Display,Formatter}; use std::fmt::{Display,Formatter};
use std::ops::Deref;
use std::rc::Rc;
quick_error! { quick_error! {
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
@ -35,6 +36,10 @@ quick_error! {
description("Eval Error") description("Eval Error")
display("No Such Variable {}", msg) display("No Such Variable {}", msg)
} }
BadArgLen(msg: String) {
description("Eval Error")
display("Bad Argument Length {}", msg)
}
TODO(msg: String) { TODO(msg: String) {
description("TODO Error") description("TODO Error")
display("TODO Error {}", msg) display("TODO Error {}", msg)
@ -45,31 +50,56 @@ quick_error! {
/// BuildResult is the result of a build. /// BuildResult is the result of a build.
type BuildResult = Result<(), Box<Error>>; 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)] #[derive(PartialEq,Debug,Clone)]
pub struct MacroDef<'a> { pub struct MacroDef {
argdefs: Vec<&'a str>, argdefs: Vec<String>,
fields: FieldList<'a>, fields: FieldList,
} }
impl<'a> MacroDef<'a> { impl MacroDef {
fn eval(&'a self, args: Vec<Expression<'a>>) -> Result<Vec<(&'a str, Rc<Val<'a>>)>, Box<Error>> { fn eval(&self, mut args: Vec<Rc<Val>>) -> Result<Vec<(String, Rc<Val>)>, Box<Error>> {
Err(Box::new( // Error conditions. If the args don't match the length and types of the argdefs then this is
BuildError::TODO( // macro call error.
"Macro Calls are not implemented yet".to_string()))) 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. /// Val is the type of a value for a field in a Tuple.
#[derive(PartialEq,Debug,Clone)] #[derive(PartialEq,Debug,Clone)]
pub enum Val<'a> { pub enum Val {
Int(i64), Int(i64),
Float(f64), Float(f64),
String(String), String(String),
Tuple(Vec<(&'a str, Rc<Val<'a>>)>), Tuple(Vec<(String, Rc<Val>)>),
Macro(MacroDef<'a>), Macro(MacroDef),
} }
impl<'a> Val<'a> { impl Val {
pub fn type_name(&self) -> String { pub fn type_name(&self) -> String {
match self { 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 { if let &Val::Tuple(ref fs) = self {
Some(fs) Some(fs)
} else { } 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 { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
// TODO(jwall): These should render better than this. // TODO(jwall): These should render better than this.
write!(f, "{}", self.type_name()) 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. /// ValueMap defines a set of values in a parsed file.
#[derive(PartialEq,Debug)] #[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. /// 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 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 /// assets are other parsed files from import statements. They
/// are keyed by the normalized import path. This acts as a cache /// 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 /// so multiple imports of the same file don't have to be parsed
/// multiple times. /// multiple times.
assets: HashMap<&'a str, ValueMap<'a>>, assets: HashMap<String, ValueMap>,
/// out is our built output. /// out is our built output.
out: HashMap<&'a str, Rc<Val<'a>>>, out: HashMap<String, Rc<Val>>,
} }
macro_rules! eval_binary_expr { 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. /// 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 { match v {
Value::Int(i) => Ok(Rc::new(Val::Int(i))), Value::Int(i) => Ok(Rc::new(Val::Int(i))),
Value::Float(f) => Ok(Rc::new(Val::Float(f))), Value::Float(f) => Ok(Rc::new(Val::Float(f))),
Value::String(s) => Ok(Rc::new(Val::String(s.to_string()))), Value::String(s) => Ok(Rc::new(Val::String(s.to_string()))),
Value::Symbol(s) => { Value::Symbol(s) => {
self.lookup_sym(s).ok_or(Box::new( self.lookup_sym(&s).ok_or(Box::new(
BuildError::NoSuchSymbol(s.to_string()))) BuildError::NoSuchSymbol(format!("Unable to find {}", s))))
}, },
Value::Tuple(fields) => { Value::Tuple(fields) => {
// TODO(jwall): We need to resolve the expressions here. // 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 { pub fn build_dir(&mut self, name: &str) -> BuildResult {
Ok(()) Ok(())
} }
@ -216,7 +254,7 @@ impl<'a> Builder<'a> {
Ok(()) 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) { if self.out.contains_key(sym) {
Some(self.out[sym].clone()) Some(self.out[sym].clone())
} else { } 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() { for (key, val) in fs.iter().cloned() {
if target == key { if target == key {
return Some(val.clone()) return Some(val.clone())
@ -233,11 +271,11 @@ impl<'a> Builder<'a> {
return None 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(); let len = sl.len();
if len > 0 { if len > 0 {
println!("Looking up symbol {}", sl[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(); let mut it = sl.iter().skip(1).peekable();
if it.peek().is_none() { if it.peek().is_none() {
return Ok(v.clone()); 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. // eval_expr evals a single Expression in the context of a running Builder.
// It does not mutate the builders collected state at all. // 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 { match expr {
Expression::Simple(val) => { Expression::Simple(val) => {
self.from(val) self.from(val)
@ -387,10 +427,10 @@ impl<'a> Builder<'a> {
Expression::Copy(sel, mut fields) => { Expression::Copy(sel, mut fields) => {
let v = try!(self.lookup_selector(sel)); let v = try!(self.lookup_selector(sel));
if let Val::Tuple(ref src_fields) = *v { 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 // loop through fields and build up a hasmap
for &(ref key, ref val) in src_fields.iter() { 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()); v.insert(val.clone());
} else { } else {
// TODO(jwall): Is this an error? // TODO(jwall): Is this an error?
@ -401,7 +441,7 @@ impl<'a> Builder<'a> {
} }
for (key, val) in fields.drain(0..) { for (key, val) in fields.drain(0..) {
let expr_result = try!(self.eval_expr(val)); let expr_result = try!(self.eval_expr(val));
match m.entry(key) { match m.entry(key.clone()) {
Entry::Vacant(mut v) => { Entry::Vacant(mut v) => {
v.insert(expr_result); 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 // 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. // 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))); return Ok(Rc::new(Val::Tuple(new_fields)));
} }
Err(Box::new( Err(Box::new(
@ -434,20 +476,51 @@ impl<'a> Builder<'a> {
Expression::Grouped(expr) => { Expression::Grouped(expr) => {
return self.eval_expr(*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( Err(Box::new(
BuildError::TODO( BuildError::TypeFail(
"TODO(jwall): Unimplemented Expression".to_string()))) // We should pretty print the selectors here.
format!("{} is not a Macro", v))))
}, },
Expression::Macro{arglist: args, tuple: fields} => { Expression::Macro{arglist: args, tuple: fields} => {
Err(Box::new( // TODO(jwall): Walk the AST and verify that the symbols all
BuildError::TODO( // exist as names in the arglist.
"TODO(jwall): Unimplemented Expression".to_string()))) let md = MacroDef{
argdefs: args,
fields: fields,
};
Ok(Rc::new(Val::Macro(md)))
}, },
Expression::Select{val: target, default: def_expr, tuple: fields} => { Expression::Select{val: target, default: def_expr, tuple: mut fields} => {
Err(Box::new( // First resolve the target expression.
BuildError::TODO( let v = try!(self.eval_expr(*target));
"TODO(jwall): Unimplemented Expression".to_string()))) // 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)] #[cfg(test)]
mod test { mod test {
use super::{Builder,Val}; use super::{Builder,Val,MacroDef};
use parse::{Expression, Value}; use parse::{Expression, Value};
use std::rc::Rc; use std::rc::Rc;
@ -517,7 +590,8 @@ mod test {
fn test_eval_mul_expr_fail() { fn test_eval_mul_expr_fail() {
let mut b = Builder::new(); let mut b = Builder::new();
test_expr_to_val(vec![ 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)), Val::Float(1.0)),
], b); ], b);
} }
@ -526,9 +600,11 @@ mod test {
fn test_eval_subtract_expr() { fn test_eval_subtract_expr() {
let mut b = Builder::new(); let mut b = Builder::new();
test_expr_to_val(vec![ 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)), 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)), Val::Float(1.0)),
], b); ], b);
} }
@ -538,7 +614,8 @@ mod test {
fn test_eval_subtract_expr_fail() { fn test_eval_subtract_expr_fail() {
let mut b = Builder::new(); let mut b = Builder::new();
test_expr_to_val(vec![ 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)), Val::Float(1.0)),
], b); ], b);
} }
@ -547,11 +624,14 @@ mod test {
fn test_eval_add_expr() { fn test_eval_add_expr() {
let mut b = Builder::new(); let mut b = Builder::new();
test_expr_to_val(vec![ 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)), 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)), 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())), Val::String("foobar".to_string())),
], b); ], b);
} }
@ -561,7 +641,8 @@ mod test {
fn test_eval_add_expr_fail() { fn test_eval_add_expr_fail() {
let mut b = Builder::new(); let mut b = Builder::new();
test_expr_to_val(vec![ 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)), Val::Float(1.0)),
], b); ], b);
} }
@ -571,59 +652,67 @@ mod test {
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Simple(Value::Int(1)), Val::Int(1)), (Expression::Simple(Value::Int(1)), Val::Int(1)),
(Expression::Simple(Value::Float(2.0)), Val::Float(2.0)), (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()); ], Builder::new());
} }
#[test] #[test]
fn test_eval_simple_lookup_expr() { fn test_eval_simple_lookup_expr() {
let mut b = Builder::new(); 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![ test_expr_to_val(vec![
(Expression::Simple(Value::Symbol("var1")), Val::Int(1)), (Expression::Simple(Value::Symbol("var1".to_string())), Val::Int(1)),
], b); ], b);
} }
#[test] #[test]
fn test_eval_simple_lookup_error() { fn test_eval_simple_lookup_error() {
let mut b = Builder::new(); 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)));
assert!(b.eval_expr(Expression::Simple(Value::Symbol("var"))).is_err()); assert!(b.eval_expr(Expression::Simple(Value::Symbol("var".to_string()))).is_err());
} }
#[test] #[test]
fn test_eval_selector_expr() { fn test_eval_selector_expr() {
// TODO(jwall): Tests for this expression. // TODO(jwall): Tests for this expression.
let mut b = Builder::new(); let mut b = Builder::new();
b.out.entry("var1").or_insert(Rc::new(Val::Tuple(vec![ b.out.entry("var1".to_string()).or_insert(Rc::new(Val::Tuple(vec![
("lvl1", Rc::new(Val::Tuple( ("lvl1".to_string(), Rc::new(Val::Tuple(
vec![ 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("var2".to_string()).or_insert(Rc::new(Val::Int(2)));
b.out.entry("var3").or_insert(Rc::new(Val::Tuple(vec![ b.out.entry("var3".to_string()).or_insert(Rc::new(Val::Tuple(vec![
("lvl1", Rc::new(Val::Int(4))) ("lvl1".to_string(), Rc::new(Val::Int(4)))
]))); ])));
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Simple(Value::Selector(vec!["var1"])), Val::Tuple( (Expression::Simple(Value::Selector(vec!["var1".to_string()])), Val::Tuple(
vec![ vec![
("lvl1", Rc::new(Val::Tuple( ("lvl1".to_string(), Rc::new(Val::Tuple(
vec![ 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![ 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!["var1".to_string(),
(Expression::Simple(Value::Selector(vec!["var2"])), Val::Int(2)), "lvl1".to_string(),
(Expression::Simple(Value::Selector(vec!["var3", "lvl1"])), Val::Int(4)), "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); ], b);
} }
@ -632,7 +721,7 @@ mod test {
fn test_expr_copy_no_such_tuple() { fn test_expr_copy_no_such_tuple() {
let mut b = Builder::new(); let mut b = Builder::new();
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Copy(vec!["tpl1"], Vec::new()), (Expression::Copy(vec!["tpl1".to_string()], Vec::new()),
Val::Tuple(Vec::new())), Val::Tuple(Vec::new())),
], b); ], b);
} }
@ -641,9 +730,9 @@ mod test {
#[should_panic(expected = "Expected Tuple got Integer")] #[should_panic(expected = "Expected Tuple got Integer")]
fn test_expr_copy_not_a_tuple() { fn test_expr_copy_not_a_tuple() {
let mut b = Builder::new(); 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![ test_expr_to_val(vec![
(Expression::Copy(vec!["tpl1"], Vec::new()), (Expression::Copy(vec!["tpl1".to_string()], Vec::new()),
Val::Tuple(Vec::new())), Val::Tuple(Vec::new())),
], b); ], b);
} }
@ -652,15 +741,16 @@ mod test {
#[should_panic(expected = "Expected type Integer for field fld1 but got String")] #[should_panic(expected = "Expected type Integer for field fld1 but got String")]
fn test_expr_copy_field_type_error() { fn test_expr_copy_field_type_error() {
let mut b = Builder::new(); let mut b = Builder::new();
b.out.entry("tpl1").or_insert(Rc::new(Val::Tuple(vec![ b.out.entry("tpl1".to_string()).or_insert(Rc::new(Val::Tuple(vec![
("fld1", Rc::new(Val::Int(1))), ("fld1".to_string(), Rc::new(Val::Int(1))),
]))); ])));
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Copy(vec!["tpl1"], (Expression::Copy(vec!["tpl1".to_string()],
vec![("fld1", Expression::Simple(Value::String("2")))]), vec![("fld1".to_string(),
Expression::Simple(Value::String("2".to_string())))]),
Val::Tuple( Val::Tuple(
vec![ vec![
("fld1", Rc::new(Val::String("2".to_string()))), ("fld1".to_string(), Rc::new(Val::String("2".to_string()))),
], ],
)), )),
], b); ], b);
@ -672,41 +762,132 @@ mod test {
fn test_expr_copy() { fn test_expr_copy() {
// TODO(jwall): Tests for this expression. // TODO(jwall): Tests for this expression.
let mut b = Builder::new(); let mut b = Builder::new();
b.out.entry("tpl1").or_insert(Rc::new(Val::Tuple(vec![ b.out.entry("tpl1".to_string()).or_insert(Rc::new(Val::Tuple(vec![
("fld1", Rc::new(Val::Int(1))), ("fld1".to_string(), Rc::new(Val::Int(1))),
]))); ])));
test_expr_to_val(vec![ test_expr_to_val(vec![
(Expression::Copy(vec!["tpl1"], (Expression::Copy(vec!["tpl1".to_string()],
vec![("fld2", Expression::Simple(Value::String("2")))]), vec![("fld2".to_string(),
Expression::Simple(Value::String("2".to_string())))]),
// Add a new field to the copy // Add a new field to the copy
Val::Tuple( Val::Tuple(
// NOTE(jwall): The order of these is important in order to ensure // NOTE(jwall): The order of these is important in order to ensure
// that the compare assertion is correct. The ordering has no // that the compare assertion is correct. The ordering has no
// semantics though so at some point we should probably be less restrictive. // semantics though so at some point we should probably be less restrictive.
vec![ vec![
("fld1", Rc::new(Val::Int(1))), ("fld1".to_string(), Rc::new(Val::Int(1))),
("fld2", Rc::new(Val::String("2".to_string()))), ("fld2".to_string(), Rc::new(Val::String("2".to_string()))),
], ],
)), )),
// Overwrite a field in the copy // Overwrite a field in the copy
(Expression::Copy(vec!["tpl1"], (Expression::Copy(vec!["tpl1".to_string()],
vec![ vec![
("fld1", Expression::Simple(Value::Int(3))), ("fld1".to_string(),
("fld2", Expression::Simple(Value::String("2"))), Expression::Simple(Value::Int(3))),
("fld2".to_string(),
Expression::Simple(Value::String("2".to_string()))),
]), ]),
Val::Tuple( Val::Tuple(
vec![ vec![
("fld1", Rc::new(Val::Int(3))), ("fld1".to_string(), Rc::new(Val::Int(3))),
("fld2", Rc::new(Val::String("2".to_string()))), ("fld2".to_string(), Rc::new(Val::String("2".to_string()))),
], ],
)), )),
// The source tuple is still unmodified. // The source tuple is still unmodified.
(Expression::Simple(Value::Selector(vec!["tpl1"])), (Expression::Simple(Value::Selector(vec!["tpl1".to_string()])),
Val::Tuple( Val::Tuple(
vec![ vec![
("fld1", Rc::new(Val::Int(1))), ("fld1".to_string(), Rc::new(Val::Int(1))),
], ],
)), )),
], b); ], 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>>; 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 FieldList = Vec<(String, Expression)>; // str is expected to be a symbol
pub type SelectorList<'a> = Vec<&'a str>; // str is expected to always 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. /// Value represents a Value in the UCG parsed AST.
#[derive(Debug,PartialEq,Clone)] #[derive(Debug,PartialEq,Clone)]
pub enum Value<'a> { pub enum Value {
// Constant Values // Constant Values
Int(i64), Int(i64),
Float(f64), Float(f64),
String(&'a str), String(String),
Symbol(&'a str), Symbol(String),
// Complex Values // Complex Values
Tuple(FieldList<'a>), Tuple(FieldList),
Selector(SelectorList<'a>), Selector(SelectorList),
} }
impl<'a> Value<'a> { impl Value {
pub fn type_name(&self) -> String { pub fn type_name(&self) -> String {
match self { match self {
&Value::Int(_) => "Integer".to_string(), &Value::Int(_) => "Integer".to_string(),
@ -56,55 +56,78 @@ impl<'a> Value<'a> {
&Value::Selector(_) => "Selector".to_string(), &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. /// Expression encodes an expression. Expressions compute a value from operands.
#[derive(Debug,PartialEq,Clone)] #[derive(Debug,PartialEq,Clone)]
pub enum Expression<'a> { pub enum Expression {
// Base Expression // Base Expression
Simple(Value<'a>), Simple(Value),
// Binary Expressions // Binary Expressions
Add(Box<Value<'a>>, Box<Expression<'a>>), Add(Box<Value>, Box<Expression>),
Sub(Box<Value<'a>>, Box<Expression<'a>>), Sub(Box<Value>, Box<Expression>),
Mul(Box<Value<'a>>, Box<Expression<'a>>), Mul(Box<Value>, Box<Expression>),
Div(Box<Value<'a>>, Box<Expression<'a>>), Div(Box<Value>, Box<Expression>),
// Complex Expressions // Complex Expressions
Copy(SelectorList<'a>, FieldList<'a>), Copy(SelectorList, FieldList),
Grouped(Box<Expression<'a>>), Grouped(Box<Expression>),
Call { Call {
macroref: SelectorList<'a>, macroref: SelectorList,
arglist: Vec<Expression<'a>>, arglist: Vec<Expression>,
}, },
Macro { Macro {
arglist: Vec<Value<'a>>, arglist: Vec<String>,
tuple: FieldList<'a>, tuple: FieldList,
}, },
Select { Select {
val: Box<Expression<'a>>, val: Box<Expression>,
default: Box<Expression<'a>>, default: Box<Expression>,
tuple: FieldList<'a>, tuple: FieldList,
}, },
} }
/// Statement encodes a parsed Statement in the UCG AST. /// Statement encodes a parsed Statement in the UCG AST.
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub enum Statement<'a> { pub enum Statement {
// simple expression // simple expression
Expression(Expression<'a>), Expression(Expression),
// Named bindings // Named bindings
Let { Let {
name: &'a str, name: String,
value: Expression<'a>, value: Expression,
}, },
// Include a file. // Include a file.
Import { Import {
path: &'a str, path: String,
name: &'a str, name: String,
}, },
} }
@ -125,12 +148,13 @@ named!(semicolon, tag!(";"));
named!(fatcomma, tag!("=>")); named!(fatcomma, tag!("=>"));
// a field is the building block of symbols and tuple field names. // 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)), 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)) 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)); named!(symbol<Value>, map_res!(field, symbol_to_value));
// quoted is a quoted string. // quoted is a quoted string.
named!(quoted<&str>, named!(quoted<String>,
map_res!(delimited!(doublequote, take_until!("\""), doublequote), 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)) Ok(Value::String(s))
} }
@ -154,8 +178,8 @@ named!(quoted_value<Value>,
); );
// Helper function to make the return types work for down below. // 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]>)) fn triple_to_number(v: (Option<&[u8]>, Option<&[u8]>, Option<&[u8]>))
-> ParseResult<Value<'a>> { -> ParseResult<Value> {
let pref = match v.0 { let pref = match v.0 {
None => "", None => "",
Some(bs) => try!(from_utf8(bs)), Some(bs) => try!(from_utf8(bs)),
@ -223,7 +247,7 @@ named!(value<Value>, alt!(number | quoted_value | symbol | tuple));
named!( named!(
#[doc="Capture a field and value pair composed of `<symbol> = <value>,`"], #[doc="Capture a field and value pair composed of `<symbol> = <value>,`"],
field_value<(&str, Expression) >, field_value<(String, Expression) >,
do_parse!( do_parse!(
field: field >> field: field >>
ws!(equal) >> ws!(equal) >>
@ -233,7 +257,7 @@ named!(
); );
// Helper function to make the return types work for down below. // 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)) 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))) 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))) 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))) 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))) 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))) Ok(Expression::Grouped(Box::new(e)))
} }
@ -346,7 +370,7 @@ named!(grouped_expression<Expression>,
named!(selector_list<SelectorList>, separated_nonempty_list!(dot, field)); 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)) 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 { match t.1 {
Value::Tuple(v) => { Value::Tuple(v) => {
Ok(Expression::Macro { Ok(Expression::Macro {
arglist: t.0, arglist: t.0.drain(0..).map(|s| s.to_string()).collect(),
tuple: v, tuple: v,
}) })
} }
@ -395,8 +423,8 @@ named!(macro_expression<Expression>,
) )
); );
fn tuple_to_select<'a>(t: (Expression<'a>, Expression<'a>, Value<'a>)) fn tuple_to_select(t: (Expression, Expression, Value))
-> ParseResult<Expression<'a>> { -> ParseResult<Expression> {
match t.2 { match t.2 {
Value::Tuple(v) => { Value::Tuple(v) => {
Ok(Expression::Select { 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 { if let Value::Selector(sl) = t.0 {
Ok(Expression::Call { Ok(Expression::Call {
macroref: sl, 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)) 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 { Ok(Statement::Let {
name: t.0, name: t.0.to_string(),
value: t.1, 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 { Ok(Statement::Import {
name: t.0, name: t.0.to_string(),
path: t.1, path: t.1.to_string(),
}) })
} }
@ -552,7 +580,7 @@ named!(pub parse<Vec<Statement> >, many1!(ws!(statement)));
mod test { mod test {
use std::str::from_utf8; use std::str::from_utf8;
use super::{Statement, Expression, Value}; 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::{arglist, macro_expression, select_expression, call_expression, expression};
use super::{expression_statement, let_statement, import_statement, statement}; use super::{expression_statement, let_statement, import_statement, statement};
use nom::IResult; use nom::IResult;
@ -562,8 +590,8 @@ mod test {
assert_eq!(statement(&b"import \"foo\" as foo;"[..]), assert_eq!(statement(&b"import \"foo\" as foo;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Import{ Statement::Import{
path: "foo", path: "foo".to_string(),
name: "foo" name: "foo".to_string()
} }
) )
); );
@ -571,7 +599,7 @@ mod test {
assert_eq!(statement(&b"let foo = 1.0 ;"[..]), assert_eq!(statement(&b"let foo = 1.0 ;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Let{name: "foo", Statement::Let{name: "foo".to_string(),
value: Expression::Simple(Value::Float(1.0))})); value: Expression::Simple(Value::Float(1.0))}));
assert_eq!(statement(&b"1.0;"[..]), assert_eq!(statement(&b"1.0;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
@ -589,8 +617,8 @@ mod test {
assert_eq!(import_statement(&b"import \"foo\" as foo;"[..]), assert_eq!(import_statement(&b"import \"foo\" as foo;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Import{ Statement::Import{
path: "foo", path: "foo".to_string(),
name: "foo" name: "foo".to_string()
} }
) )
); );
@ -609,15 +637,15 @@ mod test {
assert_eq!(let_statement(&b"let foo = 1.0 ;"[..]), assert_eq!(let_statement(&b"let foo = 1.0 ;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Let{name: "foo", Statement::Let{name: "foo".to_string(),
value: Expression::Simple(Value::Float(1.0))})); value: Expression::Simple(Value::Float(1.0))}));
assert_eq!(let_statement(&b"let foo= 1.0;"[..]), assert_eq!(let_statement(&b"let foo= 1.0;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Let{name: "foo", Statement::Let{name: "foo".to_string(),
value: Expression::Simple(Value::Float(1.0))})); value: Expression::Simple(Value::Float(1.0))}));
assert_eq!(let_statement(&b"let foo =1.0;"[..]), assert_eq!(let_statement(&b"let foo =1.0;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Let{name: "foo", Statement::Let{name: "foo".to_string(),
value: Expression::Simple(Value::Float(1.0))})); value: Expression::Simple(Value::Float(1.0))}));
} }
@ -639,33 +667,35 @@ mod test {
assert_eq!(expression_statement(&b"foo;"[..]), assert_eq!(expression_statement(&b"foo;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Expression( Statement::Expression(
Expression::Simple(Value::Symbol("foo"))))); Expression::Simple(Value::Symbol("foo".to_string())))));
assert_eq!(expression_statement(&b"foo ;"[..]), assert_eq!(expression_statement(&b"foo ;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Expression( Statement::Expression(
Expression::Simple(Value::Symbol("foo"))))); Expression::Simple(Value::Symbol("foo".to_string())))));
assert_eq!(expression_statement(&b" foo;"[..]), assert_eq!(expression_statement(&b" foo;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Expression( Statement::Expression(
Expression::Simple(Value::Symbol("foo"))))); Expression::Simple(Value::Symbol("foo".to_string())))));
assert_eq!(expression_statement(&b"\"foo\";"[..]), assert_eq!(expression_statement(&b"\"foo\";"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Expression( Statement::Expression(
Expression::Simple(Value::String("foo"))))); Expression::Simple(Value::String("foo".to_string())))));
assert_eq!(expression_statement(&b"\"foo\" ;"[..]), assert_eq!(expression_statement(&b"\"foo\" ;"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Expression( Statement::Expression(
Expression::Simple(Value::String("foo"))))); Expression::Simple(Value::String("foo".to_string())))));
assert_eq!(expression_statement(&b" \"foo\";"[..]), assert_eq!(expression_statement(&b" \"foo\";"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Statement::Expression( Statement::Expression(
Expression::Simple(Value::String("foo"))))); Expression::Simple(Value::String("foo".to_string())))));
} }
#[test] #[test]
fn test_expression_parse() { fn test_expression_parse() {
assert_eq!(expression(&b"1"[..]), assert_eq!(expression(&b"1"[..]),
IResult::Done(&b""[..], Expression::Simple(Value::Int(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"[..]), assert_eq!(expression(&b"1 + 1"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Expression::Add(Box::new(Value::Int(1)), Expression::Add(Box::new(Value::Int(1)),
@ -703,11 +733,11 @@ mod test {
IResult::Done(&b""[..], IResult::Done(&b""[..],
Expression::Macro{ Expression::Macro{
arglist: vec![ arglist: vec![
Value::Symbol("arg1"), "arg1".to_string(),
Value::Symbol("arg2") "arg2".to_string(),
], ],
tuple: vec![ 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 };"[..]), assert_eq!(expression(&b"select foo, 1, { foo = 2 };"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Expression::Select{ 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))), default: Box::new(Expression::Simple(Value::Int(1))),
tuple: vec![ 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\")"[..]), assert_eq!(expression(&b"foo.bar (1, \"foo\")"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Expression::Call{ Expression::Call{
macroref: vec!["foo","bar"], macroref: vec!["foo".to_string(),"bar".to_string()],
arglist: vec![ arglist: vec![
Expression::Simple(Value::Int(1)), 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\")"[..]), assert_eq!(call_expression(&b"foo (1, \"foo\")"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Expression::Call{ Expression::Call{
macroref: vec!["foo"], macroref: vec!["foo".to_string()],
arglist: vec![ arglist: vec![
Expression::Simple(Value::Int(1)), 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\")"[..]), assert_eq!(call_expression(&b"foo.bar (1, \"foo\")"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Expression::Call{ Expression::Call{
macroref: vec!["foo","bar"], macroref: vec!["foo".to_string(),"bar".to_string()],
arglist: vec![ arglist: vec![
Expression::Simple(Value::Int(1)), 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 };"[..]), assert_eq!(select_expression(&b"select foo, 1, { foo = 2 };"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Expression::Select{ 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))), default: Box::new(Expression::Simple(Value::Int(1))),
tuple: vec![ 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}"[..]), assert_eq!(macro_expression(&b"macro (arg1, arg2) => {foo=1,bar=2}"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Expression::Macro{ Expression::Macro{
arglist: vec![Value::Symbol("arg1"), arglist: vec!["arg1".to_string(),
Value::Symbol("arg2")], "arg2".to_string()],
tuple: vec![("foo", Expression::Simple(Value::Int(1))), tuple: vec![("foo".to_string(), Expression::Simple(Value::Int(1))),
("bar", Expression::Simple(Value::Int(2))) ("bar".to_string(), Expression::Simple(Value::Int(2)))
] ]
} }
) )
@ -834,8 +864,8 @@ mod test {
assert!(arglist(&b"arg1, arg2"[..]).is_done()); assert!(arglist(&b"arg1, arg2"[..]).is_done());
assert_eq!(arglist(&b"arg1, arg2"[..]), IResult::Done(&b""[..], assert_eq!(arglist(&b"arg1, arg2"[..]), IResult::Done(&b""[..],
vec![ vec![
Value::Symbol("arg1"), Value::Symbol("arg1".to_string()),
Value::Symbol("arg2") Value::Symbol("arg2".to_string())
])); ]));
} }
@ -846,14 +876,14 @@ mod test {
assert!(copy_expression(&b"foo{"[..]).is_incomplete() ); assert!(copy_expression(&b"foo{"[..]).is_incomplete() );
assert_eq!(copy_expression(&b"foo{}"[..]), assert_eq!(copy_expression(&b"foo{}"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Expression::Copy(vec!["foo"], Expression::Copy(vec!["foo".to_string()],
Vec::new()) Vec::new())
) )
); );
assert_eq!(copy_expression(&b"foo{bar=1}"[..]), assert_eq!(copy_expression(&b"foo{bar=1}"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Expression::Copy(vec!["foo"], Expression::Copy(vec!["foo".to_string()],
vec![("bar", Expression::Simple(Value::Int(1)))]) vec![("bar".to_string(), Expression::Simple(Value::Int(1)))])
) )
); );
} }
@ -867,7 +897,7 @@ mod test {
Expression::Grouped( Expression::Grouped(
Box::new( Box::new(
Expression::Simple( Expression::Simple(
Value::Symbol("foo"))))) Value::Symbol("foo".to_string())))))
); );
assert_eq!(grouped_expression(&b"(1 + 1)"[..]), assert_eq!(grouped_expression(&b"(1 + 1)"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
@ -902,22 +932,22 @@ mod test {
IResult::Done(&b""[..], IResult::Done(&b""[..],
Value::Tuple( Value::Tuple(
vec![ vec![
("foo", Expression::Simple(Value::Int(1))) ("foo".to_string(), Expression::Simple(Value::Int(1)))
]))); ])));
assert_eq!(tuple(&b"{ foo = 1, bar = \"1\" }"[..]), assert_eq!(tuple(&b"{ foo = 1, bar = \"1\" }"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Value::Tuple( Value::Tuple(
vec![ vec![
("foo", Expression::Simple(Value::Int(1))), ("foo".to_string(), Expression::Simple(Value::Int(1))),
("bar", Expression::Simple(Value::String("1"))) ("bar".to_string(), Expression::Simple(Value::String("1".to_string())))
]))); ])));
assert_eq!(tuple(&b"{ foo = 1, bar = {} }"[..]), assert_eq!(tuple(&b"{ foo = 1, bar = {} }"[..]),
IResult::Done(&b""[..], IResult::Done(&b""[..],
Value::Tuple( Value::Tuple(
vec![ vec![
("foo", Expression::Simple(Value::Int(1))), ("foo".to_string(), Expression::Simple(Value::Int(1))),
("bar", Expression::Simple(Value::Tuple(Vec::new()))) ("bar".to_string(), Expression::Simple(Value::Tuple(Vec::new())))
]))); ])));
} }
@ -927,13 +957,13 @@ mod test {
assert!(field_value(&b"foo ="[..]).is_incomplete() ); assert!(field_value(&b"foo ="[..]).is_incomplete() );
assert_eq!(field_value(&b"foo = 1"[..]), 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\""[..]), 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"[..]), 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 "[..]), 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] #[test]
@ -950,6 +980,12 @@ mod test {
IResult::Done(&b""[..], Value::Float(0.1)) ); 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] #[test]
fn test_parse() { fn test_parse() {
let bad_input = &b"import mylib as lib;"[..]; let bad_input = &b"import mylib as lib;"[..];
@ -967,11 +1003,11 @@ mod test {
assert_eq!(tpl.1, assert_eq!(tpl.1,
vec![ vec![
Statement::Import{ Statement::Import{
path: "mylib", path: "mylib".to_string(),
name: "lib" name: "lib".to_string()
}, },
Statement::Let{ Statement::Let{
name: "foo", name: "foo".to_string(),
value: Expression::Simple(Value::Int(1)) value: Expression::Simple(Value::Int(1))
}, },
Statement::Expression( Statement::Expression(