diff --git a/src/main.rs b/src/main.rs index f6b0f7dc04059d336ca641e707624d8eef27963f..bef24f5b2672c9970b8cc9652f81546f5b789252 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,11 +23,11 @@ extern crate calc; #[cfg(all(unix, not(target_os = "redox")))] extern crate users as users_unix; #[cfg(target_os = "redox")] extern crate syscall; +#[macro_use] mod types; #[macro_use] mod parser; mod builtins; mod shell; mod ascii_helpers; -mod types; use std::io::{stderr, Write, ErrorKind}; diff --git a/src/parser/pipelines.rs b/src/parser/pipelines.rs index 8c7d5249abdd7b5448d156c8f66ba28c67023950..e6d444ab9a4170ff00d555246038a7141dc9048c 100644 --- a/src/parser/pipelines.rs +++ b/src/parser/pipelines.rs @@ -304,7 +304,7 @@ mod tests { use shell::flow_control::Statement; use parser::peg::{parse, Pipeline, RedirectFrom, Redirection}; use shell::{Job, JobKind}; - use types::*; + use types::Array; #[test] fn stderr_redirection() { @@ -552,8 +552,8 @@ mod tests { if let Statement::Pipeline(pipeline) = parse("echo one && echo two") { let jobs = pipeline.jobs; assert_eq!(JobKind::And, jobs[0].kind); - assert_eq!(Array::from_vec(vec![String::from("echo"), String::from("one")]), jobs[0].args); - assert_eq!(Array::from_vec(vec![String::from("echo"), String::from("two")]), jobs[1].args); + assert_eq!(array!["echo", "one"], jobs[0].args); + assert_eq!(array!["echo", "two"], jobs[1].args); } else { assert!(false); } @@ -657,11 +657,9 @@ mod tests { let input = "cat | echo hello | cat < stuff ^>> other"; let expected = Pipeline { jobs: vec![ - Job::new(Array::from_vec(vec!["cat".into()]), - JobKind::Pipe(RedirectFrom::Stdout)), - Job::new(Array::from_vec(vec!["echo".into(), "hello".into()]), - JobKind::Pipe(RedirectFrom::Stdout)), - Job::new(Array::from_vec(vec!["cat".into()]), JobKind::Last) + Job::new(array!["cat"], JobKind::Pipe(RedirectFrom::Stdout)), + Job::new(array!["echo", "hello"], JobKind::Pipe(RedirectFrom::Stdout)), + Job::new(array!["cat"], JobKind::Last) ], stdin: Some(Redirection { from: RedirectFrom::Stdout, @@ -682,11 +680,9 @@ mod tests { let input = "cat | echo hello | cat < stuff &>> other"; let expected = Pipeline { jobs: vec![ - Job::new(Array::from_vec(vec!["cat".into()]), - JobKind::Pipe(RedirectFrom::Stdout)), - Job::new(Array::from_vec(vec!["echo".into(), "hello".into()]), - JobKind::Pipe(RedirectFrom::Stdout)), - Job::new(Array::from_vec(vec!["cat".into()]), JobKind::Last) + Job::new(array!["cat"], JobKind::Pipe(RedirectFrom::Stdout)), + Job::new(array!["echo", "hello"], JobKind::Pipe(RedirectFrom::Stdout)), + Job::new(array!["cat"], JobKind::Last) ], stdin: Some(Redirection { from: RedirectFrom::Stdout, @@ -754,7 +750,7 @@ mod tests { let input = "echo zardoz >> foo\\'bar"; let expected = Pipeline { jobs: vec![ - Job::new(Array::from_vec(vec!["echo".into(), "zardoz".into()]), JobKind::Last), + Job::new(array!["echo", "zardoz"], JobKind::Last), ], stdin: None, stdout: Some(Redirection { diff --git a/src/parser/shell_expand/mod.rs b/src/parser/shell_expand/mod.rs index c168c4878d7e24ae1c0210b15bc94d2de25fa637..aaf8687f12f47a82daf4c82bec54b916fa89866a 100644 --- a/src/parser/shell_expand/mod.rs +++ b/src/parser/shell_expand/mod.rs @@ -340,7 +340,7 @@ pub fn expand_tokens<'a>(token_buffer: &[WordToken], expand_func: &'a ExpanderFu } else { let mut output = String::new(); array_method.handle(&mut output, expand_func); - Array::from_vec(vec![output]) + array!(output) }; }, _ => () @@ -530,7 +530,7 @@ mod test { let input = "$FOO:NOT:$BAR"; let expected = "FOO:NOT:BAR"; let expanded = expand_string(input, &functions!(), false); - assert_eq!(Array::from_vec(vec![expected.to_owned()]), expanded); + assert_eq!(array![expected], expanded); } #[test] @@ -549,19 +549,19 @@ mod test { #[test] fn expand_variables_with_colons() { let expanded = expand_string("$FOO:$BAR", &functions!(), false); - assert_eq!(Array::from_vec(vec!["FOO:BAR".to_owned()]), expanded); + assert_eq!(array!["FOO:BAR"], expanded); } #[test] fn expand_multiple_variables() { let expanded = expand_string("${B}${C}...${D}", &functions!(), false); - assert_eq!(Array::from_vec(vec!["testing...1 2 3".to_owned()]), expanded); + assert_eq!(array!["testing...1 2 3"], expanded); } #[test] fn expand_variable_alongside_braces() { let line = "$A{1,2}"; - let expected = Array::from_vec(vec!["11".to_owned(), "12".to_owned()]); + let expected = array!["11", "12"]; let expanded = expand_string(line, &functions!(), false); assert_eq!(expected, expanded); } @@ -569,7 +569,7 @@ mod test { #[test] fn expand_variable_within_braces() { let line = "1{$A,2}"; - let expected = Array::from_vec(vec!["11".to_owned(), "12".to_owned()]); + let expected = array!["11", "12"]; let expanded = expand_string(line, &functions!(), false); assert_eq!(&expected, &expanded); } @@ -579,14 +579,14 @@ mod test { let base = |idx : &str| format!("[1 2 3][{}]", idx); let expander = functions!(); { - let expected = Array::from_vec(vec!["1".to_owned()]); + let expected = array!["1"]; let idxs = vec!["-3", "0", "..-2"]; for idx in idxs { assert_eq!(expected, expand_string(&base(idx), &expander, false)); } } { - let expected = Array::from_vec(vec!["2".to_owned(), "3".to_owned()]); + let expected = array!["2", "3"]; let idxs = vec!["1...2", "1...-1"]; for idx in idxs { assert_eq!(expected, expand_string(&base(idx), &expander, false)); @@ -605,24 +605,24 @@ mod test { fn embedded_array_expansion() { let line = |idx : &str| format!("[[foo bar] [baz bat] [bing crosby]][{}]", idx); let expander = functions!(); - let cases : Vec<(Vec<String>, &str)> = vec![ - (vec!["foo".into()], "0"), - (vec!["baz".into()], "2"), - (vec!["bat".into()], "-3"), - (vec!["bar".into(), "baz".into(), "bat".into()], "1...3") + let cases = vec![ + (array!["foo"], "0"), + (array!["baz"], "2"), + (array!["bat"], "-3"), + (array!["bar", "baz", "bat"], "1...3") ]; for (expected, idx) in cases { - assert_eq!(Array::from_vec(expected), expand_string(&line(idx), &expander, false)); + assert_eq!(expected, expand_string(&line(idx), &expander, false)); } } #[test] fn arith_expression() { let line = "$((A * A - (A + A)))"; - let expected = Array::from_vec(vec!["-1".to_owned()]); + let expected = array!["-1"]; assert_eq!(expected, expand_string(line, &functions!(), false)); let line = "$((3 * 10 - 27))"; - let expected = Array::from_vec(vec!["3".to_owned()]); + let expected = array!["3"]; assert_eq!(expected, expand_string(line, &functions!(), false)); } } diff --git a/src/parser/shell_expand/words.rs b/src/parser/shell_expand/words.rs index cec56c3804b9c0ccade949875cbd964915fb10d4..34ad5b4088410603386e73a47a9b1cecf32ac1a6 100644 --- a/src/parser/shell_expand/words.rs +++ b/src/parser/shell_expand/words.rs @@ -1370,7 +1370,7 @@ mod tests { pattern: Pattern::Whitespace, selection: Select::Index(Index::Forward(3)) }; - let expected = Array::from_vec(vec!["é".into()]); + let expected = array!["é"]; assert_eq!(method.handle_as_array(&expanders), expected); let method = ArrayMethod { method: "chars", @@ -1378,7 +1378,7 @@ mod tests { pattern: Pattern::Whitespace, selection: Select::Index(Index::Forward(3)) }; - let expected = Array::from_vec(vec!["e".into()]); + let expected = array!["e"]; assert_eq!(method.handle_as_array(&expanders), expected); let method = ArrayMethod { method: "bytes", @@ -1386,7 +1386,7 @@ mod tests { pattern: Pattern::Whitespace, selection: Select::Index(Index::Forward(1)) }; - let expected = Array::from_vec(vec!["111".into()]); + let expected = array!["111"]; assert_eq!(method.handle_as_array(&expanders), expected); } diff --git a/src/types.rs b/src/types.rs index e5fcf4b2390c337632cf1fa28f816e8a09544aa2..4a31477f002494a9756214b56599fee4f3e54380 100644 --- a/src/types.rs +++ b/src/types.rs @@ -7,3 +7,29 @@ pub type Identifier = SmallString; pub type Value = String; pub type VariableContext = FnvHashMap<Identifier, Value>; pub type ArrayVariableContext = FnvHashMap<Identifier, Array>; + +/// Construct a new Array containing the given arguments +/// +/// `array!` acts like the standard library's `vec!` macro, and can be thought +/// of as a shorthand for: +/// ```ignore,rust +/// Array::from_vec(vec![...]) +/// ``` +/// Additionally it will call `Into::into` on each of its members so that one +/// can pass in any type with some `To<SmallString>` implementation; they will +/// automatically be converted to owned SmallStrings. +/// ``` +/// let verbose = Array::from_vec(vec!["foo".into(), "bar".into(), +/// "baz".into(), "zar".into(), +/// "doz".into()]); +/// let concise = array!["foo", "bar", "baz", "zar", "doz"]; +/// assert_eq!(verbose, concise); +/// ``` +#[macro_export] +macro_rules! array [ + ( $($x:expr), *) => ({ + let mut _arr = Array::new(); + $(_arr.push($x.into());)* + _arr + }) +];