summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--Cargo.lock45
-rw-r--r--crates/driver/Cargo.toml2
-rw-r--r--crates/driver/src/context.rs29
-rw-r--r--crates/driver/src/main.rs1
-rw-r--r--crates/driver/src/parse.rs71
5 files changed, 101 insertions, 47 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fffbaf8..127dc2a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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()
+}