Use new scoped types for line_counter and caller_id

This commit is contained in:
Peter Ammon
2025-03-08 11:03:37 -08:00
parent adde79259b
commit e0953cac41
5 changed files with 24 additions and 49 deletions

View File

@@ -135,7 +135,7 @@ fn parse_cmd_opts(
let e: EventDescription;
if opt == 'j' && woptarg == "caller" {
let caller_id = if parser.scope().is_subshell {
parser.libdata().caller_id
parser.scope().caller_id
} else {
0
};

View File

@@ -11,8 +11,8 @@
STATUS_UNMATCHED_WILDCARD,
};
use crate::common::{
escape, scoped_push_replacer, should_suppress_stderr_for_tests, truncate_at_nul,
valid_var_name, ScopeGuard, ScopeGuarding,
escape, should_suppress_stderr_for_tests, truncate_at_nul, valid_var_name, ScopeGuard,
ScopeGuarding, ScopedRefCell,
};
use crate::complete::CompletionList;
use crate::env::{EnvMode, EnvStackSetResult, EnvVar, EnvVarFlags, Environment, Statuses};
@@ -52,7 +52,6 @@
use crate::wildcard::wildcard_match;
use crate::wutil::{wgettext, wgettext_maybe_fmt};
use libc::{c_int, ENOTDIR, EXIT_SUCCESS, STDERR_FILENO, STDOUT_FILENO};
use std::cell::RefCell;
use std::io::ErrorKind;
use std::rc::Rc;
use std::sync::Arc;
@@ -85,7 +84,7 @@ pub struct ExecutionContext {
// Helper to count lines.
// This is shared with the Parser so that the Parser can access the current line.
line_counter: Rc<RefCell<LineCounter<ast::JobPipeline>>>,
line_counter: Rc<ScopedRefCell<LineCounter<ast::JobPipeline>>>,
/// The block IO chain.
/// For example, in `begin; foo ; end < file.txt` this would have the 'file.txt' IO.
@@ -118,7 +117,7 @@ impl<'a> ExecutionContext {
pub fn new(
pstree: ParsedSourceRef,
block_io: IoChain,
line_counter: Rc<RefCell<LineCounter<ast::JobPipeline>>>,
line_counter: Rc<ScopedRefCell<LineCounter<ast::JobPipeline>>>,
) -> Self {
Self {
pstree,
@@ -1533,10 +1532,7 @@ fn run_1_job(
// Save the executing node.
let line_counter = Rc::clone(&self.line_counter);
let _saved_node = scoped_push_replacer(
|node| line_counter.borrow_mut().set_node(node),
Some(job_node),
);
let _saved_node = line_counter.scoped_set(job_node as *const _, |s| &mut s.node);
// Profiling support.
let profile_item_id = ctx.parser().create_profile_item();
@@ -1631,10 +1627,9 @@ fn run_1_job(
// We are about to populate a job. One possible argument to the job is a command substitution
// which may be interested in the job that's populating it, via '--on-job-exit caller'. Record
// the job ID here.
let _caller_id = scoped_push_replacer(
|new_value| std::mem::replace(&mut ctx.parser().libdata_mut().caller_id, new_value),
job.internal_job_id,
);
let _caller_id = ctx
.parser()
.push_scope(move |s| s.caller_id = job.internal_job_id);
// Populate the job. This may fail for reasons like command_not_found. If this fails, an error
// will have been printed.

View File

@@ -204,7 +204,7 @@ pub struct LineCounter<NodeType: Node> {
parsed_source: Pin<Arc<ParsedSource>>,
/// The node itself. This points into the parsed source, or it may be null.
node: *const NodeType,
pub node: *const NodeType,
// Cached line number information: the line number of the start of the node, and the number of newlines.
cached_offset: usize,
@@ -262,14 +262,6 @@ pub fn source_offset_of_node(&mut self) -> Option<usize> {
Some(range.start())
}
// Set the node. The node must belong to the parsed source.
// Returns the original node.
pub fn set_node<'a>(&mut self, node: Option<&'a NodeType>) -> Option<&'a NodeType> {
let node_ptr = node.map_or(std::ptr::null(), |node| node);
let prev = std::mem::replace(&mut self.node, node_ptr);
unsafe { prev.as_ref() }
}
// Return the source.
pub fn get_source(&self) -> &wstr {
&self.parsed_source.src

View File

@@ -3,8 +3,8 @@
use crate::ast::{self, Ast, List, Node};
use crate::builtins::shared::STATUS_ILLEGAL_CMD;
use crate::common::{
escape_string, scoped_push_replacer, CancelChecker, EscapeFlags, EscapeStringStyle,
FilenameRef, ScopeGuarding, ScopedCell, PROFILING_ACTIVE,
escape_string, CancelChecker, EscapeFlags, EscapeStringStyle, FilenameRef, ScopeGuarding,
ScopedCell, ScopedRefCell, PROFILING_ACTIVE,
};
use crate::complete::CompletionList;
use crate::env::{EnvMode, EnvStack, EnvStackSetResult, Environment, Statuses};
@@ -241,6 +241,10 @@ pub struct ScopedData {
/// Whether we are currently cleaning processes.
pub is_cleaning_procs: bool,
/// The internal job id of the job being populated, or 0 if none.
/// This supports the '--on-job-exit caller' feature.
pub caller_id: u64, // TODO should be InternalJobId
}
impl Default for ScopedData {
@@ -253,6 +257,7 @@ fn default() -> Self {
suppress_fish_trace: false,
read_limit: 0,
is_cleaning_procs: false,
caller_id: 0,
}
}
}
@@ -300,10 +305,6 @@ pub struct LibraryData {
/// Whether we called builtin_complete -C without parameter.
pub builtin_complete_current_commandline: bool,
/// The internal job id of the job being populated, or 0 if none.
/// This supports the '--on-job-exit caller' feature.
pub caller_id: u64, // TODO should be InternalJobId
/// Whether we should break or continue the current loop.
/// This is set by the 'break' and 'continue' commands.
pub loop_status: LoopStatus,
@@ -397,7 +398,7 @@ pub enum CancelBehavior {
pub struct Parser {
/// A shared line counter. This is handed out to each execution context
/// so they can communicate the line number back to this Parser.
line_counter: Rc<RefCell<LineCounter<ast::JobPipeline>>>,
line_counter: Rc<ScopedRefCell<LineCounter<ast::JobPipeline>>>,
/// The jobs associated with this parser.
job_list: RefCell<JobList>,
@@ -438,7 +439,7 @@ impl Parser {
/// Create a parser.
pub fn new(variables: Rc<EnvStack>, cancel_behavior: CancelBehavior) -> Parser {
let result = Self {
line_counter: Rc::new(RefCell::new(LineCounter::empty())),
line_counter: Rc::new(ScopedRefCell::new(LineCounter::empty())),
job_list: RefCell::default(),
wait_handles: RefCell::new(WaitHandleStore::new()),
block_list: RefCell::default(),
@@ -624,8 +625,8 @@ pub fn eval_node<T: Node>(
// Restore the line counter.
let line_counter = Rc::clone(&self.line_counter);
let scoped_line_counter =
scoped_push_replacer(|v| line_counter.replace(v), ps.line_counter());
let restore_line_counter =
line_counter.scoped_replace(ps.line_counter::<ast::JobPipeline>());
// Create a new execution context.
let mut execution_context =
@@ -640,7 +641,7 @@ pub fn eval_node<T: Node>(
let new_exec_count = self.libdata().exec_count;
let new_status_count = self.libdata().status_count;
ScopeGuarding::commit(scoped_line_counter);
ScopeGuarding::commit(restore_line_counter);
self.pop_block(scope_block);
job_reap(self, false); // reap again

View File

@@ -786,25 +786,14 @@ fn test_line_counter() {
assert_eq!(line_offset, expected);
}
fn ref_eq<T>(a: Option<&T>, b: Option<&T>) -> bool {
match (a, b) {
(Some(a), Some(b)) => std::ptr::eq(a, b),
(None, None) => true,
_ => false,
}
}
let pipelines: Vec<_> = ps.ast.walk().filter_map(|n| n.as_job_pipeline()).collect();
assert_eq!(pipelines.len(), 3);
let src_offsets = [0, 0, 2];
assert_eq!(line_counter.source_offset_of_node(), None);
assert_eq!(line_counter.line_offset_of_node(), None);
let mut last_set = None;
for (idx, &node) in pipelines.iter().enumerate() {
let orig = line_counter.set_node(Some(node));
assert!(ref_eq(orig, last_set));
last_set = Some(node);
line_counter.node = node as *const _;
assert_eq!(
line_counter.source_offset_of_node(),
Some(node.source_range().start())
@@ -813,9 +802,7 @@ fn ref_eq<T>(a: Option<&T>, b: Option<&T>) -> bool {
}
for (idx, &node) in pipelines.iter().enumerate().rev() {
let orig = line_counter.set_node(Some(node));
assert!(ref_eq(orig, last_set));
last_set = Some(node);
line_counter.node = node as *const _;
assert_eq!(
line_counter.source_offset_of_node(),
Some(node.source_range().start())