use crate::ast::{ArgSep, BuiltinCallSpan, Expr, FunctionCallSpan, Value, VarRef, VarType};
use crate::eval::{self, eval_all, Error};
use crate::exec::Machine;
use crate::syms::{
Array, CallError, CallableMetadata, CallableMetadataBuilder, Command, CommandResult, Function,
FunctionResult, Symbol, Symbols,
};
use async_trait::async_trait;
use std::cell::RefCell;
use std::collections::HashMap;
use std::io;
use std::rc::Rc;
fn format_value(v: Value, o: &mut String) {
match v {
Value::Boolean(true) => o.push_str("TRUE"),
Value::Boolean(false) => o.push_str("FALSE"),
Value::Double(d) => o.push_str(&format!("{}", d)),
Value::Integer(i) => o.push_str(&format!("{}", i)),
Value::Text(s) => o.push_str(&s),
}
}
pub(crate) struct ClearCommand {
metadata: CallableMetadata,
}
impl ClearCommand {
pub(crate) fn new() -> Rc<Self> {
Rc::from(Self {
metadata: CallableMetadataBuilder::new("CLEAR", VarType::Void).test_build(),
})
}
}
#[async_trait(?Send)]
impl Command for ClearCommand {
fn metadata(&self) -> &CallableMetadata {
&self.metadata
}
async fn exec(&self, span: &BuiltinCallSpan, machine: &mut Machine) -> CommandResult {
if !span.args.is_empty() {
return Err(CallError::SyntaxError);
}
machine.clear();
Ok(())
}
}
pub(crate) struct CountFunction {
metadata: CallableMetadata,
counter: Rc<RefCell<i32>>,
}
impl CountFunction {
pub(crate) fn new() -> Rc<Self> {
Rc::from(Self {
metadata: CallableMetadataBuilder::new("COUNT", VarType::Integer).test_build(),
counter: Rc::from(RefCell::from(0)),
})
}
}
#[async_trait(?Send)]
impl Function for CountFunction {
fn metadata(&self) -> &CallableMetadata {
&self.metadata
}
async fn exec(&self, span: &FunctionCallSpan, _symbols: &mut Symbols) -> FunctionResult {
if !span.args.is_empty() {
return Err(CallError::SyntaxError);
}
let mut counter = self.counter.borrow_mut();
*counter += 1;
debug_assert!(*counter >= 0);
Ok(Value::Integer(*counter))
}
}
pub struct RaiseFunction {
metadata: CallableMetadata,
}
impl RaiseFunction {
pub fn new() -> Rc<Self> {
Rc::from(Self {
metadata: CallableMetadataBuilder::new("RAISE", VarType::Boolean)
.with_syntax("arg1$")
.test_build(),
})
}
}
#[async_trait(?Send)]
impl Function for RaiseFunction {
fn metadata(&self) -> &CallableMetadata {
&self.metadata
}
async fn exec(&self, span: &FunctionCallSpan, symbols: &mut Symbols) -> FunctionResult {
let args = eval_all(&span.args, symbols).await?;
match args.as_slice() {
[Value::Text(s)] => {
let pos = span.args[0].start_pos();
if s == "argument" {
Err(CallError::ArgumentError(pos, "Bad argument".to_owned()))
} else if s == "eval" {
Err(Error::new(pos, "Some eval error").into())
} else if s == "internal" {
Err(CallError::InternalError(pos, "Some internal error".to_owned()))
} else if s == "io" {
Err(io::Error::new(io::ErrorKind::Other, "Some I/O error".to_owned()).into())
} else if s == "syntax" {
Err(CallError::SyntaxError)
} else {
panic!("Unknown argument");
}
}
_ => panic!("Invalid arguments"),
}
}
}
pub(crate) struct GetHiddenFunction {
metadata: CallableMetadata,
}
impl GetHiddenFunction {
pub(crate) fn new() -> Rc<Self> {
Rc::from(Self {
metadata: CallableMetadataBuilder::new("GETHIDDEN", VarType::Text)
.with_syntax("varname$")
.test_build(),
})
}
}
#[async_trait(?Send)]
impl Function for GetHiddenFunction {
fn metadata(&self) -> &CallableMetadata {
&self.metadata
}
async fn exec(&self, span: &FunctionCallSpan, symbols: &mut Symbols) -> FunctionResult {
let mut args = eval_all(&span.args, symbols).await?;
if args.len() != 1 {
return Err(CallError::SyntaxError);
}
match args.pop().unwrap() {
Value::Text(name) => match symbols.get_var(&VarRef::new(name, VarType::Text)) {
Ok(t) => Ok(t.clone()),
Err(e) => Err(CallError::EvalError(eval::Error::from_value_error(
e,
span.args[0].start_pos(),
))),
},
_ => Err(CallError::SyntaxError),
}
}
}
pub(crate) struct GetDataCommand {
metadata: CallableMetadata,
data: Rc<RefCell<Vec<Option<Value>>>>,
}
impl GetDataCommand {
pub(crate) fn new(data: Rc<RefCell<Vec<Option<Value>>>>) -> Rc<Self> {
Rc::from(Self {
metadata: CallableMetadataBuilder::new("GETDATA", VarType::Void).test_build(),
data,
})
}
}
#[async_trait(?Send)]
impl Command for GetDataCommand {
fn metadata(&self) -> &CallableMetadata {
&self.metadata
}
async fn exec(&self, span: &BuiltinCallSpan, machine: &mut Machine) -> CommandResult {
if !span.args.is_empty() {
return Err(CallError::SyntaxError);
}
*self.data.borrow_mut() = machine.get_data().to_vec();
Ok(())
}
}
pub struct InCommand {
metadata: CallableMetadata,
data: Box<RefCell<dyn Iterator<Item = &'static &'static str>>>,
}
impl InCommand {
pub fn new(data: Box<RefCell<dyn Iterator<Item = &'static &'static str>>>) -> Rc<Self> {
Rc::from(Self {
metadata: CallableMetadataBuilder::new("IN", VarType::Void).test_build(),
data,
})
}
}
#[async_trait(?Send)]
impl Command for InCommand {
fn metadata(&self) -> &CallableMetadata {
&self.metadata
}
async fn exec(&self, span: &BuiltinCallSpan, machine: &mut Machine) -> CommandResult {
if span.args.len() != 1 {
return Err(CallError::SyntaxError);
}
if span.args[0].sep != ArgSep::End {
return Err(CallError::SyntaxError);
}
let (vref, pos) = match &span.args[0].expr {
Some(Expr::Symbol(span)) => (&span.vref, span.pos),
_ => return Err(CallError::SyntaxError),
};
let mut data = self.data.borrow_mut();
let raw_value = data.next().unwrap().to_owned();
let value = Value::parse_as(vref.ref_type(), raw_value)
.map_err(|e| eval::Error::from_value_error(e, pos))?;
machine
.get_mut_symbols()
.set_var(vref, value)
.map_err(|e| eval::Error::from_value_error(e, pos))?;
Ok(())
}
}
pub struct OutCommand {
metadata: 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", VarType::Void)
.with_syntax("[arg1 <;|,> argN]")
.test_build(),
data,
})
}
}
#[async_trait(?Send)]
impl Command for OutCommand {
fn metadata(&self) -> &CallableMetadata {
&self.metadata
}
async fn exec(&self, span: &BuiltinCallSpan, machine: &mut Machine) -> CommandResult {
let mut text = String::new();
for arg in span.args.iter() {
if let Some(expr) = arg.expr.as_ref() {
format_value(expr.eval(machine.get_mut_symbols()).await?, &mut text);
}
match arg.sep {
ArgSep::End => break,
ArgSep::Short => text += " ",
ArgSep::Long | ArgSep::As => return Err(CallError::SyntaxError),
}
}
self.data.borrow_mut().push(text);
Ok(())
}
}
pub struct OutfFunction {
metadata: CallableMetadata,
data: Rc<RefCell<Vec<String>>>,
}
impl OutfFunction {
pub fn new(data: Rc<RefCell<Vec<String>>>) -> Rc<Self> {
Rc::from(Self {
metadata: CallableMetadataBuilder::new("OUTF", VarType::Integer)
.with_syntax("arg1 [<;|,> argN]")
.test_build(),
data,
})
}
}
#[async_trait(?Send)]
impl Function for OutfFunction {
fn metadata(&self) -> &CallableMetadata {
&self.metadata
}
async fn exec(&self, span: &FunctionCallSpan, symbols: &mut Symbols) -> FunctionResult {
if span.args.len() < 2 {
return Err(CallError::SyntaxError);
}
let args = eval_all(&span.args, symbols).await?;
let mut iter = args.into_iter();
let result = match iter.next() {
Some(v @ Value::Integer(_)) => v,
_ => return Err(CallError::SyntaxError),
};
let mut text = String::new();
let mut first = true;
for arg in iter {
if !first {
text += " ";
}
first = false;
format_value(arg, &mut text);
}
self.data.borrow_mut().push(text);
Ok(result)
}
}
pub struct SumFunction {
metadata: CallableMetadata,
}
impl SumFunction {
pub fn new() -> Rc<Self> {
Rc::from(Self {
metadata: CallableMetadataBuilder::new("SUM", VarType::Integer)
.with_syntax("[n1% .. nN%]")
.test_build(),
})
}
}
#[async_trait(?Send)]
impl Function for SumFunction {
fn metadata(&self) -> &CallableMetadata {
&self.metadata
}
async fn exec(&self, span: &FunctionCallSpan, symbols: &mut Symbols) -> FunctionResult {
let mut result = Value::Integer(0);
for a in &span.args {
let value = a.eval(symbols).await?;
result =
result.add(&value).map_err(|e| eval::Error::from_value_error(e, a.start_pos()))?;
}
Ok(result)
}
}
#[derive(Default)]
pub struct SymbolsBuilder {
by_name: HashMap<String, Symbol>,
}
impl SymbolsBuilder {
pub fn add_array<S: Into<String>>(mut self, name: S, subtype: VarType) -> Self {
let name = name.into();
assert!(name == name.to_ascii_uppercase());
let array = Array::new(subtype, vec![10]);
self.by_name.insert(name, Symbol::Array(array));
self
}
pub fn add_command(mut self, cmd: Rc<dyn Command>) -> Self {
let name = cmd.metadata().name();
assert!(name == name.to_ascii_uppercase());
self.by_name.insert(name.to_owned(), Symbol::Command(cmd));
self
}
pub fn add_function(mut self, func: Rc<dyn Function>) -> Self {
let name = func.metadata().name();
assert!(name == name.to_ascii_uppercase());
self.by_name.insert(name.to_owned(), Symbol::Function(func));
self
}
pub fn add_var<S: Into<String>>(mut self, name: S, value: Value) -> Self {
let name = name.into();
assert!(name == name.to_ascii_uppercase());
self.by_name.insert(name, Symbol::Variable(value));
self
}
pub fn build(self) -> Symbols {
Symbols::from(self.by_name)
}
}
pub struct TypeCheckFunction {
metadata: CallableMetadata,
value: Value,
}
impl TypeCheckFunction {
pub fn new(value: Value) -> Rc<Self> {
Rc::from(Self {
metadata: CallableMetadataBuilder::new("TYPE_CHECK", VarType::Boolean).test_build(),
value,
})
}
}
#[async_trait(?Send)]
impl Function for TypeCheckFunction {
fn metadata(&self) -> &CallableMetadata {
&self.metadata
}
async fn exec(&self, span: &FunctionCallSpan, _symbols: &mut Symbols) -> FunctionResult {
assert!(span.args.is_empty());
Ok(self.value.clone())
}
}