Skip to content

Commit

Permalink
Change ParserError::Json to use a JsonErrorVariant enum and add a
Browse files Browse the repository at this point in the history
new check to account for unresolved names
  • Loading branch information
robozati committed Oct 31, 2023
1 parent 63f675a commit 886a379
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 57 deletions.
21 changes: 12 additions & 9 deletions packages/hurl_core/src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
use core::cmp;

use crate::ast::SourceInfo;
use crate::parser;
use crate::parser::ParseError;
use crate::parser::{self, JsonErrorVariant};

pub trait Error {
fn source_info(&self) -> SourceInfo;
Expand Down Expand Up @@ -48,10 +48,7 @@ impl Error for parser::Error {
ParseError::JsonPathExpr => "Parsing JSONPath expression".to_string(),
ParseError::XPathExpr => "Parsing XPath expression".to_string(),
ParseError::TemplateVariable => "Parsing template variable".to_string(),
ParseError::Json => "Parsing JSON".to_string(),
ParseError::UnexpectedInJson { .. } => "Parsing JSON".to_string(),
ParseError::ExpectedAnElementInJson => "Parsing JSON".to_string(),
ParseError::UnclosedBraceInJson => "Parsing JSON".to_string(),
ParseError::Json(_) => "Parsing JSON".to_string(),
ParseError::Predicate => "Parsing predicate".to_string(),
ParseError::PredicateValue => "Parsing predicate value".to_string(),
ParseError::RegexExpr { .. } => "Parsing regex".to_string(),
Expand Down Expand Up @@ -97,7 +94,16 @@ impl Error for parser::Error {
ParseError::JsonPathExpr => "expecting a JSONPath expression".to_string(),
ParseError::XPathExpr => "expecting a XPath expression".to_string(),
ParseError::TemplateVariable => "expecting a variable".to_string(),
ParseError::Json => "JSON error".to_string(),
ParseError::Json(variant) => {
match variant {
JsonErrorVariant::UnexpectedCharcter { character } => format!("unexpected character: '{character}'"),
JsonErrorVariant::EmptyElement => "expecting an element; found empty element instead".to_string(),
JsonErrorVariant::UnclosedBrace => "this brace is not closed later".to_string(),
JsonErrorVariant::CannotResolve { name } => {
format!("failed to resolve '{name}'. If it's a variable, try enclosing it with double braces, e.g. {{{{{name}}}}}")
}
}
}
ParseError::Predicate => "expecting a predicate".to_string(),
ParseError::PredicateValue => "invalid predicate value".to_string(),
ParseError::RegexExpr { message } => format!("invalid Regex expression: {message}"),
Expand All @@ -119,9 +125,6 @@ impl Error for parser::Error {
ParseError::UrlInvalidStart => "expecting http://, https:// or {{".to_string(),
ParseError::Multiline => "the multiline is not valid".to_string(),
ParseError::GraphQlVariables => "GraphQL variables is not a valid JSON object".to_string(),
ParseError::UnexpectedInJson { character } => format!("unexpected character: '{character}'"),
ParseError::ExpectedAnElementInJson => "expecting an element; found empty element instead".to_string(),
ParseError::UnclosedBraceInJson => "this brace is not closed later".to_string(),
_ => format!("{self:?}"),

}
Expand Down
5 changes: 4 additions & 1 deletion packages/hurl_core/src/parser/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ mod tests {
let mut reader = Reader::new("{ x ");
let error = bytes(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 1, column: 1 });
assert_eq!(error.inner, ParseError::UnclosedBraceInJson);
assert_eq!(
error.inner,
ParseError::Json(JsonErrorVariant::UnclosedBrace)
);
}

#[test]
Expand Down
13 changes: 9 additions & 4 deletions packages/hurl_core/src/parser/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,12 @@ pub enum ParseError {
JsonPathExpr,
XPathExpr,
TemplateVariable,
Json,
Json(JsonErrorVariant),
Xml,
Predicate,
PredicateValue,
RegexExpr { message: String },

ExpectedAnElementInJson,
UnexpectedInJson { character: String },
UnclosedBraceInJson,
Eof,
Url,

Expand All @@ -68,6 +65,14 @@ pub enum ParseError {
GraphQlVariables,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum JsonErrorVariant {
UnexpectedCharcter { character: String },
CannotResolve { name: String },
EmptyElement,
UnclosedBrace,
}

impl Error {
pub fn recoverable(&self) -> Error {
Error {
Expand Down
109 changes: 67 additions & 42 deletions packages/hurl_core/src/parser/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,46 @@ pub fn parse(reader: &mut Reader) -> ParseResult<JsonValue> {
)
}

/// Helper for parse, but already knowing that we are inside a JSON body.
fn parse_in_json(reader: &mut Reader) -> ParseResult<JsonValue> {
if let Some(c) = reader.peek() {
if c == ',' {
return Err(Error {
pos: reader.state.pos.clone(),
recoverable: false,
inner: error::ParseError::Json(JsonErrorVariant::EmptyElement),
});
}
}
match parse(reader) {
Ok(r) => Ok(r),
// The only error that is recoverable is caused by reaching object_value try_literal('{'),
// but this is not recoverable in this case, because we already know that we are in a JSON
// body. So, we change the error to CannotResolve for the object found.
Err(e) => match e {
Error {
recoverable: true, ..
} => {
return Err(error::Error {
pos: e.pos,
recoverable: false,
inner: error::ParseError::Json(JsonErrorVariant::CannotResolve {
name: reader
.read_while(|c| !c.is_whitespace() && !c.is_ascii_punctuation()),
}),
})
}
_ => {
return Err(Error {
recoverable: false,
pos: e.pos,
inner: e.inner,
})
}
},
}
}

pub fn null_value(reader: &mut Reader) -> ParseResult<JsonValue> {
try_literal("null", reader)?;
Ok(JsonValue::Null)
Expand Down Expand Up @@ -264,9 +304,9 @@ fn list_value(reader: &mut Reader) -> ParseResult<JsonValue> {
return Err(Error {
pos: save,
recoverable: false,
inner: ParseError::UnexpectedInJson {
inner: ParseError::Json(JsonErrorVariant::UnexpectedCharcter {
character: ','.to_string(),
},
}),
});
}
let element = list_element(reader)?;
Expand All @@ -280,19 +320,7 @@ fn list_value(reader: &mut Reader) -> ParseResult<JsonValue> {

fn list_element(reader: &mut Reader) -> ParseResult<JsonListElement> {
let space0 = whitespace(reader);
let value = match parse(reader) {
Ok(r) => r,
Err(e) => {
return Err(Error {
// Recoverable must be set to false, else the Body parser may think this is not a
// JSON body, because the JSON parser can fail in object_value try_literal('{'),
// and try_literal is marked as recoverable.
recoverable: false,
pos: e.pos,
inner: e.inner,
});
}
};
let value = parse_in_json(reader)?;
let space1 = whitespace(reader);
Ok(JsonListElement {
space0,
Expand Down Expand Up @@ -330,9 +358,9 @@ pub fn object_value(reader: &mut Reader) -> ParseResult<JsonValue> {
return Err(Error {
pos: save,
recoverable: false,
inner: ParseError::UnexpectedInJson {
inner: ParseError::Json(JsonErrorVariant::UnexpectedCharcter {
character: ','.to_string(),
},
}),
});
}
let element = object_element(reader)?;
Expand All @@ -354,7 +382,7 @@ fn key(reader: &mut Reader) -> ParseResult<Template> {
Err(error::Error {
pos: save.pos,
recoverable: false,
inner: error::ParseError::Json,
inner: error::ParseError::Json(JsonErrorVariant::EmptyElement),
})
} else {
Ok(name)
Expand All @@ -377,22 +405,10 @@ fn object_element(reader: &mut Reader) -> ParseResult<JsonObjectElement> {
return Err(error::Error {
pos: save,
recoverable: false,
inner: error::ParseError::ExpectedAnElementInJson,
inner: error::ParseError::Json(JsonErrorVariant::EmptyElement),
});
}
let value = match parse(reader) {
Ok(r) => r,
Err(e) => {
return Err(Error {
// Recoverable must be set to false, else the Body parser may think this is not a
// JSON body, because the JSON parser can fail in object_value try_literal('{'),
// and try_literal is marked as recoverable.
recoverable: false,
pos: e.pos,
inner: e.inner,
});
}
};
let value = parse_in_json(reader)?;
let space3 = whitespace(reader);
Ok(JsonObjectElement {
space0,
Expand Down Expand Up @@ -429,7 +445,7 @@ fn peek_until_close_brace(reader: &mut Reader, state: ReaderState) -> ParseResul
return Err(Error {
pos: state.pos,
recoverable: false,
inner: ParseError::UnclosedBraceInJson,
inner: ParseError::Json(JsonErrorVariant::UnclosedBrace),
});
}
offset += 1;
Expand All @@ -446,17 +462,20 @@ mod tests {
let mut reader = Reader::new("{ \"a\":\n}");
let error = parse(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 1, column: 7 });
assert_eq!(error.inner, error::ParseError::ExpectedAnElementInJson);
assert_eq!(
error.inner,
error::ParseError::Json(JsonErrorVariant::EmptyElement)
);
assert!(!error.recoverable);

let mut reader = Reader::new("[0,1,]");
let error = parse(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 1, column: 5 });
assert_eq!(
error.inner,
error::ParseError::UnexpectedInJson {
character: ",".to_string()
}
error::ParseError::Json(JsonErrorVariant::UnexpectedCharcter {
character: ','.to_string(),
}),
);
assert!(!error.recoverable);
}
Expand Down Expand Up @@ -855,9 +874,9 @@ mod tests {
assert_eq!(error.pos, Pos { line: 1, column: 6 });
assert_eq!(
error.inner,
error::ParseError::UnexpectedInJson {
character: ",".to_string()
}
error::ParseError::Json(JsonErrorVariant::UnexpectedCharcter {
character: ','.to_string(),
}),
);
assert!(!error.recoverable);
}
Expand Down Expand Up @@ -939,7 +958,10 @@ mod tests {
let mut reader = Reader::new("{ \"a\":\n}");
let error = object_value(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 1, column: 7 });
assert_eq!(error.inner, error::ParseError::ExpectedAnElementInJson);
assert_eq!(
error.inner,
error::ParseError::Json(JsonErrorVariant::EmptyElement)
);
assert!(!error.recoverable);
}

Expand Down Expand Up @@ -983,7 +1005,10 @@ mod tests {
let mut reader = Reader::new("\"name\":\n");
let error = object_element(&mut reader).err().unwrap();
assert_eq!(error.pos, Pos { line: 1, column: 8 });
assert_eq!(error.inner, error::ParseError::ExpectedAnElementInJson,);
assert_eq!(
error.inner,
error::ParseError::Json(JsonErrorVariant::EmptyElement),
);
assert!(!error.recoverable);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/hurl_core/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub fn parse_hurl_file(s: &str) -> ParseResult<HurlFile> {
parsers::hurl_file(&mut reader)
}

pub use self::error::{Error, ParseError};
pub use self::error::{Error, ParseError, JsonErrorVariant};
pub use self::json::{
boolean_value as parse_json_boolean, null_value as parse_json_null,
number_value as parse_json_number, parse as parse_json,
Expand Down

0 comments on commit 886a379

Please sign in to comment.