Thread a reference to a line counter into parse execution

Simplify Parser by removing the reference to the execution context
This commit is contained in:
Peter Ammon 2024-06-29 14:56:03 -07:00
parent b00ab4673b
commit c212ac95e9
No known key found for this signature in database
3 changed files with 37 additions and 59 deletions

View File

@ -83,23 +83,14 @@ pub struct ExecutionContext {
cancel_signal: RefCell<Option<Signal>>, cancel_signal: RefCell<Option<Signal>>,
// Helper to count lines. // Helper to count lines.
line_counter: RefCell<LineCounter<ast::JobPipeline>>, // This is shared with the Parser so that the Parser can access the current line.
line_counter: Rc<RefCell<LineCounter<ast::JobPipeline>>>,
/// The block IO chain. /// The block IO chain.
/// For example, in `begin; foo ; end < file.txt` this would have the 'file.txt' IO. /// For example, in `begin; foo ; end < file.txt` this would have the 'file.txt' IO.
block_io: RefCell<IoChain>, block_io: RefCell<IoChain>,
} }
impl ExecutionContext {
pub fn swap(left: &Self, right: Self) -> Self {
left.pstree.swap(&right.pstree);
left.cancel_signal.swap(&right.cancel_signal);
left.line_counter.swap(&right.line_counter);
left.block_io.swap(&right.block_io);
right
}
}
// Report an error, setting $status to `status`. Always returns // Report an error, setting $status to `status`. Always returns
// 'end_execution_reason_t::error'. // 'end_execution_reason_t::error'.
macro_rules! report_error { macro_rules! report_error {
@ -123,12 +114,15 @@ macro_rules! report_error_formatted {
impl<'a> ExecutionContext { impl<'a> ExecutionContext {
/// Construct a context in preparation for evaluating a node in a tree, with the given block_io. /// 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. /// The execution context may access the parser and parent job group (if any) through ctx.
pub fn new(pstree: ParsedSourceRef, block_io: IoChain) -> Self { pub fn new(
let line_counter = pstree.line_counter(); pstree: ParsedSourceRef,
block_io: IoChain,
line_counter: Rc<RefCell<LineCounter<ast::JobPipeline>>>,
) -> Self {
Self { Self {
pstree: RefCell::new(pstree), pstree: RefCell::new(pstree),
cancel_signal: RefCell::default(), cancel_signal: RefCell::default(),
line_counter: RefCell::new(line_counter), line_counter,
block_io: RefCell::new(block_io), block_io: RefCell::new(block_io),
} }
} }

View File

@ -267,4 +267,9 @@ impl<NodeType: Node> LineCounter<NodeType> {
let prev = std::mem::replace(&mut self.node, node_ptr); let prev = std::mem::replace(&mut self.node, node_ptr);
unsafe { prev.as_ref() } unsafe { prev.as_ref() }
} }
// Return the source.
pub fn get_source(&self) -> &wstr {
&self.parsed_source.src
}
} }

View File

@ -1,6 +1,6 @@
// The fish parser. Contains functions for parsing and evaluating code. // The fish parser. Contains functions for parsing and evaluating code.
use crate::ast::{Ast, List, Node}; use crate::ast::{self, Ast, List, Node};
use crate::builtins::shared::STATUS_ILLEGAL_CMD; use crate::builtins::shared::STATUS_ILLEGAL_CMD;
use crate::common::{ use crate::common::{
escape_string, scoped_push_replacer, CancelChecker, EscapeFlags, EscapeStringStyle, escape_string, scoped_push_replacer, CancelChecker, EscapeFlags, EscapeStringStyle,
@ -22,7 +22,7 @@ use crate::parse_constants::{
SOURCE_LOCATION_UNKNOWN, SOURCE_LOCATION_UNKNOWN,
}; };
use crate::parse_execution::{EndExecutionReason, ExecutionContext}; use crate::parse_execution::{EndExecutionReason, ExecutionContext};
use crate::parse_tree::{parse_source, ParsedSourceRef}; use crate::parse_tree::{parse_source, LineCounter, ParsedSourceRef};
use crate::proc::{job_reap, JobGroupRef, JobList, JobRef, ProcStatus}; use crate::proc::{job_reap, JobGroupRef, JobList, JobRef, ProcStatus};
use crate::signal::{signal_check_cancel, signal_clear_cancel, Signal}; use crate::signal::{signal_check_cancel, signal_clear_cancel, Signal};
use crate::threads::assert_is_main_thread; use crate::threads::assert_is_main_thread;
@ -362,8 +362,9 @@ pub enum CancelBehavior {
} }
pub struct Parser { pub struct Parser {
/// The current execution context. /// A shared line counter. This is handed out to each execution context
execution_context: RefCell<Option<ExecutionContext>>, /// so they can communicate the line number back to this Parser.
line_counter: Rc<RefCell<LineCounter<ast::JobPipeline>>>,
/// The jobs associated with this parser. /// The jobs associated with this parser.
job_list: RefCell<JobList>, job_list: RefCell<JobList>,
@ -404,7 +405,7 @@ impl Parser {
/// Create a parser. /// Create a parser.
pub fn new(variables: Rc<EnvStack>, cancel_behavior: CancelBehavior) -> Parser { pub fn new(variables: Rc<EnvStack>, cancel_behavior: CancelBehavior) -> Parser {
let result = Self { let result = Self {
execution_context: RefCell::default(), line_counter: Rc::new(RefCell::new(LineCounter::empty())),
job_list: RefCell::default(), job_list: RefCell::default(),
wait_handles: RefCell::new(WaitHandleStore::new()), wait_handles: RefCell::new(WaitHandleStore::new()),
block_list: RefCell::default(), block_list: RefCell::default(),
@ -429,10 +430,6 @@ impl Parser {
result result
} }
fn execution_context(&self) -> Ref<'_, Option<ExecutionContext>> {
self.execution_context.borrow()
}
/// Adds a job to the beginning of the job list. /// Adds a job to the beginning of the job list.
pub fn job_add(&self, job: JobRef) { pub fn job_add(&self, job: JobRef) {
assert!(!job.processes().is_empty()); assert!(!job.processes().is_empty());
@ -596,35 +593,23 @@ impl Parser {
let cancel_checker: CancelChecker = Box::new(move || check_cancel_signal().is_some()); let cancel_checker: CancelChecker = Box::new(move || check_cancel_signal().is_some());
op_ctx.cancel_checker = cancel_checker; op_ctx.cancel_checker = cancel_checker;
// Create and set a new execution context. // Restore the line counter.
let exc = scoped_push_replacer( let line_counter = Rc::clone(&self.line_counter);
|new_value| { let scoped_line_counter =
if self.execution_context.borrow().is_none() || new_value.is_none() { scoped_push_replacer(|v| line_counter.replace(v), ps.line_counter());
// Outermost node.
std::mem::replace(&mut self.execution_context.borrow_mut(), new_value) // Create a new execution context.
} else { let execution_context =
#[allow(clippy::unnecessary_unwrap)] ExecutionContext::new(ps.clone(), block_io.clone(), Rc::clone(&line_counter));
Some(ExecutionContext::swap(
self.execution_context.borrow().as_ref().unwrap(),
new_value.unwrap(),
))
}
},
Some(ExecutionContext::new(ps.clone(), block_io.clone())),
);
// Check the exec count so we know if anything got executed. // Check the exec count so we know if anything got executed.
let prev_exec_count = self.libdata().exec_count; let prev_exec_count = self.libdata().exec_count;
let prev_status_count = self.libdata().status_count; let prev_status_count = self.libdata().status_count;
let reason = let reason = execution_context.eval_node(&op_ctx, node, Some(scope_block));
self.execution_context()
.as_ref()
.unwrap()
.eval_node(&op_ctx, node, Some(scope_block));
let new_exec_count = self.libdata().exec_count; let new_exec_count = self.libdata().exec_count;
let new_status_count = self.libdata().status_count; let new_status_count = self.libdata().status_count;
ScopeGuarding::commit(exc); ScopeGuarding::commit(scoped_line_counter);
self.pop_block(scope_block); self.pop_block(scope_block);
job_reap(self, false); // reap again job_reap(self, false); // reap again
@ -678,15 +663,7 @@ impl Parser {
/// ///
/// init.fish (line 127): ls|grep pancake /// init.fish (line 127): ls|grep pancake
pub fn current_line(&self) -> WString { pub fn current_line(&self) -> WString {
if self.execution_context().is_none() { let Some(source_offset) = self.line_counter.borrow_mut().source_offset_of_node() else {
return WString::new();
};
let Some(source_offset) = self
.execution_context()
.as_ref()
.unwrap()
.get_current_source_offset()
else {
return WString::new(); return WString::new();
}; };
@ -717,7 +694,7 @@ impl Parser {
empty_error.source_start = source_offset; empty_error.source_start = source_offset;
let mut line_info = empty_error.describe_with_prefix( let mut line_info = empty_error.describe_with_prefix(
&self.execution_context().as_ref().unwrap().get_source(), self.line_counter.borrow().get_source(),
&prefix, &prefix,
self.is_interactive(), self.is_interactive(),
skip_caret, skip_caret,
@ -730,11 +707,13 @@ impl Parser {
line_info line_info
} }
/// Returns the current line number. /// Returns the current line number, indexed from 1.
pub fn get_lineno(&self) -> Option<usize> { pub fn get_lineno(&self) -> Option<usize> {
self.execution_context() // The offset is 0 based; the number is 1 based.
.as_ref() self.line_counter
.and_then(|ctx| ctx.get_current_line_number()) .borrow_mut()
.line_offset_of_node()
.map(|offset| offset + 1)
} }
/// Return whether we are currently evaluating a "block" such as an if statement. /// Return whether we are currently evaluating a "block" such as an if statement.