use std::{ borrow::Cow, ffi::OsStr, io::{self, Write}, process, }; use oyster_builtin_proc::builtin; use crate::Shell; macro_rules! operator { ($name:literal, $desc:literal, $funcname:ident, $operator:tt, $neutral:literal) => { #[builtin(name = $name, description = $desc)] pub fn $funcname(_shell: &mut Shell, args: &[Cow]) { let mut errored = false; let mut parse = |n: &Cow| { n .to_str() .map(|n| { n.parse::().unwrap_or_else(|_| { writeln!(io::stderr(), "not a number: {:?}", n).unwrap(); errored = true; $neutral }) }) .unwrap_or_else(|| { writeln!(io::stderr(), "not a number: {:?}", n).unwrap(); errored = true; $neutral }) }; let mut args = args.iter(); let mut acc = args.next().map(&mut parse).unwrap_or($neutral); #[allow(clippy::assign_op_pattern)] for n in args { acc = acc $operator parse(n); } writeln!(io::stdout(), "{}", acc).unwrap(); process::exit(if errored { 1 } else { 0 }); } } } operator!("+", "adds numbers", add, +, 0.0); operator!("-", "subtracts numbers", sub, -, 0.0); operator!("*", "multiplies numbers", mul, *, 1.0); operator!("/", "divides numbers", div, /, 1.0);