Skip to content

Commit

Permalink
Implement Reclass reference parsing
Browse files Browse the repository at this point in the history
The reference parser is implemented with the [nom] library which allows
easily writing parsers through combinator functions. The parser has been
implemented by replicating the grammar supported by the Python parser
(cf. [`get_ref_parser`]). Notably, the combinator functions are named
roughly the same as their corresponding `pyparsing` functions in the
Python implementation.

Note that the Rust implementation doesn't yet support inventory queries
(default syntax `$[...]`). However, the Reclass reference `${...}`
parsing should be compatible with the Python parser including the
extension which allows nested references.

The parser implementation comes with a large amount of unit tests for
edge and corner cases which can appear when working with references.

[nom]: https://docs.rs/nom
[`get_ref_parser`]: https://github.com/kapicorp/reclass/blob/856b34cb77811d665c6346883238d436ac5c4924/reclass/values/parser_funcs.py#L103-L168
  • Loading branch information
simu committed Aug 29, 2023
1 parent 50ca6f3 commit f205831
Show file tree
Hide file tree
Showing 5 changed files with 621 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ name = "reclass_rs"
crate-type = ["cdylib", "rlib"]

[dependencies]
anyhow = "1.0.75"
nom = "7.1.3"
pyo3 = "0.19.2"
serde_json = "1.0.105"
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#![warn(clippy::redundant_closure_for_method_calls)]
#![warn(let_underscore_drop)]

mod refs;

use pyo3::prelude::*;

/// Reclass allows configuring various library behaviors
Expand Down
35 changes: 35 additions & 0 deletions src/refs/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
mod parser;
mod token;

use anyhow::{anyhow, Result};

pub use self::token::Token;

#[allow(unused)]
pub fn parse_ref(input: &str) -> Result<Token> {
use self::parser::parse_ref;
let (uncons, token) =
parse_ref(input).map_err(|e| anyhow!("Error parsing reference: {}", e))?;
if !uncons.is_empty() {
return Err(anyhow!("Failed to parse '{}': trailing {}", input, uncons));
}
Ok(token)
}

#[cfg(test)]
mod test_refs {
use super::*;

#[test]
fn test_parse_ref() {
let input = "foo-${bar:baz}";
let res = parse_ref(input).unwrap();
assert_eq!(
res,
Token::Combined(vec![
Token::Literal("foo-".to_owned()),
Token::Ref(vec![Token::Literal("bar:baz".to_owned())])
])
)
}
}
Loading

0 comments on commit f205831

Please sign in to comment.