mirror of
https://github.com/loot/loot-condition-interpreter.git
synced 2026-07-27 14:16:09 -07:00
Add parsing of version and checksum conditions
This commit is contained in:
+102
-8
@@ -1,12 +1,12 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::str;
|
||||
|
||||
use nom::{Context, Err, ErrorKind, IResult};
|
||||
use nom::{hex_digit, Context, Err, ErrorKind, IResult};
|
||||
use regex::Regex;
|
||||
|
||||
use super::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ComparisonOperator {
|
||||
Equal,
|
||||
NotEqual,
|
||||
@@ -16,6 +16,23 @@ pub enum ComparisonOperator {
|
||||
GreaterThanOrEqual,
|
||||
}
|
||||
|
||||
impl ComparisonOperator {
|
||||
pub fn parse(input: &str) -> IResult<&str, ComparisonOperator> {
|
||||
do_parse!(
|
||||
input,
|
||||
operator:
|
||||
alt!(
|
||||
tag!("==") => { |_| ComparisonOperator::Equal } |
|
||||
tag!("!=") => { |_| ComparisonOperator::NotEqual } |
|
||||
tag!("<") => { |_| ComparisonOperator::LessThan } |
|
||||
tag!(">") => { |_| ComparisonOperator::GreaterThan } |
|
||||
tag!("<=") => { |_| ComparisonOperator::LessThanOrEqual } |
|
||||
tag!(">=") => { |_| ComparisonOperator::GreaterThanOrEqual }
|
||||
) >> (operator)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Function {
|
||||
FilePath(PathBuf),
|
||||
@@ -31,10 +48,47 @@ pub enum Function {
|
||||
const INVALID_PATH_CHARS: &str = "\":*?<>|\\"; // \ is treated as invalid to distinguish regex strings.
|
||||
const INVALID_REGEX_PATH_CHARS: &str = "\"<>";
|
||||
|
||||
const PARSE_REGEX_ERROR: ErrorKind = ErrorKind::Custom(1);
|
||||
const PARSE_CRC_ERROR: ErrorKind = ErrorKind::Custom(2);
|
||||
|
||||
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))))
|
||||
.map_err(|_| Err::Failure(Context::Code(input, PARSE_REGEX_ERROR)))
|
||||
}
|
||||
|
||||
fn parse_version_args(input: &str) -> IResult<&str, (PathBuf, &str, ComparisonOperator)> {
|
||||
do_parse!(
|
||||
input,
|
||||
tag!("\"")
|
||||
>> path: is_not!(INVALID_PATH_CHARS)
|
||||
>> tag!("\"")
|
||||
>> ws!(tag!(","))
|
||||
>> tag!("\"")
|
||||
>> version: is_not!("\"")
|
||||
>> tag!("\"")
|
||||
>> ws!(tag!(","))
|
||||
>> operator: call!(ComparisonOperator::parse)
|
||||
>> ((PathBuf::from(path), version, operator))
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_crc(input: &str) -> IResult<&str, u32> {
|
||||
u32::from_str_radix(input, 16)
|
||||
.map(|c| ("", c))
|
||||
.map_err(|_| Err::Failure(Context::Code(input, PARSE_CRC_ERROR)))
|
||||
}
|
||||
|
||||
fn parse_checksum_args(input: &str) -> IResult<&str, (PathBuf, u32)> {
|
||||
do_parse!(
|
||||
input,
|
||||
tag!("\"")
|
||||
>> path: is_not!(INVALID_PATH_CHARS)
|
||||
>> tag!("\"")
|
||||
>> ws!(tag!(","))
|
||||
>> crc: flat_map!(call!(hex_digit), parse_crc)
|
||||
>> ((PathBuf::from(path), crc))
|
||||
)
|
||||
}
|
||||
|
||||
impl Function {
|
||||
@@ -48,7 +102,6 @@ impl Function {
|
||||
}
|
||||
|
||||
pub fn parse(input: &str) -> IResult<&str, Function> {
|
||||
// TODO: Handle all variants.
|
||||
do_parse!(
|
||||
input,
|
||||
function:
|
||||
@@ -70,6 +123,14 @@ impl Function {
|
||||
} |
|
||||
delimited!(tag!("many_active(\""), flat_map!(is_not!(INVALID_REGEX_PATH_CHARS), parse_regex), tag!("\"")) => {
|
||||
|r| Function::ManyActive(r)
|
||||
} |
|
||||
delimited!(tag!("version("), call!(parse_version_args), tag!(")")) => {
|
||||
|(path, version, comparator): (PathBuf, &str, ComparisonOperator)| {
|
||||
Function::Version(path, version.to_string(), comparator)
|
||||
}
|
||||
} |
|
||||
delimited!(tag!("checksum("), call!(parse_checksum_args), tag!(")")) => {
|
||||
|(path, crc)| Function::Checksum(path, crc)
|
||||
}
|
||||
) >> (function)
|
||||
)
|
||||
@@ -80,12 +141,14 @@ impl Function {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
fn function_parse_should_parse_a_file_path_function() {
|
||||
let result = Function::parse("file(\"Cargo.toml\")").unwrap().1;
|
||||
|
||||
match result {
|
||||
Function::FilePath(f) => assert_eq!(PathBuf::from("Cargo.toml"), f),
|
||||
Function::FilePath(f) => assert_eq!(Path::new("Cargo.toml"), f),
|
||||
_ => panic!("Expected a file path function"),
|
||||
}
|
||||
}
|
||||
@@ -107,7 +170,7 @@ mod tests {
|
||||
let result = Function::parse("active(\"Cargo.toml\")").unwrap().1;
|
||||
|
||||
match result {
|
||||
Function::ActivePath(f) => assert_eq!(PathBuf::from("Cargo.toml"), f),
|
||||
Function::ActivePath(f) => assert_eq!(Path::new("Cargo.toml"), f),
|
||||
_ => panic!("Expected an active path function"),
|
||||
}
|
||||
}
|
||||
@@ -131,7 +194,7 @@ mod tests {
|
||||
match result {
|
||||
Function::Many(r) => {
|
||||
assert_eq!(Regex::new("Cargo.*").unwrap().as_str(), r.as_str())
|
||||
}
|
||||
},
|
||||
_ => panic!("Expected a many function"),
|
||||
}
|
||||
}
|
||||
@@ -148,6 +211,37 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_parse_should_parse_a_checksum_function() {
|
||||
let result = Function::parse("checksum(\"Cargo.toml\", DEADBEEF)")
|
||||
.unwrap()
|
||||
.1;
|
||||
|
||||
match result {
|
||||
Function::Checksum(path, crc) => {
|
||||
assert_eq!(Path::new("Cargo.toml"), path);
|
||||
assert_eq!(0xDEADBEEF, crc);
|
||||
}
|
||||
_ => panic!("Expected a checksum function"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_parse_should_parse_a_version_equals_function() {
|
||||
let result = Function::parse("version(\"Cargo.toml\", \"1.2\", ==)")
|
||||
.unwrap()
|
||||
.1;
|
||||
|
||||
match result {
|
||||
Function::Version(path, version, comparator) => {
|
||||
assert_eq!(Path::new("Cargo.toml"), path);
|
||||
assert_eq!("1.2", version);
|
||||
assert_eq!(ComparisonOperator::Equal, comparator);
|
||||
}
|
||||
_ => panic!("Expected a checksum 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"));
|
||||
|
||||
Reference in New Issue
Block a user