diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-11-05 17:02:26 +0100 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-11-05 17:02:26 +0100 |
commit | 1671d0fbf3b5691f2db44883a0973ec858beaf94 (patch) | |
tree | 25120d00b54a443acdeaeb3ec9352cfc88c8d8ee /crates/driver/src/parse.rs | |
parent | 3bfca7703c298e3379fde398ea71b5cf082ba5bf (diff) | |
download | rebel-1671d0fbf3b5691f2db44883a0973ec858beaf94.tar rebel-1671d0fbf3b5691f2db44883a0973ec858beaf94.zip |
driver: replace regex with nom-based parser
For now, the nom-based parser doesn't really reduce complexity, but we
will need a more powerful parsing solution anyways when the task YML is
replaced with a specialized language.
Diffstat (limited to 'crates/driver/src/parse.rs')
-rw-r--r-- | crates/driver/src/parse.rs | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/crates/driver/src/parse.rs b/crates/driver/src/parse.rs new file mode 100644 index 0000000..892b654 --- /dev/null +++ b/crates/driver/src/parse.rs @@ -0,0 +1,71 @@ +use nom::{ + bytes::complete::{tag, take_while1}, + combinator::{all_consuming, opt}, + error::ParseError, + Err, IResult, InputLength, Parser, +}; + +pub struct Output<'a> { + pub recipe: &'a str, + pub task: &'a str, + pub host: Option<&'a str>, + pub target: Option<&'a str>, +} + +fn is_name_char(c: char) -> bool { + matches!(c, 'a'..='z' | 'A' ..='Z' | '0'..='9' | '_' | '-') +} + +fn name(input: &str) -> IResult<&str, &str> { + take_while1(is_name_char)(input) +} + +fn task_id(input: &str) -> IResult<&str, (&str, &str)> { + let (input, recipe) = name(input)?; + let (input, _) = tag(":")(input)?; + let (input, task) = name(input)?; + Ok((input, (recipe, task))) +} + +fn task_arg_target(input: &str) -> IResult<&str, &str> { + let (input, _) = tag(":")(input)?; + let (input, target) = name(input)?; + Ok((input, target)) +} + +fn task_args(input: &str) -> IResult<&str, (Option<&str>, Option<&str>)> { + let (input, _) = tag("/")(input)?; + let (input, host) = opt(name)(input)?; + let (input, target) = opt(task_arg_target)(input)?; + + Ok((input, (host, target))) +} + +fn task_ref(input: &str) -> IResult<&str, Output> { + let (input, (recipe, task)) = task_id(input)?; + let (input, args) = opt(task_args)(input)?; + + let (host, target) = args.unwrap_or_default(); + + Ok(( + input, + Output { + recipe, + task, + host, + target, + }, + )) +} + +fn parse_all<I, O, E: ParseError<I>, F>(f: F, input: I) -> Result<O, Err<E>> +where + I: InputLength, + F: Parser<I, O, E>, +{ + all_consuming(f)(input).map(|(_, result)| result) +} + +pub fn parse_task(input: &str) -> Option<Output> { + parse_all(task_ref, input).ok() +} |