mirror of
https://github.com/sagiegurari/duckscript
synced 2024-10-14 20:02:32 +00:00
Fixed spread expansion with control characters #109
This commit is contained in:
parent
1d8fabb55d
commit
5ff4c4b1e2
|
@ -108,7 +108,7 @@ pub(crate) fn expand_by_wrapper(
|
|||
ExpandedValue::Single(value_string.to_string())
|
||||
} else {
|
||||
let chars = value_string.to_string().chars().collect();
|
||||
match parser::parse_arguments(meta_info, &chars, 0) {
|
||||
match parser::reparse_arguments(meta_info, &chars, 0) {
|
||||
Ok(values_option) => match values_option {
|
||||
Some(values) => ExpandedValue::Multi(values),
|
||||
None => ExpandedValue::None,
|
||||
|
|
|
@ -7,6 +7,13 @@ fn get_single_value(output: ExpandedValue) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_multi_value(output: ExpandedValue) -> Vec<String> {
|
||||
match output {
|
||||
ExpandedValue::Multi(value) => value,
|
||||
_ => panic!("Invalid type."),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expand_by_wrapper_control_chars() {
|
||||
let mut variables = HashMap::new();
|
||||
|
@ -220,3 +227,51 @@ value4:test4
|
|||
value
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expand_by_wrapper_control_chars_multi() {
|
||||
let mut variables = HashMap::new();
|
||||
variables.insert("FOUND".to_string(), r#"abc/123\\123"#.to_string());
|
||||
|
||||
let output = expand_by_wrapper("%{FOUND}", &InstructionMetaInfo::new(), &mut variables);
|
||||
|
||||
let value = get_multi_value(output);
|
||||
|
||||
assert_eq!(value.len(), 1);
|
||||
assert_eq!(r#"abc/123\\123"#, value[0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expand_by_wrapper_split_multi() {
|
||||
let mut variables = HashMap::new();
|
||||
variables.insert("FOUND".to_string(), r#"abc 123"#.to_string());
|
||||
|
||||
let output = expand_by_wrapper("%{FOUND}", &InstructionMetaInfo::new(), &mut variables);
|
||||
|
||||
let value = get_multi_value(output);
|
||||
|
||||
assert_eq!(value.len(), 2);
|
||||
assert_eq!("abc", value[0]);
|
||||
assert_eq!("123", value[1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expand_by_wrapper_split_complex_multi() {
|
||||
let mut variables = HashMap::new();
|
||||
variables.insert(
|
||||
"FOUND".to_string(),
|
||||
r#"abc 123 "in quotes" 2
|
||||
lines"#
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
let output = expand_by_wrapper("%{FOUND}", &InstructionMetaInfo::new(), &mut variables);
|
||||
|
||||
let value = get_multi_value(output);
|
||||
|
||||
assert_eq!(value.len(), 4);
|
||||
assert_eq!("abc", value[0]);
|
||||
assert_eq!("123", value[1]);
|
||||
assert_eq!("in quotes", value[2]);
|
||||
assert_eq!("2\nlines", value[3]);
|
||||
}
|
||||
|
|
|
@ -195,12 +195,29 @@ pub(crate) fn parse_arguments(
|
|||
meta_info: &InstructionMetaInfo,
|
||||
line_text: &Vec<char>,
|
||||
start_index: usize,
|
||||
) -> Result<Option<Vec<String>>, ScriptError> {
|
||||
parse_arguments_with_options(meta_info, line_text, start_index, false)
|
||||
}
|
||||
|
||||
pub(crate) fn reparse_arguments(
|
||||
meta_info: &InstructionMetaInfo,
|
||||
line_text: &Vec<char>,
|
||||
start_index: usize,
|
||||
) -> Result<Option<Vec<String>>, ScriptError> {
|
||||
parse_arguments_with_options(meta_info, line_text, start_index, true)
|
||||
}
|
||||
|
||||
fn parse_arguments_with_options(
|
||||
meta_info: &InstructionMetaInfo,
|
||||
line_text: &Vec<char>,
|
||||
start_index: usize,
|
||||
control_as_char: bool,
|
||||
) -> Result<Option<Vec<String>>, ScriptError> {
|
||||
let mut arguments = vec![];
|
||||
|
||||
let mut index = start_index;
|
||||
loop {
|
||||
match parse_next_argument(&meta_info, &line_text, index) {
|
||||
match parse_next_argument(&meta_info, &line_text, index, control_as_char) {
|
||||
Ok(output) => {
|
||||
let (next_index, argument) = output;
|
||||
|
||||
|
@ -226,8 +243,17 @@ fn parse_next_argument(
|
|||
meta_info: &InstructionMetaInfo,
|
||||
line_text: &Vec<char>,
|
||||
start_index: usize,
|
||||
control_as_char: bool,
|
||||
) -> Result<(usize, Option<String>), ScriptError> {
|
||||
parse_next_value(&meta_info, &line_text, start_index, true, true, false)
|
||||
parse_next_value(
|
||||
&meta_info,
|
||||
&line_text,
|
||||
start_index,
|
||||
true,
|
||||
!control_as_char,
|
||||
false,
|
||||
control_as_char,
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_next_value(
|
||||
|
@ -237,6 +263,7 @@ fn parse_next_value(
|
|||
allow_quotes: bool,
|
||||
allow_control: bool,
|
||||
stop_on_equals: bool,
|
||||
control_as_char: bool,
|
||||
) -> Result<(usize, Option<String>), ScriptError> {
|
||||
let end_index = line_text.len();
|
||||
|
||||
|
@ -286,7 +313,9 @@ fn parse_next_value(
|
|||
});
|
||||
}
|
||||
} else if character == '\\' {
|
||||
if allow_control {
|
||||
if control_as_char {
|
||||
argument.push(character);
|
||||
} else if allow_control {
|
||||
in_control = true;
|
||||
found_variable_prefix = false;
|
||||
} else {
|
||||
|
@ -327,7 +356,9 @@ fn parse_next_value(
|
|||
});
|
||||
}
|
||||
} else if character == '\\' {
|
||||
if allow_control {
|
||||
if control_as_char {
|
||||
argument.push(character);
|
||||
} else if allow_control {
|
||||
in_control = true;
|
||||
} else {
|
||||
return Err(ScriptError {
|
||||
|
@ -379,7 +410,7 @@ fn find_label(
|
|||
index = index + 1;
|
||||
|
||||
if character == LABEL_PREFIX {
|
||||
match parse_next_value(&meta_info, &line_text, index, false, false, false) {
|
||||
match parse_next_value(&meta_info, &line_text, index, false, false, false, false) {
|
||||
Ok(output) => {
|
||||
let (next_index, value) = output;
|
||||
index = next_index;
|
||||
|
@ -421,7 +452,15 @@ fn find_output_and_command(
|
|||
start_index: usize,
|
||||
instruction: &mut ScriptInstruction,
|
||||
) -> Result<usize, ScriptError> {
|
||||
match parse_next_value(&meta_info, &line_text, start_index, false, false, true) {
|
||||
match parse_next_value(
|
||||
&meta_info,
|
||||
&line_text,
|
||||
start_index,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
) {
|
||||
Ok(output) => {
|
||||
let (next_index, value) = output;
|
||||
|
||||
|
@ -444,7 +483,9 @@ fn find_output_and_command(
|
|||
}
|
||||
|
||||
if instruction.output.is_some() {
|
||||
match parse_next_value(&meta_info, &line_text, index, false, false, false) {
|
||||
match parse_next_value(
|
||||
&meta_info, &line_text, index, false, false, false, false,
|
||||
) {
|
||||
Ok(output) => {
|
||||
let (next_index, value) = output;
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ fn parse_pre_process_line_just_command_with_arguments() {
|
|||
#[test]
|
||||
fn parse_next_argument_empty() {
|
||||
let chars = "".chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -69,7 +69,7 @@ fn parse_next_argument_empty() {
|
|||
#[test]
|
||||
fn parse_next_argument_spaces_only() {
|
||||
let chars = " ".chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -82,7 +82,7 @@ fn parse_next_argument_spaces_only() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_only() {
|
||||
let chars = "test".chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -95,7 +95,7 @@ fn parse_next_argument_value_only() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_after_spaces() {
|
||||
let chars = " test".chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -108,7 +108,7 @@ fn parse_next_argument_value_after_spaces() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_in_middle_of_spaces() {
|
||||
let chars = " test ".chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -121,7 +121,7 @@ fn parse_next_argument_value_in_middle_of_spaces() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_in_middle_of_spaces_start_in_middle_of_value() {
|
||||
let chars = " test ".chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 3);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 3, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -134,7 +134,7 @@ fn parse_next_argument_value_in_middle_of_spaces_start_in_middle_of_value() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_quots() {
|
||||
let chars = r#" "test" "#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -147,7 +147,7 @@ fn parse_next_argument_value_with_quots() {
|
|||
#[test]
|
||||
fn parse_next_argument_empty_with_quots() {
|
||||
let chars = r#" "" "#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -160,7 +160,7 @@ fn parse_next_argument_empty_with_quots() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_control() {
|
||||
let chars = r#" \"test\"\\\n\r\t test "#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -173,7 +173,7 @@ fn parse_next_argument_value_with_control() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_space_in_middle() {
|
||||
let chars = r#" "test \"test\"" "#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -186,7 +186,7 @@ fn parse_next_argument_value_with_space_in_middle() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_comment_in_middle() {
|
||||
let chars = r#" "test \"test\" #test test" "#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -199,7 +199,7 @@ fn parse_next_argument_value_with_comment_in_middle() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_comment_afterwards() {
|
||||
let chars = r#" test#comment"#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -212,7 +212,7 @@ fn parse_next_argument_value_with_comment_afterwards() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_comment_afterwards_wrapped_with_quotes() {
|
||||
let chars = r#" "test#comment""#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -225,7 +225,7 @@ fn parse_next_argument_value_with_comment_afterwards_wrapped_with_quotes() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_control_error() {
|
||||
let chars = r#" \a "#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ fn parse_next_argument_value_with_control_error() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_partial_variable_control_error() {
|
||||
let chars = r#" \$ "#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ fn parse_next_argument_value_with_partial_variable_control_error() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_control_end_error() {
|
||||
let chars = r#" \"#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ fn parse_next_argument_value_with_control_end_error() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_variable_control() {
|
||||
let chars = r#" \${out} "#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_ok());
|
||||
|
||||
|
@ -262,7 +262,7 @@ fn parse_next_argument_value_with_variable_control() {
|
|||
#[test]
|
||||
fn parse_next_argument_value_with_quote_end_error() {
|
||||
let chars = r#" ""#.chars().collect();
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0);
|
||||
let result = parse_next_argument(&InstructionMetaInfo::new(), &chars, 0, false);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue