Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Couple of misc refactors #959

Merged
merged 4 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions src/sudoers/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ impl Sudo {
/// | #<numerical id>
/// ```
impl Parse for Identifier {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
if accept_if(|c| c == '#', stream).is_some() {
let Digits(guid) = expect_nonterminal(stream)?;
make(Identifier::ID(guid))
Expand All @@ -219,7 +219,7 @@ impl Many for Identifier {}
/// This computes the correct negation with multiple exclamation marks in the parsing stage so we
/// are not bothered by it later.
impl<T: Parse + UserFriendly> Parse for Qualified<T> {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
if is_syntax('!', stream)? {
let mut neg = true;
while is_syntax('!', stream)? {
Expand All @@ -245,7 +245,7 @@ impl<T: Many> Many for Qualified<T> {

/// Helper function for parsing `Meta<T>` things where T is not a token
fn parse_meta<T: Parse>(
stream: &mut impl CharStream,
stream: &mut CharStream,
embed: impl FnOnce(SudoString) -> T,
) -> Parsed<Meta<T>> {
if let Some(meta) = try_nonterminal(stream)? {
Expand All @@ -261,7 +261,7 @@ fn parse_meta<T: Parse>(

/// Since Identifier is not a token, add the parser for `Meta<Identifier>`
impl Parse for Meta<Identifier> {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
parse_meta(stream, Identifier::Name)
}
}
Expand All @@ -274,7 +274,7 @@ impl Parse for Meta<Identifier> {
/// | +netgroup
/// ```
impl Parse for UserSpecifier {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
let userspec = if accept_if(|c| c == '%', stream).is_some() {
let ctor = if accept_if(|c| c == ':', stream).is_some() {
UserSpecifier::NonunixGroup
Expand All @@ -299,7 +299,7 @@ impl Many for UserSpecifier {}

/// UserSpecifier is not a token, implement the parser for `Meta<UserSpecifier>`
impl Parse for Meta<UserSpecifier> {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
parse_meta(stream, |name| UserSpecifier::User(Identifier::Name(name)))
}
}
Expand All @@ -309,7 +309,7 @@ impl Parse for Meta<UserSpecifier> {
/// runas = "(", userlist, (":", grouplist?)?, ")"
/// ```
impl Parse for RunAs {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
try_syntax('(', stream)?;
let users = try_nonterminal(stream).unwrap_or_default();
let groups = maybe(try_syntax(':', stream).and_then(|_| try_nonterminal(stream)))?
Expand All @@ -336,7 +336,7 @@ pub type Modifier = Box<dyn Fn(&mut Tag)>;
// to be more general, we impl Parse for Meta<Tag> so a future tag like "AFOOBAR" can be added with no problem

impl Parse for MetaOrTag {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
use Meta::*;

let start_pos = stream.get_pos();
Expand Down Expand Up @@ -402,7 +402,7 @@ impl Parse for MetaOrTag {
/// commandspec = [tag modifiers]*, command
/// ```
impl Parse for CommandSpec {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
let mut tags = vec![];
while let Some(MetaOrTag(keyword)) = try_nonterminal(stream)? {
use Qualified::Allow;
Expand Down Expand Up @@ -450,7 +450,7 @@ impl Parse for CommandSpec {
/// (host,runas,commandspec) = hostlist, "=", [runas?, commandspec]+
/// ```
impl Parse for (SpecList<Hostname>, Vec<(Option<RunAs>, CommandSpec)>) {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
let hosts = try_nonterminal(stream)?;
expect_syntax('=', stream)?;
let runas_cmds = expect_nonterminal(stream)?;
Expand All @@ -471,7 +471,7 @@ impl Many for (SpecList<Hostname>, Vec<(Option<RunAs>, CommandSpec)>) {
/// (runas,commandspec) = runas?, commandspec
/// ```
impl Parse for (Option<RunAs>, CommandSpec) {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
let runas: Option<RunAs> = try_nonterminal(stream)?;
let cmd = if runas.is_some() {
expect_nonterminal(stream)?
Expand Down Expand Up @@ -502,7 +502,7 @@ impl Parse for Sudo {
// "User_Alias, user machine = command"
// but accept:
// "user, User_Alias machine = command"; this does the same
fn parse(stream: &mut impl CharStream) -> Parsed<Sudo> {
fn parse(stream: &mut CharStream) -> Parsed<Sudo> {
if accept_if(|c| c == '@', stream).is_some() {
return parse_include(stream);
}
Expand Down Expand Up @@ -553,8 +553,8 @@ impl Parse for Sudo {
}

/// Parse the include/include dir part that comes after the '#' or '@' prefix symbol
fn parse_include(stream: &mut impl CharStream) -> Parsed<Sudo> {
fn get_path(stream: &mut impl CharStream) -> Parsed<String> {
fn parse_include(stream: &mut CharStream) -> Parsed<Sudo> {
fn get_path(stream: &mut CharStream) -> Parsed<String> {
if accept_if(|c| c == '"', stream).is_some() {
let QuotedInclude(path) = expect_nonterminal(stream)?;
expect_syntax('"', stream)?;
Expand Down Expand Up @@ -593,7 +593,7 @@ where
T: UserFriendly,
Meta<T>: Parse + Many,
{
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
let begin_pos = stream.get_pos();
let AliasName(name) = try_nonterminal(stream)?;
if name == "ALL" {
Expand All @@ -615,7 +615,7 @@ impl<T> Many for Def<T> {

fn get_directive(
perhaps_keyword: &Spec<UserSpecifier>,
stream: &mut impl CharStream,
stream: &mut CharStream,
) -> Parsed<Directive> {
use super::ast::Directive::*;
use super::ast::Meta::*;
Expand All @@ -640,7 +640,7 @@ fn get_directive(
/// parameter = name [+-]?= ...
/// ```
impl Parse for defaults::SettingsModifier {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
let id_pos = stream.get_pos();

// Parse multiple entries enclosed in quotes (for list-like Defaults-settings)
Expand Down
44 changes: 22 additions & 22 deletions src/sudoers/basic_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//!
//! ```ignore
//! impl<T: Parse> Parse for LinkedList<T> {
//! fn parse(stream: &mut impl CharStream) -> Parsed<LinkedList<T>> {
//! fn parse(stream: &mut CharStream) -> Parsed<LinkedList<T>> {
//! let x = try_nonterminal(stream)?;
//! let mut tail = if is_syntax('+', stream)? {
//! expect_nonterminal(stream)?
Expand Down Expand Up @@ -77,7 +77,7 @@ pub use super::char_stream::CharStream;
/// advanced beyond the accepted part of the input. i.e. if some input is consumed the method
/// *MUST* be producing a `Some` value.
pub trait Parse {
fn parse(stream: &mut impl CharStream) -> Parsed<Self>
fn parse(stream: &mut CharStream) -> Parsed<Self>
where
Self: Sized;
}
Expand All @@ -87,7 +87,7 @@ pub trait Parse {
/// (this can facilitate an easy switch to a different method of stream representation in the future).
/// Unlike `Parse` implementations this *does not* consume trailing whitespace.
/// This function is modelled on `next_if` on `std::Peekable`.
pub fn accept_if(predicate: impl Fn(char) -> bool, stream: &mut impl CharStream) -> Option<char> {
pub fn accept_if(predicate: impl Fn(char) -> bool, stream: &mut CharStream) -> Option<char> {
let c = stream.peek()?;
if predicate(c) {
stream.advance();
Expand All @@ -110,7 +110,7 @@ struct Comment;
/// Accept zero or more whitespace characters; fails if the whitespace is not "leading" to something
/// (which can be used to detect end-of-input).
impl Parse for LeadingWhitespace {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
let eat_space = |stream: &mut _| accept_if(|c| "\t ".contains(c), stream);
while eat_space(stream).is_some() {}

Expand All @@ -126,7 +126,7 @@ impl Parse for LeadingWhitespace {
/// always succeeds (unless some serious error occurs). This parser also accepts comments,
/// since those can form part of trailing white space.
impl Parse for TrailingWhitespace {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
loop {
let _ = LeadingWhitespace::parse(stream); // don't propagate any errors

Expand All @@ -147,27 +147,27 @@ impl Parse for TrailingWhitespace {

/// Parses a comment
impl Parse for Comment {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
accept_if(|c| c == '#', stream).ok_or(Status::Reject)?;
while accept_if(|c| c != '\n', stream).is_some() {}
make(Comment {})
}
}

fn skip_trailing_whitespace(stream: &mut impl CharStream) -> Parsed<()> {
fn skip_trailing_whitespace(stream: &mut CharStream) -> Parsed<()> {
TrailingWhitespace::parse(stream)?;
make(())
}

/// Adheres to the contract of the [Parse] trait, accepts one character and consumes trailing whitespace.
pub fn try_syntax(syntax: char, stream: &mut impl CharStream) -> Parsed<()> {
pub fn try_syntax(syntax: char, stream: &mut CharStream) -> Parsed<()> {
accept_if(|c| c == syntax, stream).ok_or(Status::Reject)?;
skip_trailing_whitespace(stream)?;
make(())
}

/// Similar to [try_syntax], but aborts parsing if the expected character is not found.
pub fn expect_syntax(syntax: char, stream: &mut impl CharStream) -> Parsed<()> {
pub fn expect_syntax(syntax: char, stream: &mut CharStream) -> Parsed<()> {
if try_syntax(syntax, stream).is_err() {
let str = if let Some(c) = stream.peek() {
c.to_string()
Expand All @@ -180,14 +180,14 @@ pub fn expect_syntax(syntax: char, stream: &mut impl CharStream) -> Parsed<()> {
}

/// Convenience function: usually try_syntax is called as a test criterion; if this returns true, the input was consumed.
pub fn is_syntax(syntax: char, stream: &mut impl CharStream) -> Parsed<bool> {
pub fn is_syntax(syntax: char, stream: &mut CharStream) -> Parsed<bool> {
let result = maybe(try_syntax(syntax, stream))?;
make(result.is_some())
}

/// Interface for working with types that implement the [Parse] trait; this allows parsing to use
/// type inference. Use this instead of calling [Parse::parse] directly.
pub fn try_nonterminal<T: Parse>(stream: &mut impl CharStream) -> Parsed<T> {
pub fn try_nonterminal<T: Parse>(stream: &mut CharStream) -> Parsed<T> {
let result = T::parse(stream)?;
skip_trailing_whitespace(stream)?;
make(result)
Expand All @@ -197,7 +197,7 @@ pub fn try_nonterminal<T: Parse>(stream: &mut impl CharStream) -> Parsed<T> {
/// the given type or gives a fatal parse error if this did not succeed.
use super::ast_names::UserFriendly;

pub fn expect_nonterminal<T: Parse + UserFriendly>(stream: &mut impl CharStream) -> Parsed<T> {
pub fn expect_nonterminal<T: Parse + UserFriendly>(stream: &mut CharStream) -> Parsed<T> {
let begin_pos = stream.get_pos();
match try_nonterminal(stream) {
Err(Status::Reject) => {
Expand Down Expand Up @@ -228,10 +228,10 @@ pub trait Token: Sized {

/// Implementation of the [Parse] trait for anything that implements [Token]
impl<T: Token> Parse for T {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
fn accept_escaped<T: Token>(
pred: fn(char) -> bool,
stream: &mut impl CharStream,
stream: &mut CharStream,
) -> Parsed<char> {
const ESCAPE: char = '\\';
if T::ALLOW_ESCAPE && accept_if(|c| c == ESCAPE, stream).is_some() {
Expand Down Expand Up @@ -267,7 +267,7 @@ impl<T: Token> Parse for T {

/// Parser for `Option<T>` (this can be used to make the code more readable)
impl<T: Parse> Parse for Option<T> {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
maybe(T::parse(stream))
}
}
Expand All @@ -276,7 +276,7 @@ impl<T: Parse> Parse for Option<T> {
pub(super) fn parse_list<T: Parse + UserFriendly>(
sep_by: char,
max: usize,
stream: &mut impl CharStream,
stream: &mut CharStream,
) -> Parsed<Vec<T>> {
let mut elems = Vec::new();
elems.push(try_nonterminal(stream)?);
Expand All @@ -300,13 +300,13 @@ pub trait Many {
/// Generic implementation for parsing multiple items of a type `T` that implements the [Parse] and
/// [Many] traits.
impl<T: Parse + Many + UserFriendly> Parse for Vec<T> {
fn parse(stream: &mut impl CharStream) -> Parsed<Self> {
fn parse(stream: &mut CharStream) -> Parsed<Self> {
parse_list(T::SEP, T::LIMIT, stream)
}
}

/// Entry point utility function; parse a `Vec<T>` but with fatal error recovery per line
pub fn parse_lines<T, Stream: CharStream>(stream: &mut Stream) -> Vec<Parsed<T>>
pub fn parse_lines<T>(stream: &mut CharStream) -> Vec<Parsed<T>>
where
T: Parse + UserFriendly,
{
Expand All @@ -329,7 +329,7 @@ where
} else {
"garbage at end of line"
};
let error = |stream: &mut Stream| unrecoverable!(stream, "{msg}");
let error = |stream: &mut CharStream| unrecoverable!(stream, "{msg}");
result.push(error(stream));
}
while accept_if(|c| c != '\n', stream).is_some() {}
Expand All @@ -340,7 +340,7 @@ where
}

#[cfg(test)]
fn expect_complete<T: Parse>(stream: &mut impl CharStream) -> Parsed<T> {
fn expect_complete<T: Parse>(stream: &mut CharStream) -> Parsed<T> {
let result = expect_nonterminal(stream)?;
if let Some(c) = stream.peek() {
unrecoverable!(stream, "garbage at end of line: {c}")
Expand All @@ -352,7 +352,7 @@ fn expect_complete<T: Parse>(stream: &mut impl CharStream) -> Parsed<T> {
/// AST constructors by hand.
#[cfg(test)]
pub fn parse_string<T: Parse>(text: &str) -> Parsed<T> {
expect_complete(&mut text.chars().peekable())
expect_complete(&mut CharStream::new(text.chars()))
}

#[cfg(test)]
Expand Down Expand Up @@ -388,7 +388,7 @@ mod test {

#[test]
fn lines_test() {
let input = |text: &str| parse_lines(&mut text.chars().peekable());
let input = |text: &str| parse_lines(&mut CharStream::new(text.chars()));

let s = |text: &str| Ok(text.to_string());
assert_eq!(input("hello\nworld\n"), vec![s("hello"), s("world")]);
Expand Down
Loading
Loading