diff --git a/src/build.rs b/src/build.rs index 1ca0978..6b690fd 100644 --- a/src/build.rs +++ b/src/build.rs @@ -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>; +/// 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, + fields: FieldList, } -impl<'a> MacroDef<'a> { - fn eval(&'a self, args: Vec>) -> Result>)>, Box> { - Err(Box::new( - BuildError::TODO( - "Macro Calls are not implemented yet".to_string()))) +impl MacroDef { + fn eval(&self, mut args: Vec>) -> Result)>, Box> { + // 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)> = 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>)>), - Macro(MacroDef<'a>), + Tuple(Vec<(String, Rc)>), + 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>)>> { + pub fn get_fields(&self) -> Option<&Vec<(String, Rc)>> { 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>>); +pub struct ValueMap(HashMap>); /// 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, /// 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, /// out is our built output. - out: HashMap<&'a str, Rc>>, + out: HashMap>, } 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, Box> { + fn from(&self, v: Value) -> Result, Box> { 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>) -> 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> { + fn lookup_sym(&self, sym: &str) -> Option> { 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>)>) -> Option>> { + fn find_in_fieldlist(target: &str, fs: &Vec<(String, Rc)>) -> Option> { 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, Box> { + fn lookup_selector(&self, sl: SelectorList) -> Result, Box> { 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, Box> { + pub fn eval_expr(&self, expr: Expression) -> Result, Box> { + // 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>::new(); + let mut m = HashMap::>::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)> = m.drain().collect(); + let mut new_fields: Vec<(String, Rc)> = 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> = 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); + } } diff --git a/src/parse.rs b/src/parse.rs index 6262c40..f43e48d 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -29,23 +29,23 @@ use nom::{alpha, is_alphanumeric, digit}; type ParseResult = Result>; -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; // 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>, Box>), - Sub(Box>, Box>), - Mul(Box>, Box>), - Div(Box>, Box>), + Add(Box, Box), + Sub(Box, Box), + Mul(Box, Box), + Div(Box, Box), // Complex Expressions - Copy(SelectorList<'a>, FieldList<'a>), - Grouped(Box>), + Copy(SelectorList, FieldList), + Grouped(Box), Call { - macroref: SelectorList<'a>, - arglist: Vec>, + macroref: SelectorList, + arglist: Vec, }, Macro { - arglist: Vec>, - tuple: FieldList<'a>, + arglist: Vec, + tuple: FieldList, }, Select { - val: Box>, - default: Box>, - tuple: FieldList<'a>, + val: Box, + default: Box, + 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, 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> { +fn symbol_to_value(s: String) -> ParseResult { Ok(Value::Symbol(s)) } @@ -138,13 +162,13 @@ fn symbol_to_value<'a>(s: &'a str) -> ParseResult> { named!(symbol, map_res!(field, symbol_to_value)); // quoted is a quoted string. -named!(quoted<&str>, +named!(quoted, 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> { +fn str_to_value(s: String) -> ParseResult { Ok(Value::String(s)) } @@ -154,8 +178,8 @@ named!(quoted_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> { +fn triple_to_number(v: (Option<&[u8]>, Option<&[u8]>, Option<&[u8]>)) + -> ParseResult { let pref = match v.0 { None => "", Some(bs) => try!(from_utf8(bs)), @@ -223,7 +247,7 @@ named!(value, alt!(number | quoted_value | symbol | tuple)); named!( #[doc="Capture a field and value pair composed of ` = ,`"], - 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> { +fn vec_to_tuple(v: FieldList) -> ParseResult { Ok(Value::Tuple(v)) } @@ -269,7 +293,7 @@ named!(simple_expression, ) ); -fn tuple_to_add_expression<'a>(tpl: (Value<'a>, Expression<'a>)) -> ParseResult> { +fn tuple_to_add_expression(tpl: (Value, Expression)) -> ParseResult { Ok(Expression::Add(Box::new(tpl.0), Box::new(tpl.1))) } @@ -285,7 +309,7 @@ named!(add_expression, ) ); -fn tuple_to_sub_expression<'a>(tpl: (Value<'a>, Expression<'a>)) -> ParseResult> { +fn tuple_to_sub_expression(tpl: (Value, Expression)) -> ParseResult { Ok(Expression::Sub(Box::new(tpl.0), Box::new(tpl.1))) } @@ -301,7 +325,7 @@ named!(sub_expression, ) ); -fn tuple_to_mul_expression<'a>(tpl: (Value<'a>, Expression<'a>)) -> ParseResult> { +fn tuple_to_mul_expression(tpl: (Value, Expression)) -> ParseResult { Ok(Expression::Mul(Box::new(tpl.0), Box::new(tpl.1))) } @@ -317,7 +341,7 @@ named!(mul_expression, ) ); -fn tuple_to_div_expression<'a>(tpl: (Value<'a>, Expression<'a>)) -> ParseResult> { +fn tuple_to_div_expression(tpl: (Value, Expression)) -> ParseResult { Ok(Expression::Div(Box::new(tpl.0), Box::new(tpl.1))) } @@ -333,7 +357,7 @@ named!(div_expression, ) ); -fn expression_to_grouped_expression<'a>(e: Expression<'a>) -> ParseResult> { +fn expression_to_grouped_expression(e: Expression) -> ParseResult { Ok(Expression::Grouped(Box::new(e))) } @@ -346,7 +370,7 @@ named!(grouped_expression, named!(selector_list, separated_nonempty_list!(dot, field)); -fn tuple_to_copy<'a>(t: (SelectorList<'a>, FieldList<'a>)) -> ParseResult> { +fn tuple_to_copy(t: (SelectorList, FieldList)) -> ParseResult { Ok(Expression::Copy(t.0, t.1)) } @@ -363,11 +387,15 @@ named!(copy_expression, ) ); -fn tuple_to_macro<'a>(t: (Vec>, Value<'a>)) -> ParseResult> { +fn value_to_string(v: Value) -> String { + v.to_string() +} + +fn tuple_to_macro(mut t: (Vec, Value)) -> ParseResult { 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, ) ); -fn tuple_to_select<'a>(t: (Expression<'a>, Expression<'a>, Value<'a>)) - -> ParseResult> { +fn tuple_to_select(t: (Expression, Expression, Value)) + -> ParseResult { match t.2 { Value::Tuple(v) => { Ok(Expression::Select { @@ -425,7 +453,7 @@ named!(select_expression, ) ); -fn tuple_to_call<'a>(t: (Value<'a>, Vec>)) -> ParseResult> { +fn tuple_to_call(t: (Value, Vec)) -> ParseResult { 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>)) -> ParseResult(v: SelectorList<'a>) -> ParseResult> { +fn vec_to_selector_value(v: SelectorList) -> ParseResult { Ok(Value::Selector(v)) } @@ -496,9 +524,9 @@ named!(expression_statement, ) ); -fn tuple_to_let<'a>(t: (&'a str, Expression<'a>)) -> ParseResult> { +fn tuple_to_let(t: (String, Expression)) -> ParseResult { Ok(Statement::Let { - name: t.0, + name: t.0.to_string(), value: t.1, }) } @@ -516,10 +544,10 @@ named!(let_statement, ) ); -fn tuple_to_import<'a>(t: (&'a str, &'a str)) -> ParseResult> { +fn tuple_to_import(t: (String, String)) -> ParseResult { 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 >, 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(