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 | |
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.
-rw-r--r-- | Cargo.lock | 45 | ||||
-rw-r--r-- | crates/driver/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/driver/src/context.rs | 29 | ||||
-rw-r--r-- | crates/driver/src/main.rs | 1 | ||||
-rw-r--r-- | crates/driver/src/parse.rs | 71 |
5 files changed, 101 insertions, 47 deletions
@@ -3,15 +3,6 @@ version = 3 [[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] name = "arrayref" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -371,6 +362,12 @@ dependencies = [ ] [[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] name = "nix" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -384,6 +381,17 @@ dependencies = [ ] [[package]] +name = "nom" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +dependencies = [ + "memchr", + "minimal-lexical", + "version_check", +] + +[[package]] name = "olpc-cjson" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -511,9 +519,9 @@ dependencies = [ "indoc", "lazy_static", "nix", + "nom", "rebel-common", "rebel-runner", - "regex", "scoped-tls-hkt", "serde", "serde_yaml", @@ -558,23 +566,6 @@ dependencies = [ ] [[package]] -name = "regex" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/crates/driver/Cargo.toml b/crates/driver/Cargo.toml index 36afe9f..9913a83 100644 --- a/crates/driver/Cargo.toml +++ b/crates/driver/Cargo.toml @@ -18,7 +18,7 @@ handlebars = "4.1.3" indoc = "1.0.3" lazy_static = "1.4.0" nix = "0.23.0" -regex = "1.5.4" +nom = "7.1.0" scoped-tls-hkt = "0.1.2" serde = { version = "1", features = ["derive", "rc"] } serde_yaml = "0.8" diff --git a/crates/driver/src/context.rs b/crates/driver/src/context.rs index ccb8581..bd8d985 100644 --- a/crates/driver/src/context.rs +++ b/crates/driver/src/context.rs @@ -8,16 +8,13 @@ use std::{ result, }; -use lazy_static::lazy_static; -use regex::Regex; - use common::{ error::{self, Contextualizable}, string_hash::ArchiveHash, types::TaskID, }; -use crate::{args::*, paths, pin::Pins, task::*}; +use crate::{args::*, parse, paths, pin::Pins, task::*}; #[derive(Debug, Clone, Copy)] pub enum ErrorKind<'ctx> { @@ -347,16 +344,10 @@ impl Context { } pub fn parse<'ctx>(&'ctx self, s: &str) -> error::Result<TaskRef> { - lazy_static! { - static ref RE: Regex = Regex::new( - r"^(?P<recipe>[[:word:]-]+):(?P<task>[[:word:]-]+)(?:/(?P<host>[[:word:]-]+)?(?::(?P<target>[[:word:]-]+))?)?$", - ).unwrap(); - } - - let cap = RE.captures(s).context("Invalid task syntax")?; + let parsed = parse::parse_task(s).context("Invalid task syntax")?; - let recipe = cap["recipe"].to_string(); - let task = cap["task"].to_string(); + let recipe = parsed.recipe.to_string(); + let task = parsed.task.to_string(); let id = TaskID { recipe, task }; let (ctx_id, _) = self @@ -366,19 +357,19 @@ impl Context { let mut args = self.globals.clone(); - if let Some(host) = cap.name("host") { + if let Some(host) = parsed.host { let plat = self .platforms - .get(host.as_str()) - .with_context(|| format!("Platform '{}' not found", host.as_str()))?; + .get(host) + .with_context(|| format!("Platform '{}' not found", host))?; args.set("host", Some(plat)); args.set("target", Some(plat)); } - if let Some(target) = cap.name("target") { + if let Some(target) = parsed.target { let plat = self .platforms - .get(target.as_str()) - .with_context(|| format!("Platform '{}' not found", target.as_str()))?; + .get(target) + .with_context(|| format!("Platform '{}' not found", target))?; args.set("target", Some(plat)); } diff --git a/crates/driver/src/main.rs b/crates/driver/src/main.rs index fe9204a..0e5c629 100644 --- a/crates/driver/src/main.rs +++ b/crates/driver/src/main.rs @@ -1,6 +1,7 @@ mod args; mod context; mod driver; +mod parse; mod paths; mod pin; mod recipe; 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() +} |