use crate::*;
use std::collections::HashMap;
#[derive(Clone,Debug, PartialEq, Eq, Hash)]
pub enum SimpleVal {
Int(i32),
List(Vec<Val>),
}
#[derive(Clone,Debug, PartialEq, Eq, Hash)]
pub enum SimpleType {
TInt,
TList
}
type Val = crate::eval::Val<SimpleVal>;
type LazyVal = crate::eval::LazyVal<SimpleVal>;
type Evaluator<'a> = crate::eval::Evaluator<'a,SimpleVal>;
type VResult = crate::eval::VResult<SimpleVal>;
type DSLFn = crate::dsl::DSLFn<SimpleVal>;
use SimpleVal::*;
use crate::eval::Val::*;
define_semantics! {
SimpleVal;
"+" = (add, "int -> int -> int"),
"*" = (mul, "int -> int -> int"),
"map" = (map, "(t0 -> t1) -> (list t0) -> (list t1)"),
"sum" = (sum, "list int -> int"),
"0" = "int",
"1" = "int",
"2" = "int",
"[]" = "(list t0)",
}
impl FromVal<SimpleVal> for i32 {
fn from_val(v: Val) -> Result<Self, VError> {
match v {
Dom(Int(i)) => Ok(i),
_ => Err("from_val_to_i32: not an int".into())
}
}
}
impl<T: FromVal<SimpleVal>> FromVal<SimpleVal> for Vec<T> {
fn from_val(v: Val) -> Result<Self, VError> {
match v {
Dom(List(v)) => v.into_iter().map(|v| T::from_val(v)).collect(),
_ => Err("from_val_to_vec: not a list".into())
}
}
}
impl From<i32> for Val {
fn from(i: i32) -> Val {
Dom(Int(i))
}
}
impl<T: Into<Val>> From<Vec<T>> for Val {
fn from(vec: Vec<T>) -> Val {
Dom(List(vec.into_iter().map(|v| v.into()).collect()))
}
}
impl Domain for SimpleVal {
type Data = ();
fn val_of_prim_fallback(p: Symbol) -> Option<Val> {
if p.as_str().chars().next().unwrap().is_ascii_digit() {
let i: i32 = p.as_str().parse().ok()?;
Some(Int(i).into())
}
else if p.as_str().starts_with('[') {
let intvec: Vec<i32> = serde_json::from_str(p.as_str()).ok()?;
let valvec: Vec<Val> = intvec.into_iter().map(|v|Dom(Int(v))).collect();
Some(List(valvec).into())
} else {
None
}
}
dsl_entries_lookup_gen!();
fn type_of_dom_val(&self) -> Type {
match self {
Int(_) => Type::base("int".into()),
List(xs) => {
let elem_tp = if xs.is_empty() {
Type::Var(0) } else {
Self::type_of_dom_val(&xs.first().unwrap().clone().dom().unwrap())
};
Type::Term("list".into(),vec![elem_tp])
},
}
}
}
fn add(mut args: Vec<LazyVal>, handle: &Evaluator) -> VResult {
load_args!(handle, args, x:i32, y:i32);
ok(x+y)
}
fn mul(mut args: Vec<LazyVal>, handle: &Evaluator) -> VResult {
load_args!(handle, args, x:i32, y:i32);
ok(x*y)
}
fn map(mut args: Vec<LazyVal>, handle: &Evaluator) -> VResult {
load_args!(handle, args, fn_val: Val, xs: Vec<Val>);
ok(xs.into_iter()
.map(|x| handle.apply(&fn_val, x))
.collect::<Result<Vec<Val>,_>>()?)
}
fn sum(mut args: Vec<LazyVal>, handle: &Evaluator) -> VResult {
load_args!(handle, args, xs: Vec<i32>);
ok(xs.iter().sum::<i32>())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_types_simple() {
use domains::simple::SimpleVal;
fn assert_unify(t1: &str, t2: &str, expected: UnifyResult) {
let mut ctx = Context::empty();
let res = ctx.unify(&t1.parse::<Type>().unwrap(),
&t2.parse::<Type>().unwrap());
assert_eq!(res, expected);
let mut typeset = TypeSet::empty();
let t1 = typeset.add_tp(&t1.parse::<Type>().unwrap()).instantiate(&mut typeset);
let t2 = typeset.add_tp(&t2.parse::<Type>().unwrap()).instantiate(&mut typeset);
let res = typeset.unify(&t1,&t2);
assert_eq!(res, expected);
}
fn assert_infer(p: &str, expected: Result<&str, UnifyErr>) {
let res = p.parse::<Expr>().unwrap().infer::<SimpleVal>(None, &mut Context::empty(), &mut Default::default());
assert_eq!(res, expected.map(|ty| ty.parse::<Type>().unwrap()));
}
assert_unify("int", "int", Ok(()));
assert_unify("int", "t0", Ok(()));
assert_unify("int", "t1", Ok(()));
assert_unify("(list int)", "(list t1)", Ok(()));
assert_unify("(int -> bool)", "(int -> t0)", Ok(()));
assert_unify("t0", "t1", Ok(()));
assert_infer("3", Ok("int"));
assert_infer("[1,2,3]", Ok("list int"));
assert_infer("(+ 2 3)", Ok("int"));
assert_infer("(lam $0)", Ok("t0 -> t0"));
assert_infer("(lam (+ $0 1))", Ok("int -> int"));
assert_infer("map", Ok("((t0 -> t1) -> (list t0) -> (list t1))"));
assert_infer("(map (lam (+ $0 1)))", Ok("list int -> list int"));
}
#[test]
fn test_eval_simple() {
assert_execution::<domains::simple::SimpleVal, i32>("(+ 1 2)", &[], 3);
assert_execution::<domains::simple::SimpleVal, i32>("(sum (map (lam $0) []))", &[], 0);
let arg = SimpleVal::val_of_prim("[1,2,3]".into()).unwrap();
assert_execution("(map (lam (+ 1 $0)) $0)", &[arg], vec![2,3,4]);
let arg = SimpleVal::val_of_prim("[1,2,3]".into()).unwrap();
assert_execution("(sum (map (lam (+ 1 $0)) $0))", &[arg], 9);
let arg = SimpleVal::val_of_prim("[1,2,3]".into()).unwrap();
assert_execution("(map (lam (* $0 $0)) (map (lam (+ 1 $0)) $0))", &[arg], vec![4,9,16]);
let arg = SimpleVal::val_of_prim("[1,2,3]".into()).unwrap();
assert_execution("(map (lam (* $0 $0)) (map (lam (+ (sum $1) $0)) $0))", &[arg], vec![49,64,81]);
}
}