mirror of
https://github.com/loot/loot-condition-interpreter.git
synced 2026-07-27 14:16:09 -07:00
Add parsing of file regex, active regex, many and many_active functions
This commit is contained in:
+70
-5
@@ -1,9 +1,8 @@
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str;
|
||||
|
||||
use nom::{Context, Err, ErrorKind, IResult};
|
||||
use regex::Regex;
|
||||
use nom::IResult;
|
||||
|
||||
use super::Error;
|
||||
|
||||
@@ -32,6 +31,12 @@ pub enum Function {
|
||||
const INVALID_PATH_CHARS: &str = "\":*?<>|\\"; // \ is treated as invalid to distinguish regex strings.
|
||||
const INVALID_REGEX_PATH_CHARS: &str = "\"<>";
|
||||
|
||||
fn parse_regex(input: &str) -> IResult<&str, Regex> {
|
||||
Regex::new(input)
|
||||
.map(|r| ("", r))
|
||||
.map_err(|e| Err::Failure(Context::Code(input, ErrorKind::Custom(1))))
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn eval(&self) -> Result<bool, Error> {
|
||||
// TODO: Handle all variants.
|
||||
@@ -44,15 +49,27 @@ impl Function {
|
||||
|
||||
pub fn parse(input: &str) -> IResult<&str, Function> {
|
||||
// TODO: Handle all variants.
|
||||
// TODO: Paths may not contain :*?"<>|
|
||||
do_parse!(
|
||||
input,
|
||||
function: alt!(
|
||||
function:
|
||||
alt!(
|
||||
delimited!(tag!("file(\""), is_not!(INVALID_PATH_CHARS), tag!("\")")) => {
|
||||
|path| Function::FilePath(PathBuf::from(path))
|
||||
} |
|
||||
delimited!(tag!("file(\""), flat_map!(is_not!(INVALID_REGEX_PATH_CHARS), parse_regex), tag!("\"")) => {
|
||||
|r| Function::FileRegex(r)
|
||||
} |
|
||||
delimited!(tag!("active(\""), is_not!(INVALID_PATH_CHARS), tag!("\")")) => {
|
||||
|path| Function::ActivePath(PathBuf::from(path))
|
||||
} |
|
||||
delimited!(tag!("active(\""), flat_map!(is_not!(INVALID_REGEX_PATH_CHARS), parse_regex), tag!("\"")) => {
|
||||
|r| Function::ActiveRegex(r)
|
||||
} |
|
||||
delimited!(tag!("many(\""), flat_map!(is_not!(INVALID_REGEX_PATH_CHARS), parse_regex), tag!("\"")) => {
|
||||
|r| Function::Many(r)
|
||||
} |
|
||||
delimited!(tag!("many_active(\""), flat_map!(is_not!(INVALID_REGEX_PATH_CHARS), parse_regex), tag!("\"")) => {
|
||||
|r| Function::ManyActive(r)
|
||||
}
|
||||
) >> (function)
|
||||
)
|
||||
@@ -74,7 +91,19 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_parse_should_parse_an_active_function() {
|
||||
fn function_parse_should_parse_a_file_regex_function() {
|
||||
let result = Function::parse("file(\"Cargo.*\")").unwrap().1;
|
||||
|
||||
match result {
|
||||
Function::FileRegex(r) => {
|
||||
assert_eq!(Regex::new("Cargo.*").unwrap().as_str(), r.as_str())
|
||||
}
|
||||
_ => panic!("Expected a file regex function"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_parse_should_parse_an_active_path_function() {
|
||||
let result = Function::parse("active(\"Cargo.toml\")").unwrap().1;
|
||||
|
||||
match result {
|
||||
@@ -83,6 +112,42 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_parse_should_parse_an_active_regex_function() {
|
||||
let result = Function::parse("active(\"Cargo.*\")").unwrap().1;
|
||||
|
||||
match result {
|
||||
Function::ActiveRegex(r) => {
|
||||
assert_eq!(Regex::new("Cargo.*").unwrap().as_str(), r.as_str())
|
||||
}
|
||||
_ => panic!("Expected an active regex function"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_parse_should_parse_a_many_function() {
|
||||
let result = Function::parse("many(\"Cargo.*\")").unwrap().1;
|
||||
|
||||
match result {
|
||||
Function::Many(r) => {
|
||||
assert_eq!(Regex::new("Cargo.*").unwrap().as_str(), r.as_str())
|
||||
}
|
||||
_ => panic!("Expected a many function"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_parse_should_parse_a_many_active_function() {
|
||||
let result = Function::parse("many_active(\"Cargo.*\")").unwrap().1;
|
||||
|
||||
match result {
|
||||
Function::ManyActive(r) => {
|
||||
assert_eq!(Regex::new("Cargo.*").unwrap().as_str(), r.as_str())
|
||||
}
|
||||
_ => panic!("Expected a many active function"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_file_path_eval_should_return_true_if_the_file_exists_relative_to_the_data_path() {
|
||||
let function = Function::FilePath(PathBuf::from("Cargo.toml"));
|
||||
|
||||
+9
-12
@@ -114,8 +114,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn expression_parse_should_handle_a_single_compound_condition() {
|
||||
let result = Expression::parse("file(\"Cargo.toml\")")
|
||||
.unwrap().1;
|
||||
let result = Expression::parse("file(\"Cargo.toml\")").unwrap().1;
|
||||
|
||||
match result.0.as_slice() {
|
||||
[CompoundCondition(_)] => {}
|
||||
@@ -126,7 +125,8 @@ mod tests {
|
||||
#[test]
|
||||
fn expression_parse_should_handle_multiple_compound_conditions() {
|
||||
let result = Expression::parse("file(\"Cargo.toml\") or file(\"Cargo.toml\")")
|
||||
.unwrap().1;
|
||||
.unwrap()
|
||||
.1;
|
||||
|
||||
match result.0.as_slice() {
|
||||
[CompoundCondition(_), CompoundCondition(_)] => {}
|
||||
@@ -139,8 +139,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn compound_condition_parse_should_handle_a_single_condition() {
|
||||
let result = CompoundCondition::parse("file(\"Cargo.toml\")")
|
||||
.unwrap().1;
|
||||
let result = CompoundCondition::parse("file(\"Cargo.toml\")").unwrap().1;
|
||||
|
||||
match result.0.as_slice() {
|
||||
[Condition::Function(Function::FilePath(f))] => {
|
||||
@@ -156,7 +155,8 @@ mod tests {
|
||||
#[test]
|
||||
fn compound_condition_parse_should_handle_multiple_conditions() {
|
||||
let result = CompoundCondition::parse("file(\"Cargo.toml\") and file(\"README.md\")")
|
||||
.unwrap().1;
|
||||
.unwrap()
|
||||
.1;
|
||||
|
||||
match result.0.as_slice() {
|
||||
[Condition::Function(Function::FilePath(f1)), Condition::Function(Function::FilePath(f2))] =>
|
||||
@@ -173,8 +173,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn condition_parse_should_handle_a_function() {
|
||||
let result = Condition::parse("file(\"Cargo.toml\")")
|
||||
.unwrap().1;
|
||||
let result = Condition::parse("file(\"Cargo.toml\")").unwrap().1;
|
||||
|
||||
match result {
|
||||
Condition::Function(Function::FilePath(f)) => {
|
||||
@@ -189,8 +188,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn condition_parse_should_handle_a_inverted_function() {
|
||||
let result = Condition::parse("not file(\"Cargo.toml\")")
|
||||
.unwrap().1;
|
||||
let result = Condition::parse("not file(\"Cargo.toml\")").unwrap().1;
|
||||
|
||||
match result {
|
||||
Condition::InvertedFunction(Function::FilePath(f)) => {
|
||||
@@ -205,8 +203,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn condition_parse_should_handle_an_expression_in_parentheses() {
|
||||
let result = Condition::parse("(not file(\"Cargo.toml\"))")
|
||||
.unwrap().1;
|
||||
let result = Condition::parse("(not file(\"Cargo.toml\"))").unwrap().1;
|
||||
|
||||
match result {
|
||||
Condition::Expression(_) => {}
|
||||
|
||||
Reference in New Issue
Block a user