parse_execution: remove pipeline node reference from ExecutionContext

Upcoming changes will pass Parser by exclusive reference ("&mut") which
prevents aliasing; let's remove an alias which seems simpler anyway.
This commit is contained in:
Johannes Altmanninger
2026-04-29 19:50:16 +08:00
parent 3d708d6fc1
commit df5067cc1c
2 changed files with 31 additions and 33 deletions

View File

@@ -56,9 +56,7 @@
trace::{trace_if_enabled, trace_if_enabled_with_args},
wildcard::wildcard_match,
};
use fish_common::{
ScopeGuard, ScopeGuarding, ScopedRefCell, escape, help_section, truncate_at_nul,
};
use fish_common::{ScopeGuard, ScopeGuarding, escape, help_section, truncate_at_nul};
use fish_widestring::WExt as _;
use libc::{ENOTDIR, EXIT_SUCCESS, STDERR_FILENO, STDOUT_FILENO, c_int};
use std::{io::ErrorKind, rc::Rc, sync::Arc};
@@ -81,7 +79,7 @@ pub enum EndExecutionReason {
Error,
}
pub struct ExecutionContext<'a> {
pub struct ExecutionContext {
// The parsed source and its AST.
pstree: ParsedSourceRef,
@@ -89,10 +87,6 @@ pub struct ExecutionContext<'a> {
// unwinding.
cancel_signal: Option<Signal>,
// The currently executing pipeline node.
// This is shared with the Parser so that the Parser can access the current line.
pipeline_node: &'a ScopedRefCell<Option<NodeRef<ast::JobPipeline>>>,
/// The block IO chain.
/// For example, in `begin; foo ; end < file.txt` this would have the 'file.txt' IO.
block_io: IoChain,
@@ -130,19 +124,17 @@ pub fn varname_error<'a>(command: &'a wstr, bad_name: &'a wstr) -> Error<'a> {
.cmd(command)
}
impl<'a> ExecutionContext<'a> {
impl ExecutionContext {
/// Construct a context in preparation for evaluating a node in a tree, with the given block_io.
/// The execution context may access the parser and parent job group (if any) through ctx.
pub fn new(
pstree: ParsedSourceRef,
block_io: IoChain,
pipeline_node: &'a ScopedRefCell<Option<NodeRef<ast::JobPipeline>>>,
test_only_suppress_stderr: bool,
) -> Self {
Self {
pstree,
cancel_signal: None,
pipeline_node,
block_io,
test_only_suppress_stderr,
}
@@ -155,7 +147,7 @@ pub fn pstree(&self) -> &ParsedSourceRef {
pub fn eval_node(
&mut self,
ctx: &OperationContext<'_>,
node: &'a dyn Node,
node: &dyn Node,
associated_block: Option<BlockId>,
) -> EndExecutionReason {
match node.kind() {
@@ -170,7 +162,7 @@ pub fn eval_node(
fn eval_statement(
&mut self,
ctx: &OperationContext<'_>,
statement: &'a ast::Statement,
statement: &ast::Statement,
associated_block: Option<BlockId>,
) -> EndExecutionReason {
// Note we only expect block-style statements here. No not statements.
@@ -188,7 +180,7 @@ fn eval_statement(
fn eval_job_list(
&mut self,
ctx: &OperationContext<'_>,
job_list: &'a ast::JobList,
job_list: &ast::JobList,
associated_block: BlockId,
) -> EndExecutionReason {
// Check for infinite recursion: a function which immediately calls itself..
@@ -391,12 +383,12 @@ fn node_source_owned(&self, node: &dyn ast::Node) -> WString {
self.node_source(node).to_owned()
}
fn infinite_recursive_statement_in_job_list<'b>(
fn infinite_recursive_statement_in_job_list<'a>(
&self,
ctx: &OperationContext<'_>,
jobs: &'b ast::JobList,
jobs: &'a ast::JobList,
out_func_name: &mut WString,
) -> Option<&'b ast::DecoratedStatement> {
) -> Option<&'a ast::DecoratedStatement> {
// This is a bit fragile. It is a test to see if we are inside of function call, but
// not inside a block in that function call. If, in the future, the rules for what
// block scopes are pushed on function invocation changes, then this check will break.
@@ -423,7 +415,7 @@ fn infinite_recursive_statement_in_job_list<'b>(
let job = &jc.job;
// Helper to return if a statement is infinitely recursive in this function.
let statement_recurses = |stat: &'b ast::Statement| -> Option<&'b ast::DecoratedStatement> {
let statement_recurses = |stat: &'a ast::Statement| -> Option<&'a ast::DecoratedStatement> {
// Ignore non-decorated statements like `if`, etc.
let Statement::Decorated(dc) = &stat else {
return None;
@@ -873,7 +865,7 @@ fn populate_block_process(
fn run_block_statement(
&mut self,
ctx: &OperationContext<'_>,
statement: &'a ast::BlockStatement,
statement: &ast::BlockStatement,
associated_block: Option<BlockId>,
) -> EndExecutionReason {
let bh = &statement.header;
@@ -891,8 +883,8 @@ fn run_block_statement(
fn run_for_statement(
&mut self,
ctx: &OperationContext<'_>,
header: &'a ast::ForHeader,
block_contents: &'a ast::JobList,
header: &ast::ForHeader,
block_contents: &ast::JobList,
) -> EndExecutionReason {
// Get the variable name: `for var_name in ...`. We expand the variable name. It better result
// in just one.
@@ -1000,7 +992,7 @@ fn run_for_statement(
fn run_if_statement(
&mut self,
ctx: &OperationContext<'_>,
statement: &'a ast::IfStatement,
statement: &ast::IfStatement,
associated_block: Option<BlockId>,
) -> EndExecutionReason {
let mut result = EndExecutionReason::Ok;
@@ -1090,7 +1082,7 @@ fn run_if_statement(
fn run_switch_statement(
&mut self,
ctx: &OperationContext<'_>,
statement: &'a ast::SwitchStatement,
statement: &ast::SwitchStatement,
) -> EndExecutionReason {
// Get the switch variable.
let switch_value = self.node_source_owned(&statement.argument);
@@ -1200,8 +1192,8 @@ fn run_switch_statement(
fn run_while_statement(
&mut self,
ctx: &OperationContext<'_>,
header: &'a ast::WhileHeader,
contents: &'a ast::JobList,
header: &ast::WhileHeader,
contents: &ast::JobList,
associated_block: Option<BlockId>,
) -> EndExecutionReason {
let mut ret = EndExecutionReason::Ok;
@@ -1334,7 +1326,7 @@ fn run_function_statement(
fn run_begin_statement(
&mut self,
ctx: &OperationContext<'_>,
contents: &'a ast::JobList,
contents: &ast::JobList,
) -> EndExecutionReason {
// Basic begin/end block. Push a scope block, run jobs, pop it
trace_if_enabled(ctx.parser(), L!("begin"));
@@ -1535,7 +1527,7 @@ fn determine_redirections(
fn run_1_job(
&mut self,
ctx: &OperationContext<'_>,
job_node: &'a ast::JobPipeline,
job_node: &ast::JobPipeline,
associated_block: Option<BlockId>,
) -> EndExecutionReason {
if let Some(ret) = self.check_end_execution(ctx) {
@@ -1552,7 +1544,10 @@ fn run_1_job(
// Save the executing node.
let executing_node = NodeRef::new(Arc::clone(self.pstree()), job_node);
let _saved_node = self.pipeline_node.scoped_replace(Some(executing_node));
let _saved_node = ctx
.parser()
.current_node()
.scoped_replace(Some(executing_node));
// Profiling support.
let profile_item_id = ctx.parser().create_profile_item();
@@ -1706,7 +1701,7 @@ fn run_1_job(
fn test_and_run_1_job_conjunction(
&mut self,
ctx: &OperationContext<'_>,
jc: &'a ast::JobConjunction,
jc: &ast::JobConjunction,
associated_block: Option<BlockId>,
) -> EndExecutionReason {
// Test this job conjunction if it has an 'and' or 'or' decorator.
@@ -1741,7 +1736,7 @@ fn test_and_run_1_job_conjunction(
fn run_job_conjunction(
&mut self,
ctx: &OperationContext<'_>,
job_expr: &'a ast::JobConjunction,
job_expr: &ast::JobConjunction,
associated_block: Option<BlockId>,
) -> EndExecutionReason {
if let Some(reason) = self.check_end_execution(ctx) {
@@ -1775,7 +1770,7 @@ fn run_job_conjunction(
fn run_job_list(
&mut self,
ctx: &OperationContext<'_>,
job_list_node: &'a ast::JobList,
job_list_node: &ast::JobList,
associated_block: Option<BlockId>,
) -> EndExecutionReason {
let mut result = EndExecutionReason::Ok;
@@ -1789,7 +1784,7 @@ fn run_job_list(
fn run_andor_job_list(
&mut self,
ctx: &OperationContext<'_>,
job_list_node: &'a ast::AndorJobList,
job_list_node: &ast::AndorJobList,
associated_block: Option<BlockId>,
) -> EndExecutionReason {
let mut result = EndExecutionReason::Ok;

View File

@@ -689,7 +689,6 @@ pub fn eval_node<T: Node>(
let mut execution_context = ExecutionContext::new(
node.parsed_source_ref(),
block_io.clone(),
&self.current_node,
test_only_suppress_stderr,
);
@@ -813,6 +812,10 @@ pub fn get_lineno_for_display(&self) -> u32 {
self.get_lineno().map_or(0, |n| n.get())
}
pub fn current_node(&self) -> &ScopedRefCell<Option<NodeRef<ast::JobPipeline>>> {
&self.current_node
}
/// Returns a NodeRef to the current node being executed, if any.
/// This can be used for lazy line number computation.
pub fn current_node_ref(&self) -> Option<NodeRef<ast::JobPipeline>> {