use crate::ast::{ArgSep, ExprType};
use crate::bytecode::VarArgTag;
use crate::callable::{
ArgSepSyntax, CallResult, Callable, CallableMetadata, CallableMetadataBuilder, RepeatedSyntax,
RepeatedTypeSyntax, Scope,
};
use std::borrow::Cow;
use std::cell::RefCell;
use std::rc::Rc;
pub struct OutCommand {
metadata: Rc<CallableMetadata>,
data: Rc<RefCell<Vec<String>>>,
}
impl OutCommand {
pub fn new(data: Rc<RefCell<Vec<String>>>) -> Rc<Self> {
Rc::from(Self {
metadata: CallableMetadataBuilder::new("OUT")
.with_syntax(&[(
&[],
Some(&RepeatedSyntax {
name: Cow::Borrowed("arg"),
type_syn: RepeatedTypeSyntax::AnyValue,
sep: ArgSepSyntax::Exactly(ArgSep::Short),
require_one: false,
allow_missing: false,
}),
)])
.test_build(),
data,
})
}
}
impl Callable for OutCommand {
fn metadata(&self) -> Rc<CallableMetadata> {
self.metadata.clone()
}
fn exec(&self, scope: Scope<'_>) -> CallResult<()> {
let mut first = true;
let mut text = String::new();
let mut reg = 0;
loop {
if !first {
text += " ";
}
first = false;
let sep = match scope.get_type(reg) {
VarArgTag::Immediate(sep, etype) => {
reg += 1;
match etype {
ExprType::Boolean => text.push_str(&format!("{}", scope.get_boolean(reg))),
ExprType::Double => text.push_str(&format!("{}", scope.get_double(reg))),
ExprType::Integer => text.push_str(&format!("{}", scope.get_integer(reg))),
ExprType::Text => text.push_str(scope.get_string(reg)),
}
sep
}
VarArgTag::Missing(sep) => {
text.push_str("<EMPTY>");
sep
}
VarArgTag::Pointer(sep) => {
reg += 1;
let typed_ptr = scope.get_ref(reg);
text.push_str(&typed_ptr.to_string());
sep
}
};
reg += 1;
if sep == ArgSep::End {
break;
}
text.push(' ');
text.push_str(&sep.to_string());
text.push(' ');
}
self.data.borrow_mut().push(text);
Ok(())
}
}