Arguments done!
This commit is contained in:
parent
ac5433248e
commit
b57b84e550
14
notes
14
notes
@ -1,20 +1,16 @@
|
|||||||
notes
|
notes
|
||||||
-----
|
-----
|
||||||
|
|
||||||
- arguments:
|
|
||||||
. change evaluate_expression to evaluate_lines
|
|
||||||
. fast errors when arguments are not passed
|
|
||||||
. don't assume that argument count is correct
|
|
||||||
. don't unwrap errors in evaluate line
|
|
||||||
. sub arguments into recipes
|
|
||||||
|
|
||||||
- save result of commands in variables: `hello`
|
- save result of commands in variables: `hello`
|
||||||
|
|
||||||
- set variables from the command line: j --set build linux
|
- set variables from the command line:
|
||||||
|
. j --set build linux
|
||||||
|
. j build=linux
|
||||||
|
|
||||||
- before release:
|
- before release:
|
||||||
|
|
||||||
|
- where can users get help?
|
||||||
|
- irc, email, github, mailing list
|
||||||
- rewrite grammar.txt
|
- rewrite grammar.txt
|
||||||
- start with an example justfile
|
- start with an example justfile
|
||||||
- then installation instructions
|
- then installation instructions
|
||||||
|
87
src/lib.rs
87
src/lib.rs
@ -135,31 +135,24 @@ fn error_from_signal(recipe: &str, exit_status: process::ExitStatus) -> RunError
|
|||||||
|
|
||||||
impl<'a> Recipe<'a> {
|
impl<'a> Recipe<'a> {
|
||||||
fn run(&self, arguments: &[&'a str], scope: &BTreeMap<&'a str, String>) -> Result<(), RunError<'a>> {
|
fn run(&self, arguments: &[&'a str], scope: &BTreeMap<&'a str, String>) -> Result<(), RunError<'a>> {
|
||||||
let mut evaluated_lines = vec![];
|
let mut arg_map = BTreeMap::new();
|
||||||
for fragments in &self.lines {
|
for (i, argument) in arguments.iter().enumerate() {
|
||||||
let mut line = String::new();
|
arg_map.insert(*self.arguments.get(i).unwrap(), Some(*argument));
|
||||||
for fragment in fragments.iter() {
|
}
|
||||||
match *fragment {
|
|
||||||
Fragment::Text{ref text} => line += text.lexeme,
|
let evaluated_lines;
|
||||||
Fragment::Expression{value: Some(ref value), ..} => {
|
match evaluate_lines(&self.lines, &scope, &arg_map) {
|
||||||
line += &value;
|
Err(error) => {
|
||||||
}
|
return Err(RunError::InternalError {
|
||||||
Fragment::Expression{ref expression, value: None} => {
|
message: format!("deferred evaluation failed {}", error),
|
||||||
let mut arg_map = BTreeMap::new();
|
});
|
||||||
for (i, argument) in arguments.iter().enumerate() {
|
|
||||||
arg_map.insert(*self.arguments.get(i).unwrap(), *argument);
|
|
||||||
}
|
|
||||||
line += &evaluate_expression(
|
|
||||||
expression,
|
|
||||||
&scope,
|
|
||||||
&BTreeMap::new(),
|
|
||||||
&BTreeMap::new(),
|
|
||||||
&arg_map,
|
|
||||||
).unwrap().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
evaluated_lines.push(line);
|
Ok(None) => {
|
||||||
|
return Err(RunError::InternalError {
|
||||||
|
message: "deferred evaluation returned None".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(Some(lines)) => evaluated_lines = lines,
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.shebang {
|
if self.shebang {
|
||||||
@ -377,26 +370,42 @@ fn evaluate<'a>(
|
|||||||
Ok(evaluated)
|
Ok(evaluated)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_expression<'a: 'b, 'b> (
|
fn evaluate_lines<'a>(
|
||||||
expression: &Expression<'a>,
|
lines: &Vec<Vec<Fragment<'a>>>,
|
||||||
scope: &BTreeMap<&'a str, String>,
|
scope: &BTreeMap<&'a str, String>,
|
||||||
assignments: &'b BTreeMap<&'a str, Expression<'a>>,
|
arguments: &BTreeMap<&str, Option<&str>>
|
||||||
assignment_tokens: &'b BTreeMap<&'a str, Token<'a>>,
|
) -> Result<Option<Vec<String>>, Error<'a>> {
|
||||||
arguments: &BTreeMap<&str, &str>,
|
|
||||||
) -> Result<Option<String>, Error<'a>> {
|
|
||||||
let mut evaluator = Evaluator{
|
let mut evaluator = Evaluator{
|
||||||
seen: HashSet::new(),
|
seen: HashSet::new(),
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
evaluated: &mut BTreeMap::new(),
|
evaluated: &mut BTreeMap::new(),
|
||||||
scope: scope,
|
scope: scope,
|
||||||
assignments: assignments,
|
assignments: &BTreeMap::new(),
|
||||||
assignment_tokens: assignment_tokens,
|
assignment_tokens: &BTreeMap::new(),
|
||||||
};
|
};
|
||||||
let mut argument_options = BTreeMap::new();
|
|
||||||
for (name, value) in arguments.iter() {
|
let mut evaluated_lines = vec![];
|
||||||
argument_options.insert(*name, Some(*value));
|
for fragments in lines {
|
||||||
|
let mut line = String::new();
|
||||||
|
for fragment in fragments.iter() {
|
||||||
|
match *fragment {
|
||||||
|
Fragment::Text{ref text} => line += text.lexeme,
|
||||||
|
Fragment::Expression{value: Some(ref value), ..} => {
|
||||||
|
line += &value;
|
||||||
|
}
|
||||||
|
Fragment::Expression{ref expression, value: None} => {
|
||||||
|
if let Some(value) = try!(evaluator.evaluate_expression(expression, &arguments)) {
|
||||||
|
line += &value;
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
evaluated_lines.push(line);
|
||||||
}
|
}
|
||||||
evaluator.evaluate_expression(expression, &argument_options)
|
|
||||||
|
Ok(Some(evaluated_lines))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Evaluator<'a: 'b, 'b> {
|
struct Evaluator<'a: 'b, 'b> {
|
||||||
@ -777,6 +786,7 @@ enum RunError<'a> {
|
|||||||
UnknownFailure{recipe: &'a str},
|
UnknownFailure{recipe: &'a str},
|
||||||
IoError{recipe: &'a str, io_error: io::Error},
|
IoError{recipe: &'a str, io_error: io::Error},
|
||||||
TmpdirIoError{recipe: &'a str, io_error: io::Error},
|
TmpdirIoError{recipe: &'a str, io_error: io::Error},
|
||||||
|
InternalError{message: String},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Display for RunError<'a> {
|
impl<'a> Display for RunError<'a> {
|
||||||
@ -815,6 +825,9 @@ impl<'a> Display for RunError<'a> {
|
|||||||
},
|
},
|
||||||
RunError::TmpdirIoError{recipe, ref io_error} =>
|
RunError::TmpdirIoError{recipe, ref io_error} =>
|
||||||
try!(write!(f, "Recipe \"{}\" could not be run because of an IO error while trying to create a temporary directory or write a file to that directory`:\n{}", recipe, io_error)),
|
try!(write!(f, "Recipe \"{}\" could not be run because of an IO error while trying to create a temporary directory or write a file to that directory`:\n{}", recipe, io_error)),
|
||||||
|
RunError::InternalError{ref message} => {
|
||||||
|
try!(writeln!(f, "internal error, this may indicate a bug in j: {}\n consider filing an issue: https://github.com/casey/j/issues/new", message));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
23
src/unit.rs
23
src/unit.rs
@ -733,3 +733,26 @@ a return code:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn missing_args() {
|
||||||
|
match parse_success("a b c d:").run(&["a", "b", "c"]).unwrap_err() {
|
||||||
|
super::RunError::ArgumentCountMismatch{recipe, found, expected} => {
|
||||||
|
assert_eq!(recipe, "a");
|
||||||
|
assert_eq!(found, 2);
|
||||||
|
assert_eq!(expected, 3);
|
||||||
|
},
|
||||||
|
other => panic!("expected an code run error, but got: {}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn missing_default() {
|
||||||
|
match parse_success("a b c d:\n echo {{b}}{{c}}{{d}}").run(&["a"]).unwrap_err() {
|
||||||
|
super::RunError::ArgumentCountMismatch{recipe, found, expected} => {
|
||||||
|
assert_eq!(recipe, "a");
|
||||||
|
assert_eq!(found, 0);
|
||||||
|
assert_eq!(expected, 3);
|
||||||
|
},
|
||||||
|
other => panic!("expected an code run error, but got: {}", other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user