use std::{collections::HashMap, fmt::Debug, ops::Range, sync::Arc, str::FromStr};
use primitive_types::U256;
use kindelia_common::{crypto, Name, U120};
use kindelia_lang::ast::{Func, Oper, Rule, Statement, Term, Var};
use proptest::{
arbitrary::any,
array,
collection::{hash_map, vec},
option, prop_oneof,
strategy::{Just, Strategy},
};
use crate::runtime::functions::{CompFunc, CompRule};
use crate::runtime::{
init_loc_map, init_name_map, init_u120_map, init_u128_map, Arits, Funcs,
Hashs, Heap, Indxs, Loc, Nodes, Ownrs, RawCell, Rollback, Runtime, Store,
};
use crate::{
net::Address,
node::{hash_bytes, Block, Body, Message, Peer, Transaction},
util::{LocMap, NameMap, U120Map, U128Map},
};
pub fn name() -> impl Strategy<Value = Name> {
"[a-z][a-zA-Z0-9_]{1,11}"
.prop_filter("Differente than 'ask'", |s| s != "ask")
.prop_filter("Differente than 'let'", |s| s != "let")
.prop_filter("Differente than 'dup'", |s| s != "dup")
.prop_map(|s| Name::from_str(&s).unwrap())
}
pub fn u120() -> impl Strategy<Value = U120> {
(0_u128..*(U120::MAX) + 1).prop_map(|n| n.try_into().unwrap())
}
pub fn loc() -> impl Strategy<Value = Loc> {
(0_u64..Loc::_MAX + 1).prop_map(|n| Loc::new(n).unwrap())
}
pub fn rawcell() -> impl Strategy<Value = RawCell> {
(any::<u128>()).prop_map(|n| RawCell::new_unchecked(n))
}
pub fn small_name() -> impl Strategy<Value = Name> {
"[A-Z][a-zA-Z0-9_]{0,11}".prop_map(|s| Name::from_str(&s).unwrap())
}
pub fn term() -> impl Strategy<Value = Term> {
let leaf = prop_oneof![
name().prop_map(|n| Term::Var { name: n }),
u120().prop_map(|n| Term::Num { numb: n }),
];
leaf.prop_recursive(
16, 256, 10, |inner| {
prop_oneof![
(name(), name(), inner.clone(), inner.clone()).prop_map(
|(n0, n1, e, b)| {
Term::Dup {
nam0: n0,
nam1: n1,
expr: Box::new(e),
body: Box::new(b),
}
}
),
(name(), inner.clone())
.prop_map(|(n, e)| { Term::Lam { name: n, body: Box::new(e) } }),
(inner.clone(), inner.clone()).prop_map(|(f, a)| {
Term::App { func: Box::new(f), argm: Box::new(a) }
}),
(small_name(), vec(inner.clone(), 0..10))
.prop_map(|(n, v)| { Term::Ctr { name: n, args: v } }),
(small_name(), vec(inner.clone(), 0..10))
.prop_map(|(n, v)| { Term::Fun { name: n, args: v } }),
(oper(), inner.clone(), inner).prop_map(|(o, v0, v1)| {
Term::Op2 { oper: o, val0: Box::new(v0), val1: Box::new(v1) }
}),
]
},
)
}
pub fn op2(operator: Range<u128>) -> impl Strategy<Value = Term> {
(operator, u120(), u120()).prop_map(|(op, a, b)| Term::Op2 {
oper: op.try_into().unwrap(),
val0: Box::new(Term::Num { numb: a }),
val1: Box::new(Term::Num { numb: b }),
})
}
fn oper() -> impl Strategy<Value = Oper> {
(0_u128..16_u128).prop_map(|v| v.try_into().unwrap())
}
fn fun() -> impl Strategy<Value = Term> {
(small_name(), vec(term(), 0..32))
.prop_map(|(n, b)| Term::Fun { name: n, args: b })
}
pub fn rule() -> impl Strategy<Value = Rule> {
(fun(), term()).prop_map(|(lhs, rhs)| Rule { lhs, rhs })
}
pub fn func() -> impl Strategy<Value = Func> {
vec(rule(), 0..10).prop_map(|rules| Func { rules })
}
pub fn sign() -> impl Strategy<Value = crypto::Signature> {
(vec(any::<u8>(), 65)).prop_map(|s| crypto::Signature(s.try_into().unwrap()))
}
pub fn statement() -> impl Strategy<Value = Statement> {
prop_oneof![
(small_name(), vec(name(), 0..10), func(), term(), option::of(sign()))
.prop_map(|(name, args, func, init, sign)| {
Statement::Fun { name, args, func, init: Some(init), sign }
}),
(small_name(), vec(name(), 0..10), option::of(sign()))
.prop_map(|(name, args, sign)| { Statement::Ctr { name, args, sign } }),
(term(), option::of(sign()))
.prop_map(|(t, s)| { Statement::Run { expr: t, sign: s } }),
(name(), u120(), option::of(sign()))
.prop_map(|(name, ownr, sign)| { Statement::Reg { name, ownr, sign } }),
]
}
pub fn hash() -> impl Strategy<Value = crypto::Hash> {
(vec(any::<u8>(), 32)).prop_map(|h| crypto::Hash(h.try_into().unwrap()))
}
pub fn nodes() -> impl Strategy<Value = Nodes> {
(loc_map(rawcell())).prop_map(|m| Nodes { nodes: m })
}
pub fn map<A: std::fmt::Debug>(
s: impl Strategy<Value = A>,
) -> impl Strategy<Value = U128Map<A>> {
vec((any::<u128>(), s), 0..10).prop_map(|v| {
let mut m = init_u128_map();
for (k, v) in v {
m.insert(k, v);
}
m
})
}
pub fn name_map<A: std::fmt::Debug>(
s: impl Strategy<Value = A>,
) -> impl Strategy<Value = NameMap<A>> {
vec((name(), s), 0..10).prop_map(|v| {
let mut m = init_name_map();
for (k, v) in v {
m.insert(k, v);
}
m
})
}
pub fn u120_map<A: std::fmt::Debug>(
s: impl Strategy<Value = A>,
) -> impl Strategy<Value = U120Map<A>> {
vec((u120(), s), 0..10).prop_map(|v| {
let mut m = init_u120_map();
for (k, v) in v {
m.insert(k, v);
}
m
})
}
pub fn loc_map<A: std::fmt::Debug>(
s: impl Strategy<Value = A>,
) -> impl Strategy<Value = LocMap<A>> {
vec((loc(), s), 0..10).prop_map(|v| {
let mut m = init_loc_map();
for (k, v) in v {
m.insert(k, v);
}
m
})
}
pub fn store() -> impl Strategy<Value = Store> {
u120_map(rawcell()).prop_map(|m| Store { links: m })
}
pub fn arits() -> impl Strategy<Value = Arits> {
name_map(any::<u64>()).prop_map(|m| Arits { arits: m })
}
pub fn ownrs() -> impl Strategy<Value = Ownrs> {
name_map(u120()).prop_map(|m| Ownrs { ownrs: m })
}
pub fn indxs() -> impl Strategy<Value = Indxs> {
name_map(any::<u128>()).prop_map(|m| Indxs { indxs: m })
}
pub fn hashs() -> impl Strategy<Value = Hashs> {
map(hash()).prop_map(|m| Hashs { stmt_hashes: m })
}
pub fn var() -> impl Strategy<Value = Var> {
(name(), any::<u64>(), option::of(any::<u64>()), any::<bool>())
.prop_map(|(n, p, f, e)| Var { name: n, param: p, field: f, erase: e })
}
pub fn comp_rule() -> impl Strategy<Value = CompRule> {
(
vec(rawcell(), 0..32),
vec(var(), 0..32),
vec((any::<u64>(), any::<u64>()), 0..32),
term(),
)
.prop_map(|(c, v, e, b)| CompRule { cond: c, vars: v, eras: e, body: b })
}
pub fn comp_func() -> impl Strategy<Value = CompFunc> {
(func(), any::<u64>(), vec(any::<u64>(), 0..32), vec(comp_rule(), 0..32))
.prop_map(|(f, a, r, s)| CompFunc { func: f, arity: a, redux: r, rules: s })
}
pub fn funcs() -> impl Strategy<Value = Funcs> {
name_map(comp_func().prop_map(|cf| Arc::new(cf)))
.prop_map(|m| Funcs { funcs: m })
}
pub fn heap() -> impl Strategy<Value = Heap> {
let u64_tuple_strategy =
(any::<u64>(), any::<u64>(), any::<u64>(), any::<u64>());
let u128_tuple_strategy =
(any::<u128>(), any::<u128>(), any::<u128>(), any::<u128>(), any::<u128>());
(
u64_tuple_strategy,
u64_tuple_strategy,
u128_tuple_strategy,
nodes(),
store(),
arits(),
ownrs(),
funcs(),
indxs(),
hashs(),
)
.prop_map(
|(
(mcap, tick, funs, dups),
(mana, next, size, rwts),
(uuid, meta, hax1, hax0, time),
memo,
disk,
arit,
ownr,
file,
indx,
hash,
)| Heap {
mcap,
disk,
arit,
ownr,
hash,
indx,
file: Funcs { funcs: init_name_map() }, uuid,
memo,
tick,
funs,
dups,
rwts,
mana,
size,
next,
meta,
hax0,
hax1,
time,
},
)
}
pub fn u256() -> impl Strategy<Value = U256> {
array::uniform32(any::<u8>()).prop_map(|a| U256::from(a))
}
pub fn body() -> impl Strategy<Value = Body> {
vec(any::<u8>(), 0..128).prop_map(|v| Body { data: v })
}
pub fn block() -> impl Strategy<Value = Block> {
(any::<u128>(), any::<u128>(), u256(), body())
.prop_map(|(t, m, p, b)| crate::node::Block::new(p, m, t, b))
}
pub fn address() -> impl Strategy<Value = Address> {
(any::<u8>(), any::<u8>(), any::<u8>(), any::<u8>(), any::<u16>()).prop_map(
|(a, b, c, d, e)| Address::IPv4 {
val0: a,
val1: b,
val2: c,
val3: d,
port: e,
},
)
}
pub fn peer() -> impl Strategy<Value = Peer<Address>> {
(any::<u32>(), address())
.prop_map(|(s, a)| Peer { seen_at: s as u128, address: a })
}
pub fn transaction() -> impl Strategy<Value = Transaction> {
vec(any::<u8>(), 1..128).prop_map(|d| Transaction::new(d).unwrap()) }
pub fn message() -> impl Strategy<Value = Message<Address>> {
prop_oneof![
(any::<bool>(), vec(block(), 0..10), vec(peer(), 0..10), any::<u32>())
.prop_map(|(g, b, p, m)| Message::NoticeTheseBlocks {
gossip: g,
blocks: b,
peers: p,
magic: m
},),
(u256(), any::<u32>())
.prop_map(|(h, m)| Message::GiveMeThatBlock { bhash: h, magic: m }),
(transaction(), any::<u32>()).prop_map(|(t, m)| {
Message::PleaseMineThisTransaction { tx: t, magic: m }
})
]
}