ast: use macro_rules_attribute for the Acceptor trait

Closes #11867
This commit is contained in:
The0x539
2025-09-03 19:11:18 -05:00
committed by Johannes Altmanninger
parent 7aec6c55f9
commit 20da9a2b51

View File

@@ -591,11 +591,15 @@ fn accept_mut<V: NodeVisitorMut>(&mut self, visitor: &mut V) {
}
/// Implement the acceptor trait for the given branch node.
macro_rules! implement_acceptor_for_branch {
macro_rules! Acceptor {
(
$name:ident
$(, $field_name:ident )*
$(,)?
$(#[$_m:meta])*
$_v:vis struct $name:ident {
$(
$(#[$_fm:meta])*
$_fv:vis $field_name:ident : $_ft:ty
),* $(,)?
}
) => {
impl Acceptor for $name {
#[allow(unused_variables)]
@@ -621,17 +625,16 @@ fn accept_mut<V: NodeVisitorMut>(&mut self, visitor: &mut V) {
visitor.did_visit_fields_of(self, flow);
}
}
}
};
}
/// A redirection has an operator like > or 2>, and a target like /dev/null or &1.
/// Note that pipes are not redirections.
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct Redirection {
pub oper: TokenRedirection,
pub target: String_,
}
implement_acceptor_for_branch!(Redirection, oper, target);
impl CheckParse for Redirection {
fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
@@ -761,7 +764,7 @@ fn accept_mut<V: NodeVisitorMut>(&mut self, visitor: &mut V) {
/// A job is a non-empty list of statements, separated by pipes. (Non-empty is useful for cases
/// like if statements, where we require a command).
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct JobPipeline {
/// Maybe the time keyword.
pub time: Option<KeywordTime>,
@@ -774,10 +777,9 @@ pub struct JobPipeline {
/// Maybe backgrounded.
pub bg: Option<TokenBackground>,
}
implement_acceptor_for_branch!(JobPipeline, time, variables, statement, continuation, bg);
/// A job_conjunction is a job followed by a && or || continuations.
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct JobConjunction {
/// The job conjunction decorator.
pub decorator: Option<JobConjunctionDecorator>,
@@ -790,7 +792,6 @@ pub struct JobConjunction {
/// only fail to be present if we ran out of tokens.
pub semi_nl: Option<SemiNl>,
}
implement_acceptor_for_branch!(JobConjunction, decorator, job, continuations, semi_nl);
impl CheckParse for JobConjunction {
fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
@@ -805,7 +806,7 @@ fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
}
}
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct ForHeader {
/// 'for'
pub kw_for: KeywordFor,
@@ -818,18 +819,16 @@ pub struct ForHeader {
/// newline or semicolon
pub semi_nl: SemiNl,
}
implement_acceptor_for_branch!(ForHeader, kw_for, var_name, kw_in, args, semi_nl);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct WhileHeader {
/// 'while'
pub kw_while: KeywordWhile,
pub condition: JobConjunction,
pub andor_tail: AndorJobList,
}
implement_acceptor_for_branch!(WhileHeader, kw_while, condition, andor_tail);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct FunctionHeader {
pub kw_function: KeywordFunction,
/// functions require at least one argument.
@@ -837,18 +836,16 @@ pub struct FunctionHeader {
pub args: ArgumentList,
pub semi_nl: SemiNl,
}
implement_acceptor_for_branch!(FunctionHeader, kw_function, first_arg, args, semi_nl);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct BeginHeader {
pub kw_begin: KeywordBegin,
/// Note that 'begin' does NOT require a semi or nl afterwards.
/// This is valid: begin echo hi; end
pub semi_nl: Option<SemiNl>,
}
implement_acceptor_for_branch!(BeginHeader, kw_begin, semi_nl);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct BlockStatement {
/// A header like for, while, etc.
pub header: BlockStatementHeader,
@@ -859,9 +856,8 @@ pub struct BlockStatement {
/// Arguments and redirections associated with the block.
pub args_or_redirs: ArgumentOrRedirectionList,
}
implement_acceptor_for_branch!(BlockStatement, header, jobs, end, args_or_redirs);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct BraceStatement {
/// The opening brace, in command position.
pub left_brace: TokenLeftBrace,
@@ -872,15 +868,8 @@ pub struct BraceStatement {
/// Arguments and redirections associated with the block.
pub args_or_redirs: ArgumentOrRedirectionList,
}
implement_acceptor_for_branch!(
BraceStatement,
left_brace,
jobs,
right_brace,
args_or_redirs
);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct IfClause {
/// The 'if' keyword.
pub kw_if: KeywordIf,
@@ -891,16 +880,14 @@ pub struct IfClause {
/// The body to execute if the condition is true.
pub body: JobList,
}
implement_acceptor_for_branch!(IfClause, kw_if, condition, andor_tail, body);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct ElseifClause {
/// The 'else' keyword.
pub kw_else: KeywordElse,
/// The 'if' clause following it.
pub if_clause: IfClause,
}
implement_acceptor_for_branch!(ElseifClause, kw_else, if_clause);
impl CheckParse for ElseifClause {
fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
pop.peek_token(0).keyword == ParseKeyword::Else
@@ -910,21 +897,20 @@ fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
define_list_node!(ElseifClauseList, ElseifClause);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct ElseClause {
/// else ; body
pub kw_else: KeywordElse,
pub semi_nl: Option<SemiNl>,
pub body: JobList,
}
implement_acceptor_for_branch!(ElseClause, kw_else, semi_nl, body);
impl CheckParse for ElseClause {
fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
pop.peek_token(0).keyword == ParseKeyword::Else
}
}
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct IfStatement {
/// if part
pub if_clause: IfClause,
@@ -937,16 +923,8 @@ pub struct IfStatement {
/// block args / redirs
pub args_or_redirs: ArgumentOrRedirectionList,
}
implement_acceptor_for_branch!(
IfStatement,
if_clause,
elseif_clauses,
else_clause,
end,
args_or_redirs
);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct CaseItem {
/// case \<arguments\> ; body
pub kw_case: KeywordCase,
@@ -954,14 +932,13 @@ pub struct CaseItem {
pub semi_nl: SemiNl,
pub body: JobList,
}
implement_acceptor_for_branch!(CaseItem, kw_case, arguments, semi_nl, body);
impl CheckParse for CaseItem {
fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
pop.peek_token(0).keyword == ParseKeyword::Case
}
}
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct SwitchStatement {
/// switch \<argument\> ; body ; end args_redirs
pub kw_switch: KeywordSwitch,
@@ -971,19 +948,10 @@ pub struct SwitchStatement {
pub end: KeywordEnd,
pub args_or_redirs: ArgumentOrRedirectionList,
}
implement_acceptor_for_branch!(
SwitchStatement,
kw_switch,
argument,
semi_nl,
cases,
end,
args_or_redirs
);
/// A decorated_statement is a command with a list of arguments_or_redirections, possibly with
/// "builtin" or "command" or "exec"
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct DecoratedStatement {
/// An optional decoration (command, builtin, exec, etc).
pub opt_decoration: Option<DecoratedStatementDecorator>,
@@ -992,10 +960,9 @@ pub struct DecoratedStatement {
/// Args and redirs
pub args_or_redirs: ArgumentOrRedirectionList,
}
implement_acceptor_for_branch!(DecoratedStatement, opt_decoration, command, args_or_redirs);
/// A not statement like `not true` or `! true`
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct NotStatement {
/// Keyword, either not or exclam.
pub kw: KeywordNot,
@@ -1003,16 +970,14 @@ pub struct NotStatement {
pub variables: VariableAssignmentList,
pub contents: Statement,
}
implement_acceptor_for_branch!(NotStatement, kw, time, variables, contents);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct JobContinuation {
pub pipe: TokenPipe,
pub newlines: MaybeNewlines,
pub variables: VariableAssignmentList,
pub statement: Statement,
}
implement_acceptor_for_branch!(JobContinuation, pipe, newlines, variables, statement);
impl CheckParse for JobContinuation {
fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
pop.peek_type(0) == ParseTokenType::pipe
@@ -1021,7 +986,7 @@ fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
define_list_node!(JobContinuationList, JobContinuation);
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct JobConjunctionContinuation {
/// The && or || token.
pub conjunction: TokenConjunction,
@@ -1029,7 +994,6 @@ pub struct JobConjunctionContinuation {
/// The job itself.
pub job: JobPipeline,
}
implement_acceptor_for_branch!(JobConjunctionContinuation, conjunction, newlines, job);
impl CheckParse for JobConjunctionContinuation {
fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
let typ = pop.peek_type(0);
@@ -1040,11 +1004,10 @@ fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
/// An andor_job just wraps a job, but requires that the job have an 'and' or 'or' job_decorator.
/// Note this is only used for andor_job_list; jobs that are not part of an andor_job_list are not
/// instances of this.
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct AndorJob {
pub job: JobConjunction,
}
implement_acceptor_for_branch!(AndorJob, job);
impl CheckParse for AndorJob {
fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
let keyword = pop.peek_token(0).keyword;
@@ -1066,11 +1029,10 @@ fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
/// A freestanding_argument_list is equivalent to a normal argument list, except it may contain
/// TOK_END (newlines, and even semicolons, for historical reasons).
/// In practice the tok_ends are ignored by fish code so we do not bother to store them.
#[derive(Default, Debug, Node!)]
#[derive(Default, Debug, Node!, Acceptor!)]
pub struct FreestandingArgumentList {
pub arguments: ArgumentList,
}
implement_acceptor_for_branch!(FreestandingArgumentList, arguments);
define_list_node!(JobConjunctionContinuationList, JobConjunctionContinuation);