summaryrefslogtreecommitdiffstats
path: root/crates
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
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')
-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
4 files changed, 83 insertions, 20 deletions
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()
+}