mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-09-11 05:35:53 +03:00
Some cosmetic changes on Reader.
This commit is contained in:
parent
76b45a1ed1
commit
b484ef8125
@ -163,7 +163,7 @@ fn selector_object_key(reader: &mut Reader) -> Result<Selector, ParseError> {
|
||||
};
|
||||
_ = reader.read();
|
||||
|
||||
let s = reader.read_while(|c| c.is_alphanumeric() || *c == '_' || *c == '-');
|
||||
let s = reader.read_while(|c| c.is_alphanumeric() || c == '_' || c == '-');
|
||||
if s.is_empty() {
|
||||
let kind = ParseErrorKind::Expecting("empty value".to_string());
|
||||
let error = ParseError::new(reader.cursor().pos, false, kind);
|
||||
|
@ -136,7 +136,7 @@ pub fn key_name(reader: &mut Reader) -> Result<String, ParseError> {
|
||||
return Err(error);
|
||||
}
|
||||
};
|
||||
let s = reader.read_while(|c| c.is_alphanumeric() || *c == '_');
|
||||
let s = reader.read_while(|c| c.is_alphanumeric() || c == '_');
|
||||
whitespace(reader);
|
||||
Ok(format!("{first_char}{s}"))
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ pub fn cookiepath(reader: &mut Reader) -> ParseResult<CookiePath> {
|
||||
|
||||
// We create a specialized reader for the templated, error and created structures are
|
||||
// relative tho the main reader.
|
||||
let s = reader.read_while(|c| *c != '[');
|
||||
let s = reader.read_while(|c| c != '[');
|
||||
let mut template_reader = Reader::with_pos(s.as_str(), start);
|
||||
let name = unquoted_template(&mut template_reader)?;
|
||||
let attribute = optional(cookiepath_attribute, reader)?;
|
||||
@ -50,7 +50,7 @@ fn cookiepath_attribute(reader: &mut Reader) -> ParseResult<CookieAttribute> {
|
||||
|
||||
fn cookiepath_attribute_name(reader: &mut Reader) -> ParseResult<CookieAttributeName> {
|
||||
let start = reader.cursor().pos;
|
||||
let s = reader.read_while(|c| c.is_alphabetic() || *c == '-');
|
||||
let s = reader.read_while(|c| c.is_alphabetic() || c == '-');
|
||||
match s.to_lowercase().as_str() {
|
||||
"value" => Ok(CookieAttributeName::Value(s)),
|
||||
"expires" => Ok(CookieAttributeName::Expires(s)),
|
||||
@ -180,7 +180,7 @@ mod tests {
|
||||
|
||||
// Check that errors are well reported with a buffer that have already read data.
|
||||
let mut reader = Reader::new("xxxx{{cookie[Domain]");
|
||||
_ = reader.read_while(|&c| c == 'x');
|
||||
_ = reader.read_while(|c| c == 'x');
|
||||
|
||||
let error = cookiepath(&mut reader).err().unwrap();
|
||||
assert_eq!(
|
||||
|
@ -52,7 +52,7 @@ pub fn parse2(reader: &mut Reader) -> ParseResult<Expr> {
|
||||
|
||||
fn variable_name(reader: &mut Reader) -> ParseResult<Variable> {
|
||||
let start = reader.cursor();
|
||||
let name = reader.read_while(|c| c.is_alphanumeric() || *c == '_' || *c == '-');
|
||||
let name = reader.read_while(|c| c.is_alphanumeric() || c == '_' || c == '-');
|
||||
if name.is_empty() {
|
||||
return Err(ParseError::new(
|
||||
start.pos,
|
||||
|
@ -45,7 +45,7 @@ pub fn parse(reader: &mut Reader) -> ParseResult<Template> {
|
||||
if value.is_empty() {
|
||||
break;
|
||||
}
|
||||
let encoded = reader.peek_back(start.offset);
|
||||
let encoded = reader.read_from(start.offset);
|
||||
let element = TemplateElement::String { value, encoded };
|
||||
elements.push(element);
|
||||
} else {
|
||||
|
@ -46,7 +46,7 @@ pub fn parse(reader: &mut Reader) -> ParseResult<Template> {
|
||||
if value.is_empty() {
|
||||
break;
|
||||
}
|
||||
let encoded = reader.peek_back(start.offset);
|
||||
let encoded = reader.read_from(start.offset);
|
||||
let element = TemplateElement::String { value, encoded };
|
||||
elements.push(element);
|
||||
} else {
|
||||
|
@ -110,7 +110,7 @@ fn string_template(reader: &mut Reader) -> ParseResult<Template> {
|
||||
fn any_char(reader: &mut Reader) -> ParseResult<(char, String, Pos)> {
|
||||
let start = reader.cursor();
|
||||
match escape_char(reader) {
|
||||
Ok(c) => Ok((c, reader.peek_back(start.offset), start.pos)),
|
||||
Ok(c) => Ok((c, reader.read_from(start.offset), start.pos)),
|
||||
Err(e) => {
|
||||
if e.recoverable {
|
||||
reader.seek(start);
|
||||
@ -128,7 +128,7 @@ fn any_char(reader: &mut Reader) -> ParseResult<(char, String, Pos)> {
|
||||
};
|
||||
Err(ParseError::new(start.pos, true, kind))
|
||||
} else {
|
||||
Ok((c, reader.peek_back(start.offset), start.pos))
|
||||
Ok((c, reader.read_from(start.offset), start.pos))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -299,7 +299,7 @@ fn list_value(reader: &mut Reader) -> ParseResult<JsonValue> {
|
||||
literal(",", reader)?;
|
||||
// If there is one more comma, e.g. [1, 2,], it's better to report to the user because
|
||||
// this occurrence is common.
|
||||
if reader.peek_ignoring_whitespace() == Some(']') {
|
||||
if reader.peek_if(|c| !is_whitespace(c)) == Some(']') {
|
||||
let kind = ParseErrorKind::Json(JsonErrorVariant::TrailingComma);
|
||||
return Err(ParseError::new(save.pos, false, kind));
|
||||
}
|
||||
@ -346,7 +346,7 @@ pub fn object_value(reader: &mut Reader) -> ParseResult<JsonValue> {
|
||||
literal(",", reader)?;
|
||||
// If there is one more comma, e.g. {"a": "b",}, it's better to report to the user
|
||||
// because this occurrence is common.
|
||||
if reader.peek_ignoring_whitespace() == Some('}') {
|
||||
if reader.peek_if(|c| !is_whitespace(c)) == Some('}') {
|
||||
let kind = ParseErrorKind::Json(JsonErrorVariant::TrailingComma);
|
||||
return Err(ParseError::new(save.pos, false, kind));
|
||||
}
|
||||
@ -396,8 +396,12 @@ fn object_element(reader: &mut Reader) -> ParseResult<JsonObjectElement> {
|
||||
})
|
||||
}
|
||||
|
||||
fn is_whitespace(c: char) -> bool {
|
||||
c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
||||
}
|
||||
|
||||
fn whitespace(reader: &mut Reader) -> String {
|
||||
reader.read_while(|c| *c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')
|
||||
reader.read_while(is_whitespace)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -38,7 +38,7 @@ pub fn parse(reader: &mut Reader) -> ParseResult<Template> {
|
||||
if value.is_empty() {
|
||||
break;
|
||||
}
|
||||
let encoded = reader.peek_back(start.offset);
|
||||
let encoded = reader.read_from(start.offset);
|
||||
let element = TemplateElement::String { value, encoded };
|
||||
elements.push(element);
|
||||
} else {
|
||||
|
@ -102,7 +102,7 @@ pub fn number(reader: &mut Reader) -> ParseResult<Number> {
|
||||
}
|
||||
match format!("{sign}{integer_digits}.{decimal_digits}").parse() {
|
||||
Ok(value) => {
|
||||
let encoded = reader.peek_back(start.offset);
|
||||
let encoded = reader.read_from(start.offset);
|
||||
Ok(Number::Float(Float { value, encoded }))
|
||||
}
|
||||
Err(_) => {
|
||||
|
@ -34,7 +34,7 @@ pub fn parse(reader: &mut Reader) -> ParseResult<EntryOption> {
|
||||
// enter the parsing of the option name and to have better error description (ex: 'max-redirs'
|
||||
// vs 'max_redirs').
|
||||
let option =
|
||||
reader.read_while(|c| c.is_ascii_alphanumeric() || *c == '-' || *c == '.' || *c == '_');
|
||||
reader.read_while(|c| c.is_ascii_alphanumeric() || c == '-' || c == '.' || c == '_');
|
||||
let space1 = zero_or_more_spaces(reader)?;
|
||||
try_literal(":", reader)?;
|
||||
let space2 = zero_or_more_spaces(reader)?;
|
||||
@ -371,7 +371,7 @@ fn variable_definition(reader: &mut Reader) -> ParseResult<VariableDefinition> {
|
||||
|
||||
fn variable_name(reader: &mut Reader) -> ParseResult<String> {
|
||||
let start = reader.cursor();
|
||||
let name = reader.read_while(|c| c.is_alphanumeric() || *c == '_' || *c == '-');
|
||||
let name = reader.read_while(|c| c.is_alphanumeric() || c == '_' || c == '-');
|
||||
if name.is_empty() {
|
||||
let kind = ParseErrorKind::Expecting {
|
||||
value: "variable name".to_string(),
|
||||
|
@ -261,7 +261,7 @@ pub fn hex(reader: &mut Reader) -> ParseResult<Hex> {
|
||||
ParseErrorKind::OddNumberOfHexDigits,
|
||||
));
|
||||
}
|
||||
let encoded = reader.peek_back(start.offset);
|
||||
let encoded = reader.read_from(start.offset);
|
||||
let space1 = zero_or_more_spaces(reader)?;
|
||||
literal(";", reader)?;
|
||||
|
||||
|
@ -75,7 +75,7 @@ pub fn unquoted_template(reader: &mut Reader) -> ParseResult<Template> {
|
||||
// (decoding escape sequence)
|
||||
pub fn quoted_oneline_string(reader: &mut Reader) -> ParseResult<String> {
|
||||
literal("\"", reader)?;
|
||||
let s = reader.read_while(|c| *c != '"' && *c != '\n');
|
||||
let s = reader.read_while(|c| c != '"' && c != '\n');
|
||||
literal("\"", reader)?;
|
||||
Ok(s)
|
||||
}
|
||||
@ -156,7 +156,7 @@ pub fn backtick_template(reader: &mut Reader) -> ParseResult<Template> {
|
||||
fn any_char(except: Vec<char>, reader: &mut Reader) -> ParseResult<(char, String)> {
|
||||
let start = reader.cursor();
|
||||
match escape_char(reader) {
|
||||
Ok(c) => Ok((c, reader.peek_back(start.offset))),
|
||||
Ok(c) => Ok((c, reader.read_from(start.offset))),
|
||||
Err(e) => {
|
||||
if e.recoverable {
|
||||
reader.seek(start);
|
||||
@ -176,7 +176,7 @@ fn any_char(except: Vec<char>, reader: &mut Reader) -> ParseResult<(char, String
|
||||
};
|
||||
Err(ParseError::new(start.pos, true, kind))
|
||||
} else {
|
||||
Ok((c, reader.peek_back(start.offset)))
|
||||
Ok((c, reader.read_from(start.offset)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Reader {
|
||||
buffer: Vec<char>,
|
||||
buf: Vec<char>,
|
||||
cursor: Cursor,
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ impl Reader {
|
||||
/// Creates a new reader, position of the index is at the first char.
|
||||
pub fn new(s: &str) -> Self {
|
||||
Reader {
|
||||
buffer: s.chars().collect(),
|
||||
buf: s.chars().collect(),
|
||||
cursor: Cursor {
|
||||
offset: 0,
|
||||
pos: Pos { line: 1, column: 1 },
|
||||
@ -95,7 +95,7 @@ impl Reader {
|
||||
/// Note: the `buffer` offset is still initialized to 0.
|
||||
pub fn with_pos(s: &str, pos: Pos) -> Self {
|
||||
Reader {
|
||||
buffer: s.chars().collect(),
|
||||
buf: s.chars().collect(),
|
||||
cursor: Cursor { offset: 0, pos },
|
||||
}
|
||||
}
|
||||
@ -112,12 +112,12 @@ impl Reader {
|
||||
|
||||
/// Returns true if the reader has read all the buffer, false otherwise.
|
||||
pub fn is_eof(&self) -> bool {
|
||||
self.cursor.offset == self.buffer.len()
|
||||
self.cursor.offset == self.buf.len()
|
||||
}
|
||||
|
||||
/// Returns the next char from the buffer advancing the internal state.
|
||||
pub fn read(&mut self) -> Option<char> {
|
||||
match self.buffer.get(self.cursor.offset) {
|
||||
match self.buf.get(self.cursor.offset) {
|
||||
None => None,
|
||||
Some(c) => {
|
||||
self.cursor.offset += 1;
|
||||
@ -147,14 +147,15 @@ impl Reader {
|
||||
}
|
||||
|
||||
/// Returns chars from the buffer while `predicate` is true, advancing the internal state.
|
||||
pub fn read_while(&mut self, predicate: fn(&char) -> bool) -> String {
|
||||
pub fn read_while(&mut self, predicate: fn(char) -> bool) -> String {
|
||||
let mut s = String::new();
|
||||
loop {
|
||||
match self.peek() {
|
||||
None => return s,
|
||||
Some(c) => {
|
||||
if predicate(&c) {
|
||||
s.push(self.read().unwrap());
|
||||
if predicate(c) {
|
||||
_ = self.read();
|
||||
s.push(c);
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
@ -163,39 +164,38 @@ impl Reader {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the next char from the buffer without advancing the internal state.
|
||||
pub fn peek(&self) -> Option<char> {
|
||||
self.buffer.get(self.cursor.offset).copied()
|
||||
/// Reads a string from a `start` position to the current position (excluded).
|
||||
///
|
||||
/// This method doesn't modify the read index since we're reading "backwards" to the current
|
||||
/// read index.
|
||||
pub fn read_from(&self, start: usize) -> String {
|
||||
let end = self.cursor.offset;
|
||||
self.buf[start..end].iter().collect()
|
||||
}
|
||||
|
||||
/// Returns the next char ignoring whitespace without advancing the internal state.
|
||||
pub fn peek_ignoring_whitespace(&self) -> Option<char> {
|
||||
/// Peeks the next char from the buffer without advancing the internal state.
|
||||
pub fn peek(&self) -> Option<char> {
|
||||
self.buf.get(self.cursor.offset).copied()
|
||||
}
|
||||
|
||||
/// Peeks the next char that meet a `predicate`.
|
||||
pub fn peek_if(&self, predicate: fn(char) -> bool) -> Option<char> {
|
||||
let mut i = self.cursor.offset;
|
||||
loop {
|
||||
if let Some(c) = self.buffer.get(i).copied() {
|
||||
if c != ' ' && c != '\t' && c != '\n' && c != '\r' {
|
||||
return Some(c);
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
let &c = self.buf.get(i)?;
|
||||
if predicate(c) {
|
||||
return Some(c);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a string of `count` char without advancing the internal state.
|
||||
/// Peeks a string of `count` char without advancing the internal state.
|
||||
/// This methods can return less than `count` chars if there is not enough chars in the buffer.
|
||||
pub fn peek_n(&self, count: usize) -> String {
|
||||
let start = self.cursor.offset;
|
||||
let end = (start + count).min(self.buffer.len());
|
||||
self.buffer[start..end].iter().collect()
|
||||
}
|
||||
|
||||
/// Reads a string backward from a `start` position to the current position (excluded), without
|
||||
/// resetting the internal state.
|
||||
pub fn peek_back(&self, start: usize) -> String {
|
||||
let end = self.cursor.offset;
|
||||
self.buffer[start..end].iter().collect()
|
||||
let end = (start + count).min(self.buf.len());
|
||||
self.buf[start..end].iter().collect()
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,7 +233,7 @@ mod tests {
|
||||
assert_eq!(reader.read(), Some('d'));
|
||||
assert_eq!(reader.read(), Some('e'));
|
||||
assert_eq!(reader.peek(), Some('f'));
|
||||
assert_eq!(reader.peek_back(3), "de");
|
||||
assert_eq!(reader.read_from(3), "de");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -280,4 +280,16 @@ mod tests {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn peek_ignoring_whitespace() {
|
||||
fn is_whitespace(c: char) -> bool {
|
||||
c == ' ' || c == '\t'
|
||||
}
|
||||
let reader = Reader::new("\t\t\tabc");
|
||||
assert_eq!(reader.peek_if(|c| !is_whitespace(c)), Some('a'));
|
||||
|
||||
let reader = Reader::new("foo");
|
||||
assert_eq!(reader.peek_if(|c| !is_whitespace(c)), Some('f'));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user