summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2024-04-03 21:43:46 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2024-04-03 22:31:14 +0200
commit142ab0db2902a42b1c11f9682d366a5c7750c649 (patch)
treef090807ba019a31ad963246159c3cd1b8cc842d1
parent42e667a5086fa4a6557ef7a64e40b833a93f3124 (diff)
downloadrebel-142ab0db2902a42b1c11f9682d366a5c7750c649.tar
rebel-142ab0db2902a42b1c11f9682d366a5c7750c649.zip
driver: parse: replace nom with peg
The PEG-based parser is much more concise and easier to understand than the old combinator solution.
-rw-r--r--Cargo.lock45
-rw-r--r--crates/driver/Cargo.toml2
-rw-r--r--crates/driver/src/context.rs4
-rw-r--r--crates/driver/src/parse.rs120
4 files changed, 76 insertions, 95 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 05d10af..605a95b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -360,12 +360,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[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.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -378,16 +372,6 @@ dependencies = [
]
[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
-[[package]]
name = "olpc-cjson"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -405,6 +389,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
+name = "peg"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "400bcab7d219c38abf8bd7cc2054eb9bbbd4312d66f6a5557d572a203f646f61"
+dependencies = [
+ "peg-macros",
+ "peg-runtime",
+]
+
+[[package]]
+name = "peg-macros"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46e61cce859b76d19090f62da50a9fe92bab7c2a5f09e183763559a2ac392c90"
+dependencies = [
+ "peg-runtime",
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "peg-runtime"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36bae92c60fa2398ce4678b98b2c4b5a7c61099961ca1fa305aec04a9ad28922"
+
+[[package]]
name = "pest"
version = "2.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -478,7 +489,7 @@ dependencies = [
"indoc",
"lazy_static",
"nix",
- "nom",
+ "peg",
"rebel-common",
"rebel-runner",
"scoped-tls-hkt",
diff --git a/crates/driver/Cargo.toml b/crates/driver/Cargo.toml
index 683ebbe..673e0ba 100644
--- a/crates/driver/Cargo.toml
+++ b/crates/driver/Cargo.toml
@@ -18,8 +18,8 @@ handlebars = "5.1.2"
indoc = "2.0.4"
lazy_static = "1.4.0"
nix = { version = "0.28.0", features = ["poll"] }
-nom = "7.1.0"
scoped-tls-hkt = "0.1.2"
serde = { version = "1", features = ["derive", "rc"] }
serde_yaml = "0.9"
walkdir = "2"
+peg = "0.8.2"
diff --git a/crates/driver/src/context.rs b/crates/driver/src/context.rs
index 47259b3..4698171 100644
--- a/crates/driver/src/context.rs
+++ b/crates/driver/src/context.rs
@@ -355,7 +355,9 @@ impl Context {
}
pub fn parse(&self, s: &str) -> error::Result<(TaskRef, TaskFlags)> {
- let (parsed, flags) = parse::parse_task_with_flags(s).context("Invalid task syntax")?;
+ let (parsed, flags) = parse::task_with_flags(s)
+ .ok()
+ .context("Invalid task syntax")?;
let recipe = parsed.id.recipe.to_string();
let task = parsed.id.task.to_string();
diff --git a/crates/driver/src/parse.rs b/crates/driver/src/parse.rs
index df540fc..f71fd18 100644
--- a/crates/driver/src/parse.rs
+++ b/crates/driver/src/parse.rs
@@ -1,10 +1,3 @@
-use nom::{
- bytes::complete::{tag, take_while1},
- combinator::{all_consuming, opt},
- error::ParseError,
- Err, IResult, InputLength, Parser,
-};
-
#[derive(Debug, Clone, Copy)]
pub struct TaskID<'a> {
pub recipe: &'a str,
@@ -28,74 +21,49 @@ pub struct TaskFlags {
pub force_run: bool,
}
-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, TaskID> {
- let (input, recipe) = name(input)?;
- let (input, _) = tag(":")(input)?;
- let (input, task) = name(input)?;
- Ok((input, TaskID { 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, TaskArgs> {
- let (input, _) = tag("/")(input)?;
- let (input, host) = opt(name)(input)?;
- let (input, target) = opt(task_arg_target)(input)?;
-
- Ok((input, TaskArgs { host, target }))
-}
-
-fn task(input: &str) -> IResult<&str, Task> {
- let (input, id) = task_id(input)?;
- let (input, args) = opt(task_args)(input)?;
-
- Ok((
- input,
- Task {
- id,
- args: args.unwrap_or_default(),
- },
- ))
-}
-
-fn task_flags(input: &str) -> IResult<&str, TaskFlags> {
- let (input, force_run) = opt(tag("+"))(input)?;
-
- Ok((
- input,
- TaskFlags {
- force_run: force_run.is_some(),
- },
- ))
+peg::parser! {
+ grammar rules() for str {
+ rule t<T>(tag: rule<()>, value: rule<T>) -> T
+ = tag() v:value() { v }
+
+ rule name_char()
+ = ['a'..='z' | 'A' ..='Z' | '0'..='9' | '_' | '-']
+
+ rule name() -> &'input str
+ = $(name_char()+)
+
+ rule task_id() -> TaskID<'input>
+ = recipe:name() ":" task:name() {
+ TaskID { recipe, task }
+ }
+
+ rule task_args() -> TaskArgs<'input>
+ = "/" host:name()? target:t(<":">, <name()>)? {
+ TaskArgs {
+ host,
+ target,
+ }
+ }
+ / { Default::default() }
+
+ pub rule task() -> Task<'input>
+ = id:task_id() args:task_args() {
+ Task {
+ id,
+ args,
+ }
+ }
+
+ rule force_run() -> bool
+ = "+" { true }
+ / { false }
+
+ rule task_flags() -> TaskFlags
+ = force_run:force_run() { TaskFlags { force_run } }
+
+ pub rule task_with_flags() -> (Task<'input>, TaskFlags)
+ = task:task() flags:task_flags() { (task, flags) }
+ }
}
-fn task_with_flags(input: &str) -> IResult<&str, (Task, TaskFlags)> {
- let (input, task) = task(input)?;
- let (input, flags) = task_flags(input)?;
-
- Ok((input, (task, flags)))
-}
-
-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_with_flags(input: &str) -> Option<(Task, TaskFlags)> {
- parse_all(task_with_flags, input).ok()
-}
+pub use rules::*;