use crate::parser::types::{FunctionValue, Value, InkIteratorKind};
use crate::parser::interpreter::Interpreter;
pub fn do_map(
interp: &mut Interpreter,
map_fn: &FunctionValue,
data_val: Value,
) -> Result<Value, String> {
use crate::parser::interpreter::apply::apply_one_function_value;
match data_val {
Value::IntArray(xs) => {
let mut out = Vec::new();
for x in xs {
let ret = apply_one_function_value(interp, Box::new(map_fn.clone()), Value::Int(x))?;
match ret {
Value::Int(i2) => out.push(i2),
other => return Err(format!("array:map => user function returned non-int: {:?}", other)),
}
}
Ok(Value::IntArray(out))
}
Value::StrArray(ss) => {
let mut results = Vec::new();
let mut out_kind: Option<&'static str> = None;
for s in ss {
let ret = apply_one_function_value(interp, Box::new(map_fn.clone()), Value::SingleString(s))?;
match &ret {
Value::Int(_) => {
if out_kind.is_none() {
out_kind = Some("int");
} else if out_kind != Some("int") {
return Err("array:map => inconsistent return types from user function".to_string());
}
}
Value::SingleString(_) => {
if out_kind.is_none() {
out_kind = Some("string");
} else if out_kind != Some("string") {
return Err("array:map => inconsistent return types".to_string());
}
}
_ => return Err("array:map => unsupported return type from user function".to_string()),
}
results.push(ret);
}
match out_kind {
None => Ok(Value::StrArray(vec![])),
Some("int") => {
let mut out = Vec::with_capacity(results.len());
for item in results {
if let Value::Int(n) = item {
out.push(n);
}
}
Ok(Value::IntArray(out))
}
Some("string") => {
let mut out = Vec::with_capacity(results.len());
for item in results {
if let Value::SingleString(st) = item {
out.push(st);
}
}
Ok(Value::StrArray(out))
}
_ => Err("array:map => unrecognized type or mixing? (string vs int?)".to_string()),
}
}
Value::FloatArray(ff) => {
let mut out = Vec::new();
for x in ff {
let ret = apply_one_function_value(interp, Box::new(map_fn.clone()), Value::Float(x))?;
match ret {
Value::Float(y) => out.push(y),
other => {
return Err(format!(
"array:map => user function returned non-float: {:?}",
other
));
}
}
}
Ok(Value::FloatArray(out))
}
Value::InkIterator(h) => {
match &h.kind {
InkIteratorKind::Core(state_arc) => {
let mut out = Vec::new();
let mut guard = state_arc.lock().map_err(|_| "InkIteratorState lock error".to_string())?;
while !guard.done && guard.current < guard.end {
let next_val = guard.current;
guard.current += 1;
if guard.current >= guard.end {
guard.done = true;
}
drop(guard);
let ret = apply_one_function_value(interp, Box::new(map_fn.clone()), Value::Int(next_val))?;
match ret {
Value::Int(i2) => out.push(i2),
other => {
return Err(format!("array:map => user function returned non-int: {:?}", other));
}
}
guard = state_arc.lock().map_err(|_| "InkIteratorState lock error".to_string())?;
}
Ok(Value::IntArray(out))
}
InkIteratorKind::Plugin(plugin_arc) => {
let mut out = Vec::new();
let mut plugin = plugin_arc.lock().map_err(|_| "Plugin InkIterator lock error".to_string())?;
loop {
match plugin.next_value() {
Ok(val) => {
let ret = apply_one_function_value(interp, Box::new(map_fn.clone()), val)?;
match ret {
Value::Int(i2) => out.push(i2),
_ => return Err("array:map => user function returned non-int for plugin iterator".to_string()),
}
}
Err(e) if e == "NO_MORE_DATA" => break,
Err(e) => return Err(e),
}
}
Ok(Value::IntArray(out))
}
}
}
other => Err(format!(
"array:map => only IntArray/StrArray/FloatArray + InkIterator supported, got {:?}",
other
)),
}
}
pub fn do_filter(
interp: &mut Interpreter,
pred_fn: &FunctionValue,
data_val: Value,
) -> Result<Value, String> {
use crate::parser::interpreter::apply::apply_one_function_value;
match data_val {
Value::IntArray(xs) => {
let mut out = Vec::new();
for x in xs {
let ret = apply_one_function_value(interp, Box::new(pred_fn.clone()), Value::Int(x))?;
match ret {
Value::Bool(flag) if flag => out.push(x),
Value::Bool(false) => {},
other => return Err(format!("array:filter => user function returned non-bool: {:?}", other)),
}
}
Ok(Value::IntArray(out))
}
Value::StrArray(ss) => {
let mut out = Vec::new();
for s in ss {
let ret = apply_one_function_value(interp, Box::new(pred_fn.clone()), Value::SingleString(s.clone()))?;
match ret {
Value::Bool(true) => out.push(s),
Value::Bool(false) => {},
other => return Err(format!("array:filter => user function returned non-bool: {:?}", other)),
}
}
Ok(Value::StrArray(out))
}
Value::InkIterator(h) => {
match &h.kind {
InkIteratorKind::Core(state_arc) => {
let mut out = Vec::new();
let mut guard = state_arc.lock().map_err(|_| "InkIteratorState lock error".to_string())?;
while !guard.done && guard.current < guard.end {
let next_val = guard.current;
guard.current += 1;
if guard.current >= guard.end {
guard.done = true;
}
drop(guard);
let ret = apply_one_function_value(interp, Box::new(pred_fn.clone()), Value::Int(next_val))?;
match ret {
Value::Bool(true) => out.push(Value::Int(next_val)),
Value::Bool(false) => {},
_ => return Err("array:filter => user function returned non-bool for core iterator".to_string()),
}
guard = state_arc.lock().map_err(|_| "InkIteratorState lock error".to_string())?;
}
Ok(Value::IntArray(out.into_iter().map(|v| match v {
Value::Int(i) => i,
_ => unreachable!(),
}).collect()))
}
InkIteratorKind::Plugin(plugin_arc) => {
let mut out = Vec::new();
let mut plugin = plugin_arc.lock().map_err(|_| "Plugin InkIterator lock error".to_string())?;
loop {
match plugin.next_value() {
Ok(val) => {
let ret = apply_one_function_value(interp, Box::new(pred_fn.clone()), val.clone())?;
match ret {
Value::Bool(true) => out.push(val),
Value::Bool(false) => {},
_ => return Err("array:filter => user function returned non-bool for plugin iterator".to_string()),
}
}
Err(e) if e == "NO_MORE_DATA" => break,
Err(e) => return Err(e),
}
}
Ok(Value::IntArray(out.into_iter().map(|v| match v {
Value::Int(i) => i,
_ => unreachable!(),
}).collect()))
}
}
}
other => Err(format!("array:filter => only IntArray/StrArray/InkIterator supported, got {:?}", other)),
}
}
pub fn apply_curried_map_placeholder(
interp: &mut Interpreter,
mut func: Option<Box<FunctionValue>>,
mut data: Option<Value>,
args: Vec<Value>,
) -> Result<Value, String> {
for val in args {
if func.is_none() {
match val {
Value::Function(fb) => func = Some(fb),
Value::Placeholder => {},
other => {
return Err(format!(
"CurriedMapPlaceholder => first param must be function or '_', got {:?}",
other
));
}
}
} else if data.is_none() {
match val {
Value::Placeholder => {},
x => data = Some(x),
}
} else {
return Err("array:map => extra argument(s) after function & data".to_string());
}
}
if let (Some(mf), Some(dat)) = (func.as_ref(), data.as_ref()) {
do_map(interp, mf, dat.clone())
} else {
Ok(Value::Function(Box::new(FunctionValue::CurriedMapPlaceholder {
func,
data,
})))
}
}
pub fn apply_curried_filter_placeholder(
interp: &mut Interpreter,
mut pred: Option<Box<FunctionValue>>,
mut data: Option<Value>,
args: Vec<Value>,
) -> Result<Value, String> {
for val in args {
if pred.is_none() {
match val {
Value::Function(fb) => pred = Some(fb),
Value::Placeholder => {},
other => {
return Err(format!(
"CurriedFilterPlaceholder => first param must be function or '_', got {:?}",
other
));
}
}
} else if data.is_none() {
match val {
Value::Placeholder => {},
v => data = Some(v),
}
} else {
return Err("array:filter => extra arg(s) after function & data".to_string());
}
}
if let (Some(pf), Some(dat)) = (pred.as_ref(), data.as_ref()) {
do_filter(interp, pf, dat.clone())
} else {
Ok(Value::Function(Box::new(FunctionValue::CurriedFilterPlaceholder {
pred,
data,
})))
}
}
pub fn apply_curried_reduce_partial(
_interp: &mut Interpreter,
f_box: Box<FunctionValue>,
init_val: Value,
args: Vec<Value>,
) -> Result<Value, String> {
if args.is_empty() {
Ok(Value::Function(Box::new(FunctionValue::CurriedReducePlaceholder {
func: Some(f_box),
init_val: Some(init_val),
data: None,
})))
} else if args.len() == 1 {
Err("reduce => not fully implemented".to_string())
} else {
Err(format!("CurriedReducePartial => expected 0 or 1 arg, got {}", args.len()))
}
}
pub fn apply_curried_reduce_placeholder(
_interp: &mut Interpreter,
mut func: Option<Box<FunctionValue>>,
mut init_val: Option<Value>,
mut data: Option<Value>,
args: Vec<Value>,
) -> Result<Value, String> {
for val in args {
if func.is_none() {
match val {
Value::Function(fb) => func = Some(fb),
Value::Placeholder => {},
other => {
return Err(format!(
"array:reduce => first param must be function or '_', got {:?}",
other
));
}
}
} else if init_val.is_none() {
match val {
Value::Placeholder => {},
x => init_val = Some(x),
}
} else if data.is_none() {
match val {
Value::Placeholder => {},
x => data = Some(x),
}
} else {
return Err("array:reduce => extra arg(s) after function, init, data".to_string());
}
}
if let (Some(_f), Some(_ini), Some(_dat)) = (func.as_ref(), init_val.as_ref(), data.as_ref()) {
Err("reduce => final bridging not fully implemented".to_string())
} else {
Ok(Value::Function(Box::new(FunctionValue::CurriedReducePlaceholder {
func,
init_val,
data,
})))
}
}