diff --git a/src/build.rs b/src/build.rs index df67d3d..3be0cf5 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,23 +1,30 @@ -use parse::{parse, Statement, Expression, Value, FieldList}; +use parse::{parse, Statement, Expression, Value, FieldList, SelectorList}; use std::error::Error; -use std::collections::HashMap; -use std::convert::From; +use std::collections::{HashMap, VecDeque}; +use std::collections::hash_map::Entry; +use std::rc::Rc; +use std::fmt; +use std::fmt::{Display,Formatter}; quick_error! { #[derive(Debug,PartialEq)] pub enum BuildError { TypeFail(msg: String) { - description("Eval Error") - display("Eval Error {}", msg) + description("Type Error") + display("Type Error {}", msg) + } + Unsupported(msg: String) { + description("Unsupported Operation") + display("Unsupported Operation {}", msg) } NoSuchSymbol(msg: String) { description("Eval Error") - display("Eval Error {}", msg) + display("No Such Variable {}", msg) } TODO(msg: String) { - description("Eval Error") - display("Eval Error {}", msg) + description("TODO Error") + display("TODO Error {}", msg) } } } @@ -26,27 +33,76 @@ quick_error! { type BuildResult = Result<(), Box>; /// Val is the type of a value for a field in a Tuple. -#[derive(PartialEq,Debug)] +#[derive(PartialEq,Debug,Clone)] pub enum Val<'a> { Int(i64), Float(f64), - String(&'a str), - Symbol(&'a str), - Tuple(FieldList<'a>), + String(String), + Tuple(Vec<(&'a str, Rc>)>), } -impl<'a> From> for Val<'a> { - fn from(v: Value<'a>) -> Self { - match v { - Value::Int(i) => Val::Int(i), - Value::Float(f) => Val::Float(f), - Value::String(s) => Val::String(s), - Value::Symbol(s) => Val::Symbol(s), - Value::Tuple(ref fields) => { - Val::Tuple(Vec::new()) - } +impl<'a> Val<'a> { + + pub fn type_name(&self) -> String { + match self { + &Val::Int(_) => "Integer".to_string(), + &Val::Float(_) => "Float".to_string(), + &Val::String(_) => "String".to_string(), + &Val::Tuple(_) => "Tuple".to_string(), } } + + pub fn type_equal(&self, target: &Self) -> bool { + match self { + &Val::Int(_) => if let &Val::Int(_) = target { true } else { false }, + &Val::Float(_) => if let &Val::Float(_) = target { true } else { false }, + &Val::String(_) => if let &Val::String(_) = target { true } else { false }, + &Val::Tuple(_) => if let &Val::Tuple(_) = target { true } else { false }, + } + } + + pub fn get_fields(&self) -> Option<&Vec<(&'a str, Rc>)>> { + if let &Val::Tuple(ref fs) = self { + Some(fs) + } else { + None + } + } + + pub fn is_int(&self) -> bool { + if let &Val::Int(_) = self { + return true; + } + return false; + } + + pub fn is_float(&self) -> bool { + if let &Val::Float(_) = self { + return true; + } + return false; + } + + pub fn is_string(&self) -> bool { + if let &Val::String(_) = self { + return true; + } + return false; + } + + pub fn is_tuple(&self) -> bool { + if let &Val::Tuple(_) = self { + return true; + } + return false; + } +} + +impl<'a> Display for Val<'a> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + // TODO(jwall): These should render better than this. + write!(f, "{}", self.type_name()) + } } /// Tuple defines a set of fields. @@ -55,7 +111,7 @@ pub struct Tuple<'a>(HashMap<&'a str, Val<'a>>); /// Builder parses one or more statements into a out Tuple. pub struct Builder<'a> { - /// env is the 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>, /// assets are other parsed files from import statements. They /// are keyed by the normalized import path. This acts as a cache @@ -63,28 +119,66 @@ pub struct Builder<'a> { /// multiple times. assets: HashMap<&'a str, Tuple<'a>>, /// out is our built output. - out: Tuple<'a>, + out: HashMap<&'a str, Rc>>, +} + +macro_rules! eval_binary_expr { + ($case:pat, $rside:ident, $result:expr, $msg:expr) => { + match $rside.as_ref() { + $case => { + return Ok(Rc::new($result)) + }, + val => { + return Err(Box::new( + BuildError::TypeFail( + format!("Expected {} but got {}", $msg, val)))) + } + } + } } impl<'a> Builder<'a> { /// new_builder constructs Builder with initialized fields ready to parse. - pub fn new_builder() -> Self { - Builder { - env: HashMap::new(), - assets: HashMap::new(), - out: Tuple(HashMap::new()), + fn from(&self, v: Value<'a>) -> 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()))) + }, + Value::Tuple(fields) => { + // TODO(jwall): We need to resolve the expressions here. + // TODO(jwall): Don't forget we want a stable order for the fields + // in a tuple to make Vec comparisons easier later on. + Err(Box::new( + BuildError::TODO( + "Value::Tuple to Val::Tuple is not yet impolemented.".to_string()))) + }, + Value::Selector(selector_list) => { + self.lookup_selector(selector_list) + }, } } - pub fn build_dir(&self, name: &str) -> BuildResult { + pub fn new() -> Self { + Builder { + env: HashMap::new(), + assets: HashMap::new(), + out: HashMap::new(), + } + } + + pub fn build_dir(&mut self, name: &str) -> BuildResult { Ok(()) } - pub fn build_file(&self, name: &str) -> BuildResult { + pub fn build_file(&mut self, name: &str) -> BuildResult { Ok(()) } - pub fn build(&self, ast: Vec) -> BuildResult { + pub fn build(&mut self, ast: Vec) -> BuildResult { // TODO(jwall): for stmt in ast.iter() { self.build_stmt(stmt); @@ -92,45 +186,223 @@ impl<'a> Builder<'a> { Ok(()) } - fn eval_expr(&'a self, expr: Expression<'a>) -> Result> { + fn lookup_sym(&'a self, sym: &str) -> Option> { + if self.out.contains_key(sym) { + Some(self.out[sym].clone()) + } else { + None + } + } + + fn find_in_fieldlist(target: &str, fs: &Vec<(&str, Rc>)>) -> Option>> { + for (key, val) in fs.iter().cloned() { + if target == key { + return Some(val.clone()) + } + } + return None + } + + fn lookup_selector(&'a 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]) { + let mut it = sl.iter().skip(1).peekable(); + if it.peek().is_none() { + return Ok(v.clone()); + } + if let &Val::Tuple(ref fs) = v.as_ref() { + let mut stack = VecDeque::new(); + stack.push_back(v.clone()); + loop { + let vref = stack.pop_front().unwrap(); + if it.peek().is_none() { + return Ok(vref.clone()); + } + // This unwrap is safe because we already checked for + // None above. + let k = it.next().unwrap(); + if !vref.is_tuple() { + return Err(Box::new(BuildError::NoSuchSymbol( + format!("Attempted to dereference non-tuple {:?} at field {}.", sl, k)))); + } + // This unwrap is safe because we already checked for + // Tuple above. + let fs = vref.get_fields().unwrap(); + if let Some(vv) = Self::find_in_fieldlist(k, fs) { + if vv.is_tuple() { + stack.push_back(vv.clone()); + continue; + } + if it.peek().is_some() { + return Err(Box::new(BuildError::NoSuchSymbol( + format!("Unable to match selector path {:?}", sl)))); + } else { + return Ok(vv.clone()); + } + } else { + // TODO(jwall): A better error for this would be nice. + return Err(Box::new(BuildError::NoSuchSymbol( + format!("Unable to match selector path {:?}", sl)))); + } + }; + } + return Err(Box::new(BuildError::TypeFail( + format!("{} is not a Tuple", sl[0])))); + } + return Err(Box::new(BuildError::NoSuchSymbol( + format!("Unable to find Symbol {}", sl[0])))); + } + return Err(Box::new(BuildError::NoSuchSymbol( + "Attempted to lookup an empty selector".to_string()))); + } + + // 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> { match expr { Expression::Simple(val) => { - Ok(Val::from(val)) + self.from(val) }, Expression::Add(v, expr) => { - Err(Box::new( - BuildError::TODO( - "TODO(jwall): Unimplemented Expression".to_string()))) + let expr_result = try!(self.eval_expr(*expr)); + let v = try!(self.from(*v)); + match *v { + Val::Int(i) => { + eval_binary_expr!(&Val::Int(ii), expr_result, + Val::Int(i + ii), "Integer") + }, + Val::Float(f) => { + eval_binary_expr!(&Val::Float(ff), expr_result, + Val::Float(f + ff), "Float") + }, + Val::String(ref s) => { + match expr_result.as_ref() { + &Val::String(ref ss) => { + return Ok(Rc::new( + Val::String([s.to_string(), ss.clone()].concat()))) + }, + val => { + return Err(Box::new( + BuildError::TypeFail( + format!("Expected String but got {:?}", val)))) + } + } + }, + ref expr => { + return Err(Box::new( + BuildError::Unsupported( + format!("{} does not support the '+' operation", expr.type_name())))) + } + } }, Expression::Sub(v, expr) => { - Err(Box::new( - BuildError::TODO( - "TODO(jwall): Unimplemented Expression".to_string()))) + let expr_result = try!(self.eval_expr(*expr)); + let v = try!(self.from(*v)); + match *v { + Val::Int(i) => { + eval_binary_expr!(&Val::Int(ii), expr_result, + Val::Int(i - ii), "Integer") + }, + Val::Float(f) => { + eval_binary_expr!(&Val::Float(ff), expr_result, + Val::Float(f - ff), "Float") + }, + ref expr => { + return Err(Box::new( + BuildError::Unsupported( + format!("{} does not support the '-' operation", expr.type_name())))) + } + } }, Expression::Mul(v, expr) => { - Err(Box::new( - BuildError::TODO( - "TODO(jwall): Unimplemented Expression".to_string()))) + let expr_result = try!(self.eval_expr(*expr)); + let v = try!(self.from(*v)); + match *v { + Val::Int(i) => { + eval_binary_expr!(&Val::Int(ii), expr_result, + Val::Int(i * ii), "Integer") + }, + Val::Float(f) => { + eval_binary_expr!(&Val::Float(ff), expr_result, + Val::Float(f * ff), "Float") + }, + ref expr => { + return Err(Box::new( + BuildError::Unsupported( + format!("{} does not support the '*' operation", expr.type_name())))) + } + } }, Expression::Div(v, expr) => { - Err(Box::new( - BuildError::TODO( - "TODO(jwall): Unimplemented Expression".to_string()))) + let expr_result = try!(self.eval_expr(*expr)); + let v = try!(self.from(*v)); + match *v { + Val::Int(i) => { + eval_binary_expr!(&Val::Int(ii), expr_result, + Val::Int(i / ii), "Integer") + }, + Val::Float(f) => { + eval_binary_expr!(&Val::Float(ff), expr_result, + Val::Float(f / ff), "Float") + }, + ref expr => { + return Err(Box::new( + BuildError::Unsupported( + format!("{} does not support the '*' operation", expr.type_name())))) + } + } }, - Expression::Copy(sel, fields) => { + 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(); + // 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) { + v.insert(val.clone()); + } else { + // TODO(jwall): Is this an error? + return Err(Box::new( + BuildError::TypeFail( + format!("Duplicate field: {} in tuple", *key)))); + } + } + for (key, val) in fields.drain(0..) { + let expr_result = try!(self.eval_expr(val)); + match m.entry(key) { + Entry::Vacant(mut v) => { + v.insert(expr_result); + }, + Entry::Occupied(mut v) => { + // Ensure that the new type matches the old type. + // TODO(jwall): This copy is ugly but I don't think it's possible + // to both compare and replace this at the same time. + let src_val = v.get().clone(); + if src_val.type_equal(&expr_result) { + v.insert(expr_result); + } else { + return Err(Box::new( + BuildError::TypeFail( + format!("Expected type {} for field {} but got {}", + src_val.type_name(), key, expr_result.type_name())))); + } + }, + }; + } + let mut new_fields: Vec<(&str, Rc)> = m.drain().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)); + return Ok(Rc::new(Val::Tuple(new_fields))); + } Err(Box::new( - BuildError::TODO( - "TODO(jwall): Unimplemented Expression".to_string()))) - }, - Expression::Selector(sel) => { - Err(Box::new( - BuildError::TODO( - "TODO(jwall): Unimplemented Expression".to_string()))) + BuildError::TypeFail( + format!("Expected Tuple got {}", v)))) }, Expression::Grouped(expr) => { - Err(Box::new( - BuildError::TODO( - "TODO(jwall): Unimplemented Expression".to_string()))) + return self.eval_expr(*expr); }, Expression::Call{lambda: sel, arglist: args} => { Err(Box::new( @@ -165,3 +437,246 @@ impl<'a> Builder<'a> { Ok(()) } } + +#[cfg(test)] +mod test { + use super::{Builder,Val}; + use parse::{Expression, Value}; + use std::rc::Rc; + + fn test_expr_to_val(mut cases: Vec<(Expression,Val)>, b: Builder) { + for tpl in cases.drain(0..) { + assert_eq!(b.eval_expr(tpl.0).unwrap(), Rc::new(tpl.1)); + } + } + + #[test] + fn test_eval_div_expr() { + let mut b = Builder::new(); + test_expr_to_val(vec![ + (Expression::Div(Box::new(Value::Int(2)), Box::new(Expression::Simple(Value::Int(2)))), + Val::Int(1)), + (Expression::Div(Box::new(Value::Float(2.0)), Box::new(Expression::Simple(Value::Float(2.0)))), + Val::Float(1.0)), + ], b); + } + + #[test] + #[should_panic(expected = "Expected Float")] + fn test_eval_div_expr_fail() { + let mut b = Builder::new(); + test_expr_to_val(vec![ + (Expression::Div(Box::new(Value::Float(2.0)), Box::new(Expression::Simple(Value::Int(2)))), + Val::Float(1.0)), + ], b); + } + + #[test] + fn test_eval_mul_expr() { + let mut b = Builder::new(); + test_expr_to_val(vec![ + (Expression::Mul(Box::new(Value::Int(2)), Box::new(Expression::Simple(Value::Int(2)))), + Val::Int(4)), + (Expression::Mul(Box::new(Value::Float(2.0)), Box::new(Expression::Simple(Value::Float(2.0)))), + Val::Float(4.0)), + ], b); + } + + #[test] + #[should_panic(expected = "Expected Float")] + 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)))), + Val::Float(1.0)), + ], b); + } + + #[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)))), + Val::Int(1)), + (Expression::Sub(Box::new(Value::Float(2.0)), Box::new(Expression::Simple(Value::Float(1.0)))), + Val::Float(1.0)), + ], b); + } + + #[test] + #[should_panic(expected = "Expected Float")] + 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)))), + Val::Float(1.0)), + ], b); + } + + #[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)))), + Val::Int(2)), + (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")))), + Val::String("foobar".to_string())), + ], b); + } + + #[test] + #[should_panic(expected = "Expected Float")] + 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)))), + Val::Float(1.0)), + ], b); + } + + #[test] + fn test_eval_simple_expr() { + 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())), + ], 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))); + test_expr_to_val(vec![ + (Expression::Simple(Value::Symbol("var1")), 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()); + } + + #[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( + vec![ + ("lvl2", 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))) + ]))); + test_expr_to_val(vec![ + (Expression::Simple(Value::Selector(vec!["var1"])), Val::Tuple( + vec![ + ("lvl1", Rc::new(Val::Tuple( + vec![ + ("lvl2", Rc::new(Val::Int(3))), + ] + ))), + ] + )), + (Expression::Simple(Value::Selector(vec!["var1","lvl1"])), Val::Tuple( + vec![ + ("lvl2", 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)), + ], b); + } + + #[test] + #[should_panic(expected = "Unable to find Symbol tpl1")] + fn test_expr_copy_no_such_tuple() { + let mut b = Builder::new(); + test_expr_to_val(vec![ + (Expression::Copy(vec!["tpl1"], Vec::new()), + Val::Tuple(Vec::new())), + ], b); + } + + #[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))); + test_expr_to_val(vec![ + (Expression::Copy(vec!["tpl1"], Vec::new()), + Val::Tuple(Vec::new())), + ], b); + } + + #[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))), + ]))); + test_expr_to_val(vec![ + (Expression::Copy(vec!["tpl1"], + vec![("fld1", Expression::Simple(Value::String("2")))]), + Val::Tuple( + vec![ + ("fld1", Rc::new(Val::String("2".to_string()))), + ], + )), + ], b); + } + + // TODO(jwall): What about the duplicate field error? + + #[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))), + ]))); + test_expr_to_val(vec![ + (Expression::Copy(vec!["tpl1"], + vec![("fld2", Expression::Simple(Value::String("2")))]), + // 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()))), + ], + )), + // Overwrite a field in the copy + (Expression::Copy(vec!["tpl1"], + vec![ + ("fld1", Expression::Simple(Value::Int(3))), + ("fld2", Expression::Simple(Value::String("2"))), + ]), + Val::Tuple( + vec![ + ("fld1", Rc::new(Val::Int(3))), + ("fld2", Rc::new(Val::String("2".to_string()))), + ], + )), + // The source tuple is still unmodified. + (Expression::Simple(Value::Selector(vec!["tpl1"])), + Val::Tuple( + vec![ + ("fld1", Rc::new(Val::Int(1))), + ], + )), + ], b); + } +} diff --git a/src/parse.rs b/src/parse.rs index 58437c5..79d69da 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -8,12 +8,11 @@ quick_error! { } } -use std::collections::HashMap; use std::str::FromStr; use std::str::from_utf8; use std::error::Error; -use nom::{alpha, is_alphanumeric, digit, IResult}; +use nom::{alpha, is_alphanumeric, digit}; type ParseResult = Result>; @@ -21,17 +20,33 @@ pub type FieldList<'a> = Vec<(&'a str, Expression<'a>)>; // str is expected to b pub type SelectorList<'a> = Vec<&'a str>; // str is expected to always be a symbol. /// Value represents a Value in the UCG parsed AST. -#[derive(Debug,PartialEq)] +#[derive(Debug,PartialEq,Clone)] pub enum Value<'a> { + // Constant Values Int(i64), Float(f64), String(&'a str), Symbol(&'a str), + // Complex Values Tuple(FieldList<'a>), + Selector(SelectorList<'a>), +} + +impl<'a> Value<'a> { + pub fn type_name(&self) -> String { + match self { + &Value::Int(_) => "Integer".to_string(), + &Value::Float(_) => "Float".to_string(), + &Value::String(_) => "String".to_string(), + &Value::Symbol(_) => "Symbol".to_string(), + &Value::Tuple(_) => "Tuple".to_string(), + &Value::Selector(_) => "Selector".to_string(), + } + } } /// Expression encodes an expression. Expressions compute a value from operands. -#[derive(Debug,PartialEq)] +#[derive(Debug,PartialEq,Clone)] pub enum Expression<'a> { // Base Expression Simple(Value<'a>), @@ -44,7 +59,6 @@ pub enum Expression<'a> { // Complex Expressions Copy(SelectorList<'a>, FieldList<'a>), - Selector(SelectorList<'a>), Grouped(Box>), Call { @@ -83,7 +97,6 @@ pub enum Statement<'a> { // sentinels and punctuation named!(doublequote, tag!("\"")); -named!(singlequote, tag!("'")); named!(comma, tag!(",")); named!(lbrace, tag!("{")); named!(rbrace, tag!("}")); @@ -95,7 +108,6 @@ named!(minus, tag!("-")); named!(mul, tag!("*")); named!(div, tag!("/")); named!(equal, tag!("=")); -named!(slashes, tag!("//")); named!(semicolon, tag!(";")); named!(fatcomma, tag!("=>")); @@ -194,20 +206,6 @@ named!(number, ) ); -#[test] -fn test_number_parsing() { - assert!(number(&b"."[..]).is_err() ); - assert!(number(&b". "[..]).is_err() ); - assert_eq!(number(&b"1.0"[..]), - IResult::Done(&b""[..], Value::Float(1.0)) ); - assert_eq!(number(&b"1."[..]), - IResult::Done(&b""[..], Value::Float(1.0)) ); - assert_eq!(number(&b"1"[..]), - IResult::Done(&b""[..], Value::Int(1)) ); - assert_eq!(number(&b".1"[..]), - IResult::Done(&b""[..], Value::Float(0.1)) ); -} - named!(value, alt!(number | quoted_value | symbol | tuple)); named!( @@ -221,21 +219,6 @@ named!( ) ); -#[test] -fn test_field_value_parse() { - assert!(field_value(&b"foo"[..]).is_incomplete() ); - assert!(field_value(&b"foo ="[..]).is_incomplete() ); - - assert_eq!(field_value(&b"foo = 1"[..]), - IResult::Done(&b""[..], ("foo", Expression::Simple(Value::Int(1)))) ); - assert_eq!(field_value(&b"foo = \"1\""[..]), - IResult::Done(&b""[..], ("foo", Expression::Simple(Value::String("1")))) ); - assert_eq!(field_value(&b"foo = bar"[..]), - IResult::Done(&b""[..], ("foo", Expression::Simple(Value::Symbol("bar")))) ); - assert_eq!(field_value(&b"foo = bar "[..]), - IResult::Done(&b""[..], ("foo", Expression::Simple(Value::Symbol("bar")))) ); -} - // Helper function to make the return types work for down below. fn vec_to_tuple<'a>(v: FieldList<'a>) -> ParseResult> { Ok(Value::Tuple(v)) @@ -255,43 +238,6 @@ named!( ) ); -#[test] -fn test_tuple_parse() { - assert!(tuple(&b"{"[..]).is_incomplete() ); - assert!(tuple(&b"{ foo"[..]).is_incomplete() ); - assert!(tuple(&b"{ foo ="[..]).is_incomplete() ); - assert!(tuple(&b"{ foo = 1"[..]).is_incomplete() ); - assert!(tuple(&b"{ foo = 1,"[..]).is_err() ); - assert!(tuple(&b"{ foo = 1, bar ="[..]).is_err() ); - - assert_eq!(tuple(&b"{ }"[..]), - IResult::Done(&b""[..], - Value::Tuple( - vec![]))); - - assert_eq!(tuple(&b"{ foo = 1 }"[..]), - IResult::Done(&b""[..], - Value::Tuple( - vec![ - ("foo", 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"))) - ]))); - 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()))) - ]))); -} - // keywords named!(let_word, tag!("let")); named!(select_word, tag!("select")); @@ -385,32 +331,6 @@ named!(grouped_expression, ) ); -#[test] -fn test_grouped_expression_parse() { - assert!(grouped_expression(&b"foo"[..]).is_err() ); - assert!(grouped_expression(&b"(foo"[..]).is_incomplete() ); - assert_eq!(grouped_expression(&b"(foo)"[..]), - IResult::Done(&b""[..], - Expression::Grouped( - Box::new( - Expression::Simple( - Value::Symbol("foo"))))) - ); - assert_eq!(grouped_expression(&b"(1 + 1)"[..]), - IResult::Done(&b""[..], - Expression::Grouped( - Box::new( - Expression::Add( - Box::new(Value::Int(1)), - Box::new(Expression::Simple( - Value::Int(1))) - ) - ) - ) - ) - ); -} - named!(selector_list, separated_nonempty_list!(dot, field)); fn tuple_to_copy<'a>(t: (SelectorList<'a>, FieldList<'a>)) -> ParseResult> { @@ -430,25 +350,6 @@ named!(copy_expression, ) ); -#[test] -fn test_copy_parse() { - assert!(copy_expression(&b"{}"[..]).is_err() ); - assert!(copy_expression(&b"foo"[..]).is_incomplete() ); - assert!(copy_expression(&b"foo{"[..]).is_incomplete() ); - assert_eq!(copy_expression(&b"foo{}"[..]), - IResult::Done(&b""[..], - Expression::Copy(vec!["foo"], - Vec::new()) - ) - ); - assert_eq!(copy_expression(&b"foo{bar=1}"[..]), - IResult::Done(&b""[..], - Expression::Copy(vec!["foo"], - vec![("bar", Expression::Simple(Value::Int(1)))]) - ) - ); -} - fn tuple_to_lambda<'a>(t: (Vec>, Value<'a>)) -> ParseResult> { match t.1 { Value::Tuple(v) => { @@ -466,17 +367,6 @@ fn tuple_to_lambda<'a>(t: (Vec>, Value<'a>)) -> ParseResult >, separated_list!(ws!(comma), symbol)); -#[test] -fn test_arglist_parse() { - assert!(arglist(&b"arg"[..]).is_done()); - assert!(arglist(&b"arg1, arg2"[..]).is_done()); - assert_eq!(arglist(&b"arg1, arg2"[..]), IResult::Done(&b""[..], - vec![ - Value::Symbol("arg1"), - Value::Symbol("arg2") - ])); -} - named!(lambda_expression, map_res!( do_parse!( @@ -492,33 +382,6 @@ named!(lambda_expression, ) ); -#[test] -fn test_lambda_expression_parsing() { - assert!(lambda_expression(&b"foo"[..]).is_err() ); - assert!(lambda_expression(&b"lambda \"foo\""[..]).is_err() ); - assert!(lambda_expression(&b"lambda 1"[..]).is_err() ); - assert!(lambda_expression(&b"lambda"[..]).is_incomplete() ); - assert!(lambda_expression(&b"lambda ("[..]).is_incomplete() ); - assert!(lambda_expression(&b"lambda (arg"[..]).is_incomplete() ); - assert!(lambda_expression(&b"lambda (arg, arg2"[..]).is_incomplete() ); - assert!(lambda_expression(&b"lambda (arg1, arg2) =>"[..]).is_incomplete() ); - assert!(lambda_expression(&b"lambda (arg1, arg2) => {"[..]).is_incomplete() ); - assert!(lambda_expression(&b"lambda (arg1, arg2) => { foo"[..]).is_incomplete() ); - assert!(lambda_expression(&b"lambda (arg1, arg2) => { foo ="[..]).is_incomplete() ); - - assert_eq!(lambda_expression(&b"lambda (arg1, arg2) => {foo=1,bar=2}"[..]), - IResult::Done(&b""[..], - Expression::Lambda{ - arglist: vec![Value::Symbol("arg1"), - Value::Symbol("arg2")], - tuple: vec![("foo", Expression::Simple(Value::Int(1))), - ("bar", Expression::Simple(Value::Int(2))) - ] - } - ) - ); -} - fn tuple_to_select<'a>(t: (Expression<'a>, Expression<'a>, Value<'a>)) -> ParseResult> { match t.2 { @@ -536,8 +399,6 @@ fn tuple_to_select<'a>(t: (Expression<'a>, Expression<'a>, Value<'a>)) } } -named!(select_selector, alt!(symbol | quoted_value | number)); - named!(select_expression, map_res!( terminated!(do_parse!( @@ -551,28 +412,8 @@ named!(select_expression, ) ); -#[test] -fn test_select_parse() { - assert!(select_expression(&b"select"[..]).is_incomplete()); - assert!(select_expression(&b"select foo"[..]).is_incomplete()); - assert!(select_expression(&b"select foo, 1"[..]).is_incomplete()); - assert!(select_expression(&b"select foo, 1, {"[..]).is_incomplete()); - - assert_eq!(select_expression(&b"select foo, 1, { foo = 2 };"[..]), - IResult::Done(&b""[..], - Expression::Select{ - val: Box::new(Expression::Simple(Value::Symbol("foo"))), - default: Box::new(Expression::Simple(Value::Int(1))), - tuple: vec![ - ("foo", Expression::Simple(Value::Int(2))) - ] - } - ) - ); -} - -fn tuple_to_call<'a>(t: (Expression<'a>, Vec>)) -> ParseResult> { - if let Expression::Selector(sl) = t.0 { +fn tuple_to_call<'a>(t: (Value<'a>, Vec>)) -> ParseResult> { + if let Value::Selector(sl) = t.0 { Ok(Expression::Call { lambda: sl, arglist: t.1, @@ -582,21 +423,21 @@ fn tuple_to_call<'a>(t: (Expression<'a>, Vec>)) -> ParseResult(v: SelectorList<'a>) -> ParseResult> { - Ok(Expression::Selector(v)) +fn vec_to_selector_value<'a>(v: SelectorList<'a>) -> ParseResult> { + Ok(Value::Selector(v)) } -named!(selector_expression, +named!(selector_value, map_res!( ws!(selector_list), - vec_to_selector_expression + vec_to_selector_value ) ); named!(call_expression, map_res!( do_parse!( - lambda: selector_expression >> + lambda: selector_value >> lparen >> args: ws!(separated_list!(ws!(comma), expression)) >> rparen >> @@ -606,39 +447,6 @@ named!(call_expression, ) ); -#[test] -fn test_call_parse() { - assert!(call_expression(&b"foo"[..]).is_incomplete() ); - assert!(call_expression(&b"foo ("[..]).is_incomplete() ); - assert!(call_expression(&b"foo (1"[..]).is_incomplete() ); - assert!(call_expression(&b"foo (1,"[..]).is_err() ); - assert!(call_expression(&b"foo (1,2"[..]).is_incomplete() ); - - assert_eq!(call_expression(&b"foo (1, \"foo\")"[..]), - IResult::Done(&b""[..], - Expression::Call{ - lambda: vec!["foo"], - arglist: vec![ - Expression::Simple(Value::Int(1)), - Expression::Simple(Value::String("foo")), - ], - } - ) - ); - - assert_eq!(call_expression(&b"foo.bar (1, \"foo\")"[..]), - IResult::Done(&b""[..], - Expression::Call{ - lambda: vec!["foo","bar"], - arglist: vec![ - Expression::Simple(Value::Int(1)), - Expression::Simple(Value::String("foo")), - ], - } - ) - ); -} - // NOTE(jwall): HERE THERE BE DRAGONS. The order for these matters // alot. We need to process alternatives in order of decreasing // specificity. Unfortunately this means we are required to go in a @@ -664,92 +472,6 @@ named!(expression, ) ); -#[test] -fn test_expression_parse() { - assert_eq!(expression(&b"1"[..]), - IResult::Done(&b""[..], Expression::Simple(Value::Int(1)))); - assert_eq!(expression(&b"1 + 1"[..]), - IResult::Done(&b""[..], - Expression::Add(Box::new(Value::Int(1)), - Box::new(Expression::Simple(Value::Int(1)))))); - assert_eq!(expression(&b"1 - 1"[..]), - IResult::Done(&b""[..], - Expression::Sub(Box::new(Value::Int(1)), - Box::new(Expression::Simple(Value::Int(1)))))); - assert_eq!(expression(&b"1 * 1"[..]), - IResult::Done(&b""[..], - Expression::Mul(Box::new(Value::Int(1)), - Box::new(Expression::Simple(Value::Int(1)))))); - assert_eq!(expression(&b"1 / 1"[..]), - IResult::Done(&b""[..], - Expression::Div(Box::new(Value::Int(1)), - Box::new(Expression::Simple(Value::Int(1)))))); - - assert_eq!(expression(&b"1+1"[..]), - IResult::Done(&b""[..], - Expression::Add(Box::new(Value::Int(1)), - Box::new(Expression::Simple(Value::Int(1)))))); - assert_eq!(expression(&b"1-1"[..]), - IResult::Done(&b""[..], - Expression::Sub(Box::new(Value::Int(1)), - Box::new(Expression::Simple(Value::Int(1)))))); - assert_eq!(expression(&b"1*1"[..]), - IResult::Done(&b""[..], - Expression::Mul(Box::new(Value::Int(1)), - Box::new(Expression::Simple(Value::Int(1)))))); - assert_eq!(expression(&b"1/1"[..]), - IResult::Done(&b""[..], - Expression::Div(Box::new(Value::Int(1)), - Box::new(Expression::Simple(Value::Int(1)))))); - assert_eq!(expression(&b"lambda (arg1, arg2) => { foo = arg1 }"[..]), - IResult::Done(&b""[..], - Expression::Lambda{ - arglist: vec![ - Value::Symbol("arg1"), - Value::Symbol("arg2") - ], - tuple: vec![ - ("foo", Expression::Simple(Value::Symbol("arg1"))), - ], - } - ) - ); - assert_eq!(expression(&b"select foo, 1, { foo = 2 };"[..]), - IResult::Done(&b""[..], - Expression::Select{ - val: Box::new(Expression::Simple(Value::Symbol("foo"))), - default: Box::new(Expression::Simple(Value::Int(1))), - tuple: vec![ - ("foo", Expression::Simple(Value::Int(2))) - ] - } - ) - ); - assert_eq!(expression(&b"foo.bar (1, \"foo\")"[..]), - IResult::Done(&b""[..], - Expression::Call{ - lambda: vec!["foo","bar"], - arglist: vec![ - Expression::Simple(Value::Int(1)), - Expression::Simple(Value::String("foo")), - ], - } - ) - ); - assert_eq!(expression(&b"(1 + 1)"[..]), - IResult::Done(&b""[..], - Expression::Grouped( - Box::new( - Expression::Add( - Box::new(Value::Int(1)), - Box::new(Expression::Simple(Value::Int(1))) - ) - ) - ) - ) - ); -} - fn expression_to_statement(v: Expression) -> ParseResult { Ok(Statement::Expression(v)) } @@ -761,47 +483,6 @@ named!(expression_statement, ) ); -#[test] -fn test_expression_statement_parse() { - assert!(expression_statement(&b"foo"[..]).is_incomplete() ); - assert_eq!(expression_statement(&b"1.0;"[..]), - IResult::Done(&b""[..], - Statement::Expression( - Expression::Simple(Value::Float(1.0))))); - assert_eq!(expression_statement(&b"1.0 ;"[..]), - IResult::Done(&b""[..], - Statement::Expression( - Expression::Simple(Value::Float(1.0))))); - assert_eq!(expression_statement(&b" 1.0;"[..]), - IResult::Done(&b""[..], - Statement::Expression( - Expression::Simple(Value::Float(1.0))))); - assert_eq!(expression_statement(&b"foo;"[..]), - IResult::Done(&b""[..], - Statement::Expression( - Expression::Simple(Value::Symbol("foo"))))); - assert_eq!(expression_statement(&b"foo ;"[..]), - IResult::Done(&b""[..], - Statement::Expression( - Expression::Simple(Value::Symbol("foo"))))); - assert_eq!(expression_statement(&b" foo;"[..]), - IResult::Done(&b""[..], - Statement::Expression( - Expression::Simple(Value::Symbol("foo"))))); - assert_eq!(expression_statement(&b"\"foo\";"[..]), - IResult::Done(&b""[..], - Statement::Expression( - Expression::Simple(Value::String("foo"))))); - assert_eq!(expression_statement(&b"\"foo\" ;"[..]), - IResult::Done(&b""[..], - Statement::Expression( - Expression::Simple(Value::String("foo"))))); - assert_eq!(expression_statement(&b" \"foo\";"[..]), - IResult::Done(&b""[..], - Statement::Expression( - Expression::Simple(Value::String("foo"))))); -} - fn tuple_to_let<'a>(t: (&'a str, Expression<'a>)) -> ParseResult> { Ok(Statement::Let { name: t.0, @@ -822,31 +503,6 @@ named!(let_statement, ) ); -#[test] -fn test_let_statement_parse() { - assert!(let_statement(&b"foo"[..]).is_err() ); - assert!(let_statement(&b"let \"foo\""[..]).is_err() ); - assert!(let_statement(&b"let 1"[..]).is_err() ); - assert!(let_statement(&b"let"[..]).is_incomplete() ); - assert!(let_statement(&b"let foo"[..]).is_incomplete() ); - assert!(let_statement(&b"let foo ="[..]).is_incomplete() ); - assert!(let_statement(&b"let foo = "[..]).is_incomplete() ); - assert!(let_statement(&b"let foo = 1"[..]).is_incomplete() ); - - assert_eq!(let_statement(&b"let foo = 1.0 ;"[..]), - IResult::Done(&b""[..], - Statement::Let{name: "foo", - value: Expression::Simple(Value::Float(1.0))})); - assert_eq!(let_statement(&b"let foo= 1.0;"[..]), - IResult::Done(&b""[..], - Statement::Let{name: "foo", - value: Expression::Simple(Value::Float(1.0))})); - assert_eq!(let_statement(&b"let foo =1.0;"[..]), - IResult::Done(&b""[..], - Statement::Let{name: "foo", - value: Expression::Simple(Value::Float(1.0))})); -} - fn tuple_to_import<'a>(t: (&'a str, &'a str)) -> ParseResult> { Ok(Statement::Import { name: t.0, @@ -867,23 +523,6 @@ named!(import_statement, ) ); -#[test] -fn test_import_parse() { - assert!(import_statement(&b"import"[..]).is_incomplete()); - assert!(import_statement(&b"import \"foo\""[..]).is_incomplete()); - assert!(import_statement(&b"import \"foo\" as"[..]).is_incomplete()); - assert!(import_statement(&b"import \"foo\" as foo"[..]).is_incomplete()); - - assert_eq!(import_statement(&b"import \"foo\" as foo;"[..]), - IResult::Done(&b""[..], - Statement::Import{ - path: "foo", - name: "foo" - } - ) - ); -} - named!(statement, alt_complete!( import_statement | @@ -892,9 +531,22 @@ named!(statement, ) ); -#[test] -fn test_statement_parse() { - assert_eq!(statement(&b"import \"foo\" as foo;"[..]), +named!(pub parse >, many1!(ws!(statement))); + +// TODO(jwall): Full Statement parsing tests. + +#[cfg(test)] +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::{arglist, lambda_expression, select_expression, call_expression, expression}; + use super::{expression_statement, let_statement, import_statement, statement}; + use nom::IResult; + + #[test] + fn test_statement_parse() { + assert_eq!(statement(&b"import \"foo\" as foo;"[..]), IResult::Done(&b""[..], Statement::Import{ path: "foo", @@ -902,37 +554,404 @@ fn test_statement_parse() { } ) ); - assert!(statement(&b"import foo"[..]).is_err() ); + assert!(statement(&b"import foo"[..]).is_err() ); - assert_eq!(statement(&b"let foo = 1.0 ;"[..]), + assert_eq!(statement(&b"let foo = 1.0 ;"[..]), IResult::Done(&b""[..], Statement::Let{name: "foo", value: Expression::Simple(Value::Float(1.0))})); - assert_eq!(statement(&b"1.0;"[..]), + assert_eq!(statement(&b"1.0;"[..]), IResult::Done(&b""[..], Statement::Expression( Expression::Simple(Value::Float(1.0))))); -} + } -named!(pub parse >, many1!(ws!(statement))); + #[test] + fn test_import_parse() { + assert!(import_statement(&b"import"[..]).is_incomplete()); + assert!(import_statement(&b"import \"foo\""[..]).is_incomplete()); + assert!(import_statement(&b"import \"foo\" as"[..]).is_incomplete()); + assert!(import_statement(&b"import \"foo\" as foo"[..]).is_incomplete()); -// TODO(jwall): Full Statement parsing tests. + assert_eq!(import_statement(&b"import \"foo\" as foo;"[..]), + IResult::Done(&b""[..], + Statement::Import{ + path: "foo", + name: "foo" + } + ) + ); + } -#[test] -fn test_parse() { - let bad_input = &b"import mylib as lib;"[..]; - let bad_result = parse(bad_input); - assert!(bad_result.is_err() ); + #[test] + fn test_let_statement_parse() { + assert!(let_statement(&b"foo"[..]).is_err() ); + assert!(let_statement(&b"let \"foo\""[..]).is_err() ); + assert!(let_statement(&b"let 1"[..]).is_err() ); + assert!(let_statement(&b"let"[..]).is_incomplete() ); + assert!(let_statement(&b"let foo"[..]).is_incomplete() ); + assert!(let_statement(&b"let foo ="[..]).is_incomplete() ); + assert!(let_statement(&b"let foo = "[..]).is_incomplete() ); + assert!(let_statement(&b"let foo = 1"[..]).is_incomplete() ); - // Valid parsing tree - let input = &b"import \"mylib\" as lib;\ + assert_eq!(let_statement(&b"let foo = 1.0 ;"[..]), + IResult::Done(&b""[..], + Statement::Let{name: "foo", + value: Expression::Simple(Value::Float(1.0))})); + assert_eq!(let_statement(&b"let foo= 1.0;"[..]), + IResult::Done(&b""[..], + Statement::Let{name: "foo", + value: Expression::Simple(Value::Float(1.0))})); + assert_eq!(let_statement(&b"let foo =1.0;"[..]), + IResult::Done(&b""[..], + Statement::Let{name: "foo", + value: Expression::Simple(Value::Float(1.0))})); + } + + #[test] + fn test_expression_statement_parse() { + assert!(expression_statement(&b"foo"[..]).is_incomplete() ); + assert_eq!(expression_statement(&b"1.0;"[..]), + IResult::Done(&b""[..], + Statement::Expression( + Expression::Simple(Value::Float(1.0))))); + assert_eq!(expression_statement(&b"1.0 ;"[..]), + IResult::Done(&b""[..], + Statement::Expression( + Expression::Simple(Value::Float(1.0))))); + assert_eq!(expression_statement(&b" 1.0;"[..]), + IResult::Done(&b""[..], + Statement::Expression( + Expression::Simple(Value::Float(1.0))))); + assert_eq!(expression_statement(&b"foo;"[..]), + IResult::Done(&b""[..], + Statement::Expression( + Expression::Simple(Value::Symbol("foo"))))); + assert_eq!(expression_statement(&b"foo ;"[..]), + IResult::Done(&b""[..], + Statement::Expression( + Expression::Simple(Value::Symbol("foo"))))); + assert_eq!(expression_statement(&b" foo;"[..]), + IResult::Done(&b""[..], + Statement::Expression( + Expression::Simple(Value::Symbol("foo"))))); + assert_eq!(expression_statement(&b"\"foo\";"[..]), + IResult::Done(&b""[..], + Statement::Expression( + Expression::Simple(Value::String("foo"))))); + assert_eq!(expression_statement(&b"\"foo\" ;"[..]), + IResult::Done(&b""[..], + Statement::Expression( + Expression::Simple(Value::String("foo"))))); + assert_eq!(expression_statement(&b" \"foo\";"[..]), + IResult::Done(&b""[..], + Statement::Expression( + Expression::Simple(Value::String("foo"))))); + } + + #[test] + fn test_expression_parse() { + assert_eq!(expression(&b"1"[..]), + IResult::Done(&b""[..], Expression::Simple(Value::Int(1)))); + assert_eq!(expression(&b"1 + 1"[..]), + IResult::Done(&b""[..], + Expression::Add(Box::new(Value::Int(1)), + Box::new(Expression::Simple(Value::Int(1)))))); + assert_eq!(expression(&b"1 - 1"[..]), + IResult::Done(&b""[..], + Expression::Sub(Box::new(Value::Int(1)), + Box::new(Expression::Simple(Value::Int(1)))))); + assert_eq!(expression(&b"1 * 1"[..]), + IResult::Done(&b""[..], + Expression::Mul(Box::new(Value::Int(1)), + Box::new(Expression::Simple(Value::Int(1)))))); + assert_eq!(expression(&b"1 / 1"[..]), + IResult::Done(&b""[..], + Expression::Div(Box::new(Value::Int(1)), + Box::new(Expression::Simple(Value::Int(1)))))); + + assert_eq!(expression(&b"1+1"[..]), + IResult::Done(&b""[..], + Expression::Add(Box::new(Value::Int(1)), + Box::new(Expression::Simple(Value::Int(1)))))); + assert_eq!(expression(&b"1-1"[..]), + IResult::Done(&b""[..], + Expression::Sub(Box::new(Value::Int(1)), + Box::new(Expression::Simple(Value::Int(1)))))); + assert_eq!(expression(&b"1*1"[..]), + IResult::Done(&b""[..], + Expression::Mul(Box::new(Value::Int(1)), + Box::new(Expression::Simple(Value::Int(1)))))); + assert_eq!(expression(&b"1/1"[..]), + IResult::Done(&b""[..], + Expression::Div(Box::new(Value::Int(1)), + Box::new(Expression::Simple(Value::Int(1)))))); + assert_eq!(expression(&b"lambda (arg1, arg2) => { foo = arg1 }"[..]), + IResult::Done(&b""[..], + Expression::Lambda{ + arglist: vec![ + Value::Symbol("arg1"), + Value::Symbol("arg2") + ], + tuple: vec![ + ("foo", Expression::Simple(Value::Symbol("arg1"))), + ], + } + ) + ); + assert_eq!(expression(&b"select foo, 1, { foo = 2 };"[..]), + IResult::Done(&b""[..], + Expression::Select{ + val: Box::new(Expression::Simple(Value::Symbol("foo"))), + default: Box::new(Expression::Simple(Value::Int(1))), + tuple: vec![ + ("foo", Expression::Simple(Value::Int(2))) + ] + } + ) + ); + assert_eq!(expression(&b"foo.bar (1, \"foo\")"[..]), + IResult::Done(&b""[..], + Expression::Call{ + lambda: vec!["foo","bar"], + arglist: vec![ + Expression::Simple(Value::Int(1)), + Expression::Simple(Value::String("foo")), + ], + } + ) + ); + assert_eq!(expression(&b"(1 + 1)"[..]), + IResult::Done(&b""[..], + Expression::Grouped( + Box::new( + Expression::Add( + Box::new(Value::Int(1)), + Box::new(Expression::Simple(Value::Int(1))) + ) + ) + ) + ) + ); + } + + #[test] + fn test_call_parse() { + assert!(call_expression(&b"foo"[..]).is_incomplete() ); + assert!(call_expression(&b"foo ("[..]).is_incomplete() ); + assert!(call_expression(&b"foo (1"[..]).is_incomplete() ); + assert!(call_expression(&b"foo (1,"[..]).is_err() ); + assert!(call_expression(&b"foo (1,2"[..]).is_incomplete() ); + + assert_eq!(call_expression(&b"foo (1, \"foo\")"[..]), + IResult::Done(&b""[..], + Expression::Call{ + lambda: vec!["foo"], + arglist: vec![ + Expression::Simple(Value::Int(1)), + Expression::Simple(Value::String("foo")), + ], + } + ) + ); + + assert_eq!(call_expression(&b"foo.bar (1, \"foo\")"[..]), + IResult::Done(&b""[..], + Expression::Call{ + lambda: vec!["foo","bar"], + arglist: vec![ + Expression::Simple(Value::Int(1)), + Expression::Simple(Value::String("foo")), + ], + } + ) + ); + } + + #[test] + fn test_select_parse() { + assert!(select_expression(&b"select"[..]).is_incomplete()); + assert!(select_expression(&b"select foo"[..]).is_incomplete()); + assert!(select_expression(&b"select foo, 1"[..]).is_incomplete()); + assert!(select_expression(&b"select foo, 1, {"[..]).is_incomplete()); + + assert_eq!(select_expression(&b"select foo, 1, { foo = 2 };"[..]), + IResult::Done(&b""[..], + Expression::Select{ + val: Box::new(Expression::Simple(Value::Symbol("foo"))), + default: Box::new(Expression::Simple(Value::Int(1))), + tuple: vec![ + ("foo", Expression::Simple(Value::Int(2))) + ] + } + ) + ); + } + + #[test] + fn test_lambda_expression_parsing() { + assert!(lambda_expression(&b"foo"[..]).is_err() ); + assert!(lambda_expression(&b"lambda \"foo\""[..]).is_err() ); + assert!(lambda_expression(&b"lambda 1"[..]).is_err() ); + assert!(lambda_expression(&b"lambda"[..]).is_incomplete() ); + assert!(lambda_expression(&b"lambda ("[..]).is_incomplete() ); + assert!(lambda_expression(&b"lambda (arg"[..]).is_incomplete() ); + assert!(lambda_expression(&b"lambda (arg, arg2"[..]).is_incomplete() ); + assert!(lambda_expression(&b"lambda (arg1, arg2) =>"[..]).is_incomplete() ); + assert!(lambda_expression(&b"lambda (arg1, arg2) => {"[..]).is_incomplete() ); + assert!(lambda_expression(&b"lambda (arg1, arg2) => { foo"[..]).is_incomplete() ); + assert!(lambda_expression(&b"lambda (arg1, arg2) => { foo ="[..]).is_incomplete() ); + + assert_eq!(lambda_expression(&b"lambda (arg1, arg2) => {foo=1,bar=2}"[..]), + IResult::Done(&b""[..], + Expression::Lambda{ + arglist: vec![Value::Symbol("arg1"), + Value::Symbol("arg2")], + tuple: vec![("foo", Expression::Simple(Value::Int(1))), + ("bar", Expression::Simple(Value::Int(2))) + ] + } + ) + ); + } + + #[test] + fn test_arglist_parse() { + assert!(arglist(&b"arg"[..]).is_done()); + assert!(arglist(&b"arg1, arg2"[..]).is_done()); + assert_eq!(arglist(&b"arg1, arg2"[..]), IResult::Done(&b""[..], + vec![ + Value::Symbol("arg1"), + Value::Symbol("arg2") + ])); + } + + #[test] + fn test_copy_parse() { + assert!(copy_expression(&b"{}"[..]).is_err() ); + assert!(copy_expression(&b"foo"[..]).is_incomplete() ); + assert!(copy_expression(&b"foo{"[..]).is_incomplete() ); + assert_eq!(copy_expression(&b"foo{}"[..]), + IResult::Done(&b""[..], + Expression::Copy(vec!["foo"], + Vec::new()) + ) + ); + assert_eq!(copy_expression(&b"foo{bar=1}"[..]), + IResult::Done(&b""[..], + Expression::Copy(vec!["foo"], + vec![("bar", Expression::Simple(Value::Int(1)))]) + ) + ); + } + + #[test] + fn test_grouped_expression_parse() { + assert!(grouped_expression(&b"foo"[..]).is_err() ); + assert!(grouped_expression(&b"(foo"[..]).is_incomplete() ); + assert_eq!(grouped_expression(&b"(foo)"[..]), + IResult::Done(&b""[..], + Expression::Grouped( + Box::new( + Expression::Simple( + Value::Symbol("foo"))))) + ); + assert_eq!(grouped_expression(&b"(1 + 1)"[..]), + IResult::Done(&b""[..], + Expression::Grouped( + Box::new( + Expression::Add( + Box::new(Value::Int(1)), + Box::new(Expression::Simple( + Value::Int(1))) + ) + ) + ) + ) + ); + } + + #[test] + fn test_tuple_parse() { + assert!(tuple(&b"{"[..]).is_incomplete() ); + assert!(tuple(&b"{ foo"[..]).is_incomplete() ); + assert!(tuple(&b"{ foo ="[..]).is_incomplete() ); + assert!(tuple(&b"{ foo = 1"[..]).is_incomplete() ); + assert!(tuple(&b"{ foo = 1,"[..]).is_err() ); + assert!(tuple(&b"{ foo = 1, bar ="[..]).is_err() ); + + assert_eq!(tuple(&b"{ }"[..]), + IResult::Done(&b""[..], + Value::Tuple( + vec![]))); + + assert_eq!(tuple(&b"{ foo = 1 }"[..]), + IResult::Done(&b""[..], + Value::Tuple( + vec![ + ("foo", 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"))) + ]))); + 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()))) + ]))); + } + + #[test] + fn test_field_value_parse() { + assert!(field_value(&b"foo"[..]).is_incomplete() ); + assert!(field_value(&b"foo ="[..]).is_incomplete() ); + + assert_eq!(field_value(&b"foo = 1"[..]), + IResult::Done(&b""[..], ("foo", Expression::Simple(Value::Int(1)))) ); + assert_eq!(field_value(&b"foo = \"1\""[..]), + IResult::Done(&b""[..], ("foo", Expression::Simple(Value::String("1")))) ); + assert_eq!(field_value(&b"foo = bar"[..]), + IResult::Done(&b""[..], ("foo", Expression::Simple(Value::Symbol("bar")))) ); + assert_eq!(field_value(&b"foo = bar "[..]), + IResult::Done(&b""[..], ("foo", Expression::Simple(Value::Symbol("bar")))) ); + } + + #[test] + fn test_number_parsing() { + assert!(number(&b"."[..]).is_err() ); + assert!(number(&b". "[..]).is_err() ); + assert_eq!(number(&b"1.0"[..]), + IResult::Done(&b""[..], Value::Float(1.0)) ); + assert_eq!(number(&b"1."[..]), + IResult::Done(&b""[..], Value::Float(1.0)) ); + assert_eq!(number(&b"1"[..]), + IResult::Done(&b""[..], Value::Int(1)) ); + assert_eq!(number(&b".1"[..]), + IResult::Done(&b""[..], Value::Float(0.1)) ); + } + + #[test] + fn test_parse() { + let bad_input = &b"import mylib as lib;"[..]; + let bad_result = parse(bad_input); + assert!(bad_result.is_err() ); + + // Valid parsing tree + let input = &b"import \"mylib\" as lib;\ let foo = 1;\ 1+1;"[..]; - let result = parse(input); - assert!(result.is_done() ); - let tpl = result.unwrap(); - assert_eq!(from_utf8(tpl.0).unwrap(), ""); - assert_eq!(tpl.1, + let result = parse(input); + assert!(result.is_done() ); + let tpl = result.unwrap(); + assert_eq!(from_utf8(tpl.0).unwrap(), ""); + assert_eq!(tpl.1, vec![ Statement::Import{ path: "mylib", @@ -947,4 +966,5 @@ fn test_parse() { Box::new(Expression::Simple(Value::Int(1)))) ) ]); + } }