use crate::coderef::{CodeRef, GroupRef};
use crate::permutation::Permutation;
use crate::program::Program;
use crate::entries::ExternEntry;
use crate::{EvalError, ValueAccessError};
use core::fmt::{Debug, Display, Formatter};
use lincoln_common::traits::{Access, AnyDebugDisplay};
use smallvec::SmallVec;
pub trait Value: AnyDebugDisplay {
fn eval(
self: Box<Self>,
ctx: &mut Context,
variant: u8,
) -> Result<CodeRef, EvalError>;
fn into_wrapped(self: Box<Self>) -> Option<Box<dyn Value>>;
}
struct Closure(SmallVec<[CodeRef; 5]>, Context);
impl Debug for Closure {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{}", self)
}
}
impl Display for Closure {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut it = self.0.iter();
write!(fmt, "[{{")?;
if let Some(cr) = it.next() {
write!(fmt, "{}", cr)?;
}
for cr in it {
write!(fmt, ";{}", cr)?;
}
write!(fmt, "}} {}]", self.1)
}
}
impl Value for Closure {
fn eval(
mut self: Box<Self>,
ctx: &mut Context,
variant: u8,
) -> Result<CodeRef, EvalError> {
ctx.append(&mut self.1);
if variant as usize >= self.0.len() {
Err(EvalError::VariantOutOfBound {
given: variant,
max: self.0.len() as u8,
})
} else {
Ok(self.0[variant as usize].clone())
}
}
fn into_wrapped(self: Box<Self>) -> Option<Box<dyn Value>> {
None
}
}
#[derive(Default)]
pub struct Context(Vec<Box<dyn Value>>);
impl std::fmt::Display for Context {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "(")?;
let mut it = self.0.iter();
if let Some(value) = it.next() {
write!(fmt, "{:?}", value)?;
}
for value in it {
write!(fmt, ",{:?}", value)?;
}
write!(fmt, ")")
}
}
impl Context {
pub fn expect_args(&self, args: u8) -> Result<(), EvalError> {
if self.len() != args {
return Err(EvalError::UnexpectedArgs {
expect: args,
actual: self.len(),
});
} else {
Ok(())
}
}
pub fn append(self: &mut Self, other: &mut Self) {
self.0.append(&mut other.0);
}
pub fn iterate(self: &mut Self) -> impl Iterator<Item = Box<dyn Value>> {
core::mem::replace(&mut self.0, vec![]).into_iter()
}
pub fn len(&self) -> u8 {
self.0.len() as u8
}
pub fn split(&mut self, at: u8) -> Result<Self, ValueAccessError> {
if at as usize > self.0.len() {
return Err(ValueAccessError::SplitOutOfRange {
at,
total: self.len(),
});
}
let r = self.0.split_off(at as usize);
let ctx2 = Context(r);
Ok(ctx2)
}
pub fn push(self: &mut Self, v: Box<dyn Value>) {
self.0.push(v)
}
pub fn pop(&mut self) -> Result<Box<dyn Value>, ValueAccessError> {
self.0.pop().ok_or(ValueAccessError::PopFromEmpty)
}
pub fn permutate(&mut self, p: Permutation) {
p.permutate(&mut self.0)
}
}
impl Drop for Context {
fn drop(&mut self) {}
}
pub(crate) fn closure_prog(
ent: GroupRef,
ctx: Context,
prog: &Program,
) -> Result<Box<dyn Value>, EvalError> {
if let Some(1) = ent.count(prog) {
if let Ok(CodeRef::Extern(ext)) = ent.get_entry(prog, 0) {
if let Some(ExternEntry::Value{value,..}) = ext.access(prog) {
ctx.expect_args(0)?;
return Ok(value.get_value());
}
}
}
Ok(Box::new(Closure(ent.get_vec(prog)?, ctx)))
}
struct Wrapped<T>(T);
impl<T> Debug for Wrapped<T>
where
T: Debug,
{
fn fmt(&self, fmt: &mut Formatter) -> core::fmt::Result {
write!(fmt, "|{:?}|", self.0)
}
}
impl<T> Display for Wrapped<T>
where
T: Display,
{
fn fmt(&self, fmt: &mut Formatter) -> core::fmt::Result {
write!(fmt, "|{}|", self.0)
}
}
impl<T> Value for Wrapped<T>
where
T: AnyDebugDisplay,
{
fn eval(
self: Box<Self>,
_: &mut Context,
_: u8,
) -> Result<CodeRef, EvalError> {
Err(EvalError::CallingWrapped)
}
fn into_wrapped(self: Box<Self>) -> Option<Box<dyn Value>> {
Some(self)
}
}
pub fn wrap<T>(t: T) -> Box<dyn Value>
where
T: AnyDebugDisplay,
{
Box::new(Wrapped(t))
}
pub fn unwrap<T>(v: Box<dyn Value>) -> Result<T, EvalError>
where
T: AnyDebugDisplay,
{
Ok(v.into_wrapped()
.ok_or(EvalError::from(ValueAccessError::UnwrapNotWrapped("fail into_wrapped".into())))?
.into_boxed_any()
.downcast::<Wrapped<T>>()
.map_err(|_| ValueAccessError::UnwrapNotWrapped("not Wrapped type".into()))?
.0)
}
struct WrappedFn<F>(String, F);
impl<F> Debug for WrappedFn<F>
where
F: FnOnce(&mut Context, u8) -> Result<CodeRef, EvalError>,
{
fn fmt(&self, fmt: &mut Formatter) -> core::fmt::Result {
write!(fmt, "{}", self.0)
}
}
impl<F> Display for WrappedFn<F>
where
F: FnOnce(&mut Context, u8) -> Result<CodeRef, EvalError>,
{
fn fmt(&self, fmt: &mut Formatter) -> core::fmt::Result {
write!(fmt, "{}", self.0)
}
}
impl<F> Value for WrappedFn<F>
where
F: FnOnce(&mut Context, u8) -> Result<CodeRef, EvalError> + 'static,
{
fn eval(
self: Box<Self>,
ctx: &mut Context,
variant: u8,
) -> Result<CodeRef, EvalError> {
self.1(ctx, variant)
}
fn into_wrapped(self: Box<Self>) -> Option<Box<dyn Value>> {
None
}
}
pub fn native_closure(
name: impl Into<String>,
f: impl FnOnce(&mut Context, u8) -> Result<CodeRef, EvalError> + 'static,
) -> Box<dyn Value> {
Box::new(WrappedFn(name.into(), f))
}