summaryrefslogtreecommitdiffstats
path: root/crates/driver/src/parse.rs
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2021-11-05 17:02:26 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2021-11-05 17:02:26 +0100
commit1671d0fbf3b5691f2db44883a0973ec858beaf94 (patch)
tree25120d00b54a443acdeaeb3ec9352cfc88c8d8ee /crates/driver/src/parse.rs
parent3bfca7703c298e3379fde398ea71b5cf082ba5bf (diff)
downloadrebel-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.rs71
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()
+}