mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-22 12:41:08 +08:00
Remove the notion of principal parser
The "principal" parser is the one and only today; in the future we hope to have multiple parsers to execute fish script in parallel. Having a globally accessible "principle" parser is suspicious; now we can get rid of it.
This commit is contained in:
parent
631516398e
commit
4557d9fc09
|
@ -46,7 +46,7 @@ use fish::{
|
|||
parse_constants::{ParseErrorList, ParseTreeFlags},
|
||||
parse_tree::ParsedSource,
|
||||
parse_util::parse_util_detect_errors_in_ast,
|
||||
parser::{BlockType, Parser},
|
||||
parser::{BlockType, CancelBehavior, Parser},
|
||||
path::path_get_config,
|
||||
printf,
|
||||
proc::{
|
||||
|
@ -65,6 +65,7 @@ use std::fs::File;
|
|||
use std::mem::MaybeUninit;
|
||||
use std::os::unix::prelude::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::{env, ops::ControlFlow};
|
||||
|
@ -591,7 +592,9 @@ fn throwing_main() -> i32 {
|
|||
ScopeGuard::new((), |()| restore_term_foreground_process_group_for_exit());
|
||||
let _restore_term = reader_init();
|
||||
|
||||
let parser = Parser::principal_parser();
|
||||
// Construct the root parser!
|
||||
let env = Rc::new(EnvStack::globals().create_child(true /* dispatches_var_changes */));
|
||||
let parser: &Parser = &Parser::new(env, CancelBehavior::Clear);
|
||||
parser.set_syncs_uvars(!opts.no_config);
|
||||
|
||||
if !opts.no_exec && !opts.no_config {
|
||||
|
|
|
@ -25,7 +25,7 @@ use crate::parse_execution::{EndExecutionReason, ParseExecutionContext};
|
|||
use crate::parse_tree::{parse_source, ParsedSourceRef};
|
||||
use crate::proc::{job_reap, JobGroupRef, JobList, JobRef, ProcStatus};
|
||||
use crate::signal::{signal_check_cancel, signal_clear_cancel, Signal};
|
||||
use crate::threads::{assert_is_main_thread, MainThread};
|
||||
use crate::threads::assert_is_main_thread;
|
||||
use crate::util::get_time;
|
||||
use crate::wait_handle::WaitHandleStore;
|
||||
use crate::wchar::{wstr, WString, L};
|
||||
|
@ -353,6 +353,16 @@ pub type BlockId = usize;
|
|||
|
||||
pub type ParserRef = Rc<Parser>;
|
||||
|
||||
// Controls the behavior when fish itself receives a signal and there are
|
||||
// no blocks on the stack.
|
||||
// The "outermost" parser is responsible for clearing the signal.
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum CancelBehavior {
|
||||
#[default]
|
||||
Return, // Return the signal to the caller.
|
||||
Clear, // Clear the signal.
|
||||
}
|
||||
|
||||
pub struct Parser {
|
||||
/// The current execution context.
|
||||
execution_context: RefCell<Option<ParseExecutionContext>>,
|
||||
|
@ -382,8 +392,8 @@ pub struct Parser {
|
|||
/// including sending on-variable change events.
|
||||
syncs_uvars: RelaxedAtomicBool,
|
||||
|
||||
/// If set, we are the principal parser.
|
||||
is_principal: RelaxedAtomicBool,
|
||||
/// The behavior when fish itself receives a signal and there are no blocks on the stack.
|
||||
cancel_behavior: CancelBehavior,
|
||||
|
||||
/// List of profile items.
|
||||
profile_items: RefCell<Vec<ProfileItem>>,
|
||||
|
@ -393,8 +403,8 @@ pub struct Parser {
|
|||
}
|
||||
|
||||
impl Parser {
|
||||
/// Create a parser
|
||||
pub fn new(variables: Rc<EnvStack>, is_principal: bool) -> ParserRef {
|
||||
/// Create a parser.
|
||||
pub fn new(variables: Rc<EnvStack>, cancel_behavior: CancelBehavior) -> ParserRef {
|
||||
let result = Rc::new(Self {
|
||||
execution_context: RefCell::default(),
|
||||
job_list: RefCell::default(),
|
||||
|
@ -404,7 +414,7 @@ impl Parser {
|
|||
variables,
|
||||
library_data: RefCell::new(LibraryData::new()),
|
||||
syncs_uvars: RelaxedAtomicBool::new(false),
|
||||
is_principal: RelaxedAtomicBool::new(is_principal),
|
||||
cancel_behavior,
|
||||
profile_items: RefCell::default(),
|
||||
global_event_blocks: AtomicU64::new(0),
|
||||
});
|
||||
|
@ -451,17 +461,6 @@ impl Parser {
|
|||
.any(|b| b.typ() == BlockType::subst)
|
||||
}
|
||||
|
||||
/// Get the "principal" parser, whatever that is. Can only be called by the main thread.
|
||||
pub fn principal_parser() -> &'static Parser {
|
||||
use std::cell::OnceCell;
|
||||
static PRINCIPAL: MainThread<OnceCell<ParserRef>> = MainThread::new(OnceCell::new());
|
||||
PRINCIPAL.get().get_or_init(|| {
|
||||
let dispatches_var_changes = true;
|
||||
let env = Rc::new(EnvStack::globals().create_child(dispatches_var_changes));
|
||||
Parser::new(env, true)
|
||||
})
|
||||
}
|
||||
|
||||
/// Assert that this parser is allowed to execute on the current thread.
|
||||
pub fn assert_can_execute(&self) {
|
||||
assert_is_main_thread();
|
||||
|
@ -553,14 +552,14 @@ impl Parser {
|
|||
"Invalid block type"
|
||||
);
|
||||
|
||||
// If fish itself got a cancel signal, then we want to unwind back to the principal parser.
|
||||
// If we are the principal parser and our block stack is empty, then we want to clear the
|
||||
// signal.
|
||||
// If fish itself got a cancel signal, then we want to unwind back to the parser which
|
||||
// has a Clear cancellation behavior.
|
||||
// Note this only happens in interactive sessions. In non-interactive sessions, SIGINT will
|
||||
// cause fish to exit.
|
||||
let sig = signal_check_cancel();
|
||||
if sig != 0 {
|
||||
if self.is_principal.load() && self.block_list.borrow().is_empty() {
|
||||
if self.cancel_behavior == CancelBehavior::Clear && self.block_list.borrow().is_empty()
|
||||
{
|
||||
signal_clear_cancel();
|
||||
} else {
|
||||
return EvalRes::new(ProcStatus::from_signal(Signal::new(sig)));
|
||||
|
|
|
@ -30,7 +30,7 @@ mod wgetopt;
|
|||
pub mod prelude {
|
||||
use crate::common::ScopeGuarding;
|
||||
use crate::env::{env_init, misc_init};
|
||||
use crate::parser::{Parser, ParserRef};
|
||||
use crate::parser::{CancelBehavior, Parser, ParserRef};
|
||||
use crate::reader::reader_init;
|
||||
use crate::signal::signal_reset_handlers;
|
||||
pub use crate::tests::env::{PwdEnvironment, TestEnvironment};
|
||||
|
@ -52,7 +52,7 @@ pub mod prelude {
|
|||
impl TestParser {
|
||||
pub fn new() -> TestParser {
|
||||
TestParser {
|
||||
parser: Parser::new(Rc::new(EnvStack::new()), false),
|
||||
parser: Parser::new(Rc::new(EnvStack::new()), CancelBehavior::default()),
|
||||
pushed_dirs: RefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::parse_constants::{
|
|||
ParseErrorCode, ParseTreeFlags, ParserTestErrorBits, StatementDecoration,
|
||||
};
|
||||
use crate::parse_util::{parse_util_detect_errors, parse_util_detect_errors_in_argument};
|
||||
use crate::parser::Parser;
|
||||
use crate::parser::{CancelBehavior, Parser};
|
||||
use crate::reader::{reader_pop, reader_push, reader_reset_interrupted, ReaderConfig};
|
||||
use crate::signal::{signal_clear_cancel, signal_reset_handlers, signal_set_handlers};
|
||||
use crate::tests::prelude::*;
|
||||
|
@ -716,7 +716,7 @@ fn test_1_cancellation(parser: &Parser, src: &wstr) {
|
|||
#[serial]
|
||||
fn test_cancellation() {
|
||||
let _cleanup = test_init();
|
||||
let parser = Parser::new(Rc::new(EnvStack::new()), true);
|
||||
let parser = Parser::new(Rc::new(EnvStack::new()), CancelBehavior::Clear);
|
||||
reader_push(&parser, L!(""), ReaderConfig::default());
|
||||
let _pop = ScopeGuard::new((), |()| reader_pop());
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user