use crate::common::output;
use crate::common::report::{merge_reports, report_error, report_failure};
use crate::typeset::Command;
use crate::typeset::FunctionAttr;
use crate::typeset::PrintContext;
use crate::typeset::Scope::Global;
use crate::typeset::VariableAttr;
use crate::typeset::syntax::OptionSpec;
use crate::typeset::syntax::PRINT_OPTION;
use crate::typeset::syntax::interpret;
use crate::typeset::syntax::parse;
use yash_env::Env;
use yash_env::builtin::Result;
use yash_env::option::State::On;
use yash_env::semantics::Field;
pub const PORTABLE_OPTIONS: &[OptionSpec<'static>] = &[PRINT_OPTION];
pub const PRINT_CONTEXT: PrintContext<'static> = PrintContext {
builtin_name: "readonly",
builtin_is_significant: true,
options_allowed: &[],
};
pub async fn main(env: &mut Env, args: Vec<Field>) -> Result {
match parse(PORTABLE_OPTIONS, args) {
Ok((options, operands)) => match interpret(options, operands) {
Ok(mut command) => {
match &mut command {
Command::SetVariables(sv) => {
sv.attrs.push((VariableAttr::ReadOnly, On));
sv.scope = Global;
}
Command::PrintVariables(pv) => {
pv.attrs.push((VariableAttr::ReadOnly, On));
pv.scope = Global;
}
Command::SetFunctions(sf) => sf.attrs.push((FunctionAttr::ReadOnly, On)),
Command::PrintFunctions(pf) => pf.attrs.push((FunctionAttr::ReadOnly, On)),
}
match command.execute(env, &PRINT_CONTEXT) {
Ok(result) => output(env, &result).await,
Err(errors) => report_failure(env, merge_reports(&errors).unwrap()).await,
}
}
Err(error) => report_error(env, &error).await,
},
Err(error) => report_error(env, &error).await,
}
}
#[allow(clippy::bool_assert_comparison)]
#[cfg(test)]
mod tests {
use super::*;
use futures_util::FutureExt;
use yash_env::Env;
use yash_env::semantics::ExitStatus;
use yash_env::variable::Value;
#[test]
fn builtin_defines_read_only_variable() {
let mut env = Env::new_virtual();
let args = Field::dummies(["foo=bar baz"]);
let location = args[0].origin.clone();
let result = main(&mut env, args).now_or_never().unwrap();
assert_eq!(result, Result::new(ExitStatus::SUCCESS));
let v = env.variables.get("foo").unwrap();
assert_eq!(v.value, Some(Value::scalar("bar baz")));
assert_eq!(v.is_exported, false);
assert_eq!(v.read_only_location.as_ref().unwrap(), &location);
assert_eq!(v.last_assigned_location.as_ref().unwrap(), &location);
}
}