diff --git a/Cargo.toml b/Cargo.toml index faf9702d..8849b8c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ rustc_version = "0.1.7" [dependencies] clap = "2.19.3" -error-chain = "0.9.0" +error-chain = "0.8.1" nickel = "0.9.0" slog = "1.4.0" slog-scope = "0.2.2" diff --git a/db/Cargo.toml b/db/Cargo.toml index a6b4e26d..b0deae04 100644 --- a/db/Cargo.toml +++ b/db/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.1" workspace = ".." [dependencies] -error-chain = "0.9.0" +error-chain = "0.8.1" itertools = "0.5.9" lazy_static = "0.2.2" ordered-float = "0.4.0" diff --git a/query-algebrizer/Cargo.toml b/query-algebrizer/Cargo.toml index 71c15f50..c21bc49b 100644 --- a/query-algebrizer/Cargo.toml +++ b/query-algebrizer/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.1" workspace = ".." [dependencies] -error-chain = "0.9.0" +error-chain = "0.8.1" [dependencies.mentat_core] path = "../core" diff --git a/query-parser/Cargo.toml b/query-parser/Cargo.toml index 7668db30..7dde1314 100644 --- a/query-parser/Cargo.toml +++ b/query-parser/Cargo.toml @@ -5,7 +5,7 @@ workspace = ".." [dependencies] combine = "2.2.2" -error-chain = "0.9.0" +error-chain = "0.8.1" matches = "0.1" [dependencies.edn] diff --git a/query-parser/src/parse.rs b/query-parser/src/parse.rs index 2952afdc..3017b797 100644 --- a/query-parser/src/parse.rs +++ b/query-parser/src/parse.rs @@ -353,15 +353,15 @@ enum FindQueryPart { } def_parser!(Find, vars, BTreeSet, { - vector().of_exactly(many(Query::variable()).map(|vars: Vec| { + vector().of_exactly(many(Query::variable()).and_then(|vars: Vec| { let given = vars.len(); let set: BTreeSet = vars.into_iter().collect(); if given != set.len() { // TODO: find out what the variable is! - // TODO: figure out how to use `and_then` to return an error here. - panic!(Error::from_kind(ErrorKind::DuplicateVariableError)); + let e = Box::new(Error::from_kind(ErrorKind::DuplicateVariableError)); + Err(combine::primitives::Error::Other(e)) } else { - set + Ok(set) } })) }); @@ -549,6 +549,33 @@ mod test { vec![variable(e.clone())]); } + #[test] + fn test_repeated_vars() { + let e = edn::PlainSymbol::new("?e"); + let f = edn::PlainSymbol::new("?f"); + let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(e.clone()), + edn::Value::PlainSymbol(f.clone()),]); + assert_parses_to!(Find::vars, input, + vec![variable(e.clone()), variable(f.clone())].into_iter().collect()); + + let g = edn::PlainSymbol::new("?g"); + let input = edn::Value::Vector(vec![edn::Value::PlainSymbol(g.clone()), + edn::Value::PlainSymbol(g.clone()),]); + + let mut par = Find::vars(); + let result = par.parse(input.with_spans().into_atom_stream()) + .map(|x| x.0) + .map_err(|e| if let Some(combine::primitives::Error::Other(x)) = e.errors.into_iter().next() { + // Pattern matching on boxes is rocket science until Rust Nightly features hit + // stable. ErrorKind isn't Clone, so convert to strings. We could pattern match + // for exact comparison here. + x.downcast::().ok().map(|e| e.to_string()) + } else { + None + }); + assert_eq!(result, Err(Some("duplicates in variable list".to_string()))); + } + #[test] fn test_or() { let oj = edn::PlainSymbol::new("or"); diff --git a/query-projector/Cargo.toml b/query-projector/Cargo.toml index 9ef12ac0..0bd54f1f 100644 --- a/query-projector/Cargo.toml +++ b/query-projector/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.1" workspace = ".." [dependencies] -error-chain = "0.9.0" +error-chain = "0.8.1" [dependencies.rusqlite] version = "0.10.1" diff --git a/sql/Cargo.toml b/sql/Cargo.toml index d6e57d77..868d07e4 100644 --- a/sql/Cargo.toml +++ b/sql/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.1" workspace = ".." [dependencies] -error-chain = "0.9.0" +error-chain = "0.8.1" ordered-float = "0.4.0" [dependencies.mentat_core] diff --git a/tx-parser/Cargo.toml b/tx-parser/Cargo.toml index cb0c051d..1fc8839c 100644 --- a/tx-parser/Cargo.toml +++ b/tx-parser/Cargo.toml @@ -5,7 +5,7 @@ workspace = ".." [dependencies] combine = "2.2.2" -error-chain = "0.9.0" +error-chain = "0.8.1" [dependencies.edn] path = "../edn"