Use combinator in jsonpath parser.

This commit is contained in:
Jean-Christophe Amiel 2024-06-30 15:37:37 +02:00
parent 89f7313ce6
commit e07470c326
No known key found for this signature in database
GPG Key ID: 07FF11CFD55356CC
5 changed files with 31 additions and 84 deletions

View File

@ -1,68 +0,0 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2024 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
use super::error::*;
use super::{ParseFunc, ParseResult};
use hurl_core::reader::Reader;
pub fn zero_or_more<T>(f: ParseFunc<T>, p: &mut Reader) -> ParseResult<Vec<T>> {
let _start = p.state;
let mut v: Vec<T> = Vec::new();
loop {
let initial_state = p.state;
if p.is_eof() {
return Ok(v);
}
match f(p) {
Ok(r) => {
v.push(r);
}
Err(e) => {
return if e.recoverable {
p.state.pos = initial_state.pos;
p.state.cursor = initial_state.cursor;
Ok(v)
} else {
Err(e)
};
}
}
}
}
/// Tries to apply the list of parser functions `fs` until one of them succeeds.
/// Typically this should be recoverable
pub fn choice<T>(fs: &[ParseFunc<T>], reader: &mut Reader) -> ParseResult<T> {
for (pos, f) in fs.iter().enumerate() {
let start = reader.state;
if pos == fs.len() - 1 {
return f(reader);
}
match f(reader) {
Err(ParseError {
recoverable: true, ..
}) => {
reader.state = start;
continue;
}
x => return x,
}
}
panic!("You can't call choice with an empty vector of choice")
}

View File

@ -18,6 +18,8 @@
use hurl_core::reader::Pos;
pub type ParseResult<T> = Result<T, ParseError>;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParseError {
pub pos: Pos,
@ -39,3 +41,23 @@ impl ParseError {
pub enum ParseErrorKind {
Expecting(String),
}
impl hurl_core::combinator::ParseError for ParseError {
fn is_recoverable(&self) -> bool {
self.recoverable
}
fn to_recoverable(self) -> Self {
ParseError {
recoverable: true,
..self
}
}
fn to_non_recoverable(self) -> Self {
ParseError {
recoverable: false,
..self
}
}
}

View File

@ -15,16 +15,8 @@
* limitations under the License.
*
*/
use error::ParseError;
use hurl_core::reader::Reader;
pub type ParseResult<T> = Result<T, ParseError>;
pub type ParseFunc<T> = fn(&mut Reader) -> ParseResult<T>;
pub use self::parse::parse;
mod combinators;
mod error;
mod parse;
mod primitives;

View File

@ -15,11 +15,12 @@
* limitations under the License.
*
*/
use super::super::ast::*;
use super::combinators::*;
use super::error::{ParseError, ParseErrorKind};
use super::primitives::*;
use super::ParseResult;
use crate::jsonpath::ast::{Predicate, PredicateFunc, Query, Selector, Slice};
use crate::jsonpath::parser::error::{ParseError, ParseErrorKind, ParseResult};
use crate::jsonpath::parser::primitives::{
integer, key_name, key_path, literal, natural, number, string_value, try_literal, whitespace,
};
use hurl_core::combinator::{choice, zero_or_more};
use hurl_core::reader::Reader;
pub fn parse(s: &str) -> Result<Query, ParseError> {
@ -277,6 +278,7 @@ fn equal_string_predicate_func(reader: &mut Reader) -> ParseResult<PredicateFunc
#[cfg(test)]
mod tests {
use crate::jsonpath::ast::Number;
use hurl_core::reader::Pos;
// tests from https://cburgmer.github.io/json-path-comparison
use super::*;

View File

@ -15,9 +15,8 @@
* limitations under the License.
*
*/
use super::super::ast::*;
use super::error::{ParseError, ParseErrorKind};
use super::ParseResult;
use crate::jsonpath::ast::Number;
use crate::jsonpath::parser::error::{ParseError, ParseErrorKind, ParseResult};
use hurl_core::reader::Reader;
pub fn natural(reader: &mut Reader) -> ParseResult<usize> {