1pub mod startup;
27use self::startup::args::Parse;
30use self::startup::init_file::run_rcfile;
31use self::startup::input::prepare_input;
32use std::cell::RefCell;
33use std::ops::ControlFlow::{Break, Continue};
34use yash_env::Env;
35use yash_env::RealSystem;
36use yash_env::System;
37use yash_env::option::{Interactive, On};
38use yash_env::signal;
39use yash_env::system::{Disposition, Errno};
40use yash_executor::Executor;
41use yash_semantics::trap::run_exit_trap;
42use yash_semantics::{Divert, ExitStatus};
43use yash_semantics::{interactive_read_eval_loop, read_eval_loop};
44
45async fn print_version(env: &mut Env) -> ExitStatus {
46 let version = env!("CARGO_PKG_VERSION");
47 let result = yash_builtin::common::output(env, &format!("yash {}\n", version)).await;
48 result.exit_status()
49}
50
51#[allow(clippy::await_holding_refcell_ref)]
53async fn parse_and_print(mut env: Env) -> ExitStatus {
54 let run = match self::startup::args::parse(std::env::args()) {
56 Ok(Parse::Help) => todo!("print help"),
57 Ok(Parse::Version) => return print_version(&mut env).await,
58 Ok(Parse::Run(run)) => run,
59 Err(e) => {
60 let arg0 = std::env::args().next().unwrap_or_else(|| "yash".to_owned());
61 env.system.print_error(&format!("{}: {}\n", arg0, e)).await;
62 return ExitStatus::ERROR;
63 }
64 };
65
66 env.variables.extend_env(std::env::vars());
68
69 let work = self::startup::configure_environment(&mut env, run);
70
71 let is_interactive = env.options.get(Interactive) == On;
72
73 run_rcfile(&mut env, work.rcfile).await;
76
77 let ref_env = &RefCell::new(&mut env);
79 let lexer = match prepare_input(ref_env, &work.source) {
80 Ok(lexer) => lexer,
81 Err(e) => {
82 let arg0 = std::env::args().next().unwrap_or_else(|| "yash".to_owned());
83 let message = format!("{}: {}\n", arg0, e);
84 ref_env.borrow_mut().system.print_error(&message).await;
89 return match e.errno {
90 Errno::ENOENT | Errno::ENOTDIR | Errno::EILSEQ => ExitStatus::NOT_FOUND,
91 _ => ExitStatus::NOEXEC,
92 };
93 }
94 };
95
96 let result = if is_interactive {
98 interactive_read_eval_loop(ref_env, &mut { lexer }).await
99 } else {
100 read_eval_loop(ref_env, &mut { lexer }).await
101 };
102
103 env.apply_result(result);
104
105 match result {
106 Continue(())
107 | Break(Divert::Continue { .. })
108 | Break(Divert::Break { .. })
109 | Break(Divert::Return(_))
110 | Break(Divert::Interrupt(_))
111 | Break(Divert::Exit(_)) => run_exit_trap(&mut env).await,
112 Break(Divert::Abort(_)) => (),
113 }
114
115 env.exit_status
116}
117
118pub fn main() -> ! {
119 let system = unsafe { RealSystem::new() };
122 let mut env = Env::with_system(Box::new(system));
123
124 let sigpipe = env
128 .system
129 .signal_number_from_name(signal::Name::Pipe)
130 .unwrap();
131 _ = env.system.sigaction(sigpipe, Disposition::Default);
132
133 let system = env.system.clone();
134 let executor = Executor::new();
135 let task = Box::pin(async {
136 let exit_status = parse_and_print(env).await;
137 std::process::exit(exit_status.0);
138 });
139 unsafe { executor.spawn_pinned(task) }
142 loop {
143 executor.run_until_stalled();
144 system.select(false).ok();
145 }
146}