use std::ops::ControlFlow::{Break, Continue};
use yash_env::Env;
#[cfg(doc)]
use yash_env::SharedSystem;
use yash_env::io::Fd;
use yash_env::semantics::Divert;
use yash_env::semantics::ExitStatus;
#[allow(deprecated)]
use yash_env::source::pretty::{Annotation, AnnotationType, Message, MessageBase};
#[cfg(doc)]
use yash_env::stack::Stack;
pub mod report;
pub mod syntax;
#[allow(deprecated)]
#[deprecated(
note = "Use `report::prepare_report_message_and_divert` instead",
since = "0.11.0"
)]
#[must_use = "returned message should be printed"]
pub fn arrange_message_and_divert<'e: 'm, 'm>(
env: &'e Env,
mut message: Message<'m>,
) -> (String, yash_env::semantics::Result) {
let is_special_builtin;
if let Some(builtin) = env.stack.current_builtin() {
message.annotations.push(Annotation::new(
AnnotationType::Info,
format!("executing the {} built-in", builtin.name.value).into(),
&builtin.name.origin,
));
let source = &builtin.name.origin.code.source;
source.complement_annotations(&mut message.annotations);
is_special_builtin = builtin.is_special;
} else {
is_special_builtin = false;
}
let message = yash_env::io::message_to_string(env, &message);
let divert = if is_special_builtin {
Break(Divert::Interrupt(None))
} else {
Continue(())
};
(message, divert)
}
#[allow(deprecated)]
#[deprecated(note = "Use `report::report` instead", since = "0.11.0")]
#[inline]
pub async fn report<'a, M>(
env: &mut Env,
message: M,
exit_status: ExitStatus,
) -> yash_env::builtin::Result
where
M: Into<Message<'a>> + 'a,
{
async fn inner(
env: &mut Env,
message: Message<'_>,
exit_status: ExitStatus,
) -> yash_env::builtin::Result {
let (message, divert) = arrange_message_and_divert(env, message);
env.system.print_error(&message).await;
yash_env::builtin::Result::with_exit_status_and_divert(exit_status, divert)
}
inner(env, message.into(), exit_status).await
}
#[allow(deprecated)]
#[deprecated(note = "Use `report::report_failure` instead", since = "0.11.0")]
#[inline]
pub async fn report_failure<'a, M>(env: &mut Env, message: M) -> yash_env::builtin::Result
where
M: Into<Message<'a>> + 'a,
{
report(env, message, ExitStatus::FAILURE).await
}
#[allow(deprecated)]
#[deprecated(note = "Use `report::report_error` instead", since = "0.11.0")]
#[inline]
pub async fn report_error<'a, M>(env: &mut Env, message: M) -> yash_env::builtin::Result
where
M: Into<Message<'a>> + 'a,
{
report(env, message, ExitStatus::ERROR).await
}
#[deprecated(
note = "This function has been moved to the `report` module",
since = "0.11.0"
)]
pub use report::{report_simple, report_simple_error, report_simple_failure, syntax_error};
pub async fn output(env: &mut Env, content: &str) -> yash_env::builtin::Result {
match env.system.write_all(Fd::STDOUT, content.as_bytes()).await {
Ok(_) => Default::default(),
Err(errno) => {
report_simple_failure(env, &format!("error printing results to stdout: {errno}")).await
}
}
}
#[allow(deprecated)]
#[deprecated(note = "Use `report::merge_reports` instead", since = "0.11.0")]
#[must_use]
pub fn to_single_message<'a, I, M>(errors: I) -> Option<Message<'a>>
where
I: IntoIterator<Item = &'a M>,
M: MessageBase + 'a,
{
let mut errors = errors.into_iter();
let first = errors.next()?;
let mut message = Message::from(first);
let other_errors = errors.map(MessageBase::main_annotation);
message.annotations.extend(other_errors);
Some(message)
}
#[cfg(test)]
mod tests {
use super::*;
use yash_env::semantics::Field;
use yash_env::stack::Builtin;
use yash_env::stack::Frame;
#[allow(deprecated)]
fn dummy_message() -> Message<'static> {
Message {
r#type: AnnotationType::Error,
title: "foo".into(),
annotations: vec![],
footers: vec![],
}
}
#[allow(deprecated)]
#[test]
fn divert_without_builtin() {
let env = Env::new_virtual();
let (_message, divert) = arrange_message_and_divert(&env, dummy_message());
assert_eq!(divert, Continue(()));
}
#[allow(deprecated)]
#[test]
fn divert_with_special_builtin() {
let mut env = Env::new_virtual();
let env = env.push_frame(Frame::Builtin(Builtin {
name: Field::dummy("builtin"),
is_special: true,
}));
let (_message, divert) = arrange_message_and_divert(&env, dummy_message());
assert_eq!(divert, Break(Divert::Interrupt(None)));
}
#[allow(deprecated)]
#[test]
fn divert_with_non_special_builtin() {
let mut env = Env::new_virtual();
let env = env.push_frame(Frame::Builtin(Builtin {
name: Field::dummy("builtin"),
is_special: false,
}));
let (_message, divert) = arrange_message_and_divert(&env, dummy_message());
assert_eq!(divert, Continue(()));
}
}