Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 73 additions & 3 deletions packages/hurl_core/src/parser/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,19 +467,34 @@ fn variable_name(reader: &mut Reader) -> ParseResult<String> {
Ok(name)
}

// `null`, a boolean or a number is only a variable value when the literal spans the whole
// value. When more characters follow (as in `11aa` or `true_is_true`), the literal is just
// the start of an unquoted string, so return a recoverable error to fall back to it.
fn literal_value<T>(reader: &mut Reader, value: T) -> ParseResult<T> {
match reader.peek() {
None | Some(' ' | '\t' | '\r' | '\n' | '#') => Ok(value),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless mistake, I think we should not take # into account here:

GET http://localhost:8000
[Options]
variable: foo=true#this_is_not_a_comment

foo should be equal to the string true#this_is_not_a_comment and not be parsed as a bool

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first, I would have excluded it.
But in the shell, it is not treated as comment

  $ value=true#this_is_not_a_comment
  $ echo "$value"
  true#this_is_not_a_comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By "not take # into account here" I mean not use in this pattern Some(' ' | '\t' | '\r' | '\n' | '#').

variable: foo=true#this_is_not_a_comment should create a string variable with value true#this_is_not_a_comment

Some(_) => {
let kind = ParseErrorKind::Expecting {
value: "variable value".to_string(),
};
Err(ParseError::new(reader.cursor().pos, true, kind))
}
}
}

fn variable_value(reader: &mut Reader) -> ParseResult<VariableValue> {
choice(
&[
|p1| match null(p1) {
Ok(()) => Ok(VariableValue::Null),
Ok(()) => literal_value(p1, VariableValue::Null),
Err(e) => Err(e),
},
|p1| match boolean(p1) {
Ok(value) => Ok(VariableValue::Bool(value)),
Ok(value) => literal_value(p1, VariableValue::Bool(value)),
Err(e) => Err(e),
},
|p1| match number(p1) {
Ok(value) => Ok(VariableValue::Number(value)),
Ok(value) => literal_value(p1, VariableValue::Number(value)),
Err(e) => Err(e),
},
|p1| match quoted_template(p1) {
Expand Down Expand Up @@ -767,4 +782,59 @@ mod tests {
))
);
}

#[test]
fn test_variable_value_string_with_literal_prefix() {
let mut reader = Reader::new("11aa");
assert_eq!(
variable_value(&mut reader).unwrap(),
VariableValue::String(Template::new(
None,
vec![TemplateElement::String {
value: "11aa".to_string(),
source: "11aa".to_source(),
}],
SourceInfo::new(Pos::new(1, 1), Pos::new(1, 5)),
))
);

let mut reader = Reader::new("0.5x");
assert_eq!(
variable_value(&mut reader).unwrap(),
VariableValue::String(Template::new(
None,
vec![TemplateElement::String {
value: "0.5x".to_string(),
source: "0.5x".to_source(),
}],
SourceInfo::new(Pos::new(1, 1), Pos::new(1, 5)),
))
);

let mut reader = Reader::new("true_is_true");
assert_eq!(
variable_value(&mut reader).unwrap(),
VariableValue::String(Template::new(
None,
vec![TemplateElement::String {
value: "true_is_true".to_string(),
source: "true_is_true".to_source(),
}],
SourceInfo::new(Pos::new(1, 1), Pos::new(1, 13)),
))
);

let mut reader = Reader::new("nullable");
assert_eq!(
variable_value(&mut reader).unwrap(),
VariableValue::String(Template::new(
None,
vec![TemplateElement::String {
value: "nullable".to_string(),
source: "nullable".to_source(),
}],
SourceInfo::new(Pos::new(1, 1), Pos::new(1, 9)),
))
);
}
}
Loading