From 142ab0db2902a42b1c11f9682d366a5c7750c649 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 3 Apr 2024 21:43:46 +0200 Subject: driver: parse: replace nom with peg The PEG-based parser is much more concise and easier to understand than the old combinator solution. --- crates/driver/Cargo.toml | 2 +- crates/driver/src/context.rs | 4 +- crates/driver/src/parse.rs | 120 ++++++++++++++++--------------------------- 3 files changed, 48 insertions(+), 78 deletions(-) (limited to 'crates') 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(tag: rule<()>, value: rule) -> 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(<":">, )? { + 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, F>(f: F, input: I) -> Result> -where - I: InputLength, - F: Parser, -{ - 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::*; -- cgit v1.2.3