#![allow(unused_mut)]
#![allow(unused_parens)]
#![allow(unused_variables)]
use crate::*;
use crate::runtime::*;
use crate::{lang::{Varity, Parameter, Identifier}, stdlib::RantStdResult};
use cast::*;
use cast::Error as CastError;
use std::{rc::Rc, ops::{DerefMut, Deref}, convert::TryInto};
pub trait IntoRant: Sized {
fn into_rant(self) -> RantValue;
}
pub trait TryIntoRant: Sized {
fn try_into_rant(self) -> Result<RantValue, ValueError>;
}
pub trait FromRant: Sized {
fn from_rant(val: RantValue) -> Self;
fn is_optional_param_type() -> bool {
false
}
}
pub trait TryFromRant: Sized {
fn try_from_rant(val: RantValue) -> Result<Self, ValueError>;
fn is_optional_param_type() -> bool {
false
}
}
trait IntoCastResult<T> {
fn into_cast_result(self) -> Result<T, CastError>;
}
impl<T> IntoCastResult<T> for Result<T, CastError> {
fn into_cast_result(self) -> Result<T, CastError> {
self
}
}
impl IntoCastResult<i64> for i64 {
fn into_cast_result(self) -> Result<i64, CastError> {
Ok(self)
}
}
fn rant_cast_error(from: &'static str, to: &'static str, err: CastError) -> ValueError {
ValueError::InvalidConversion {
from,
to,
message: Some(match err {
CastError::Overflow => "integer overflow",
CastError::Underflow => "integer underflow",
CastError::Infinite => "infinity",
CastError::NaN => "NaN"
}.to_owned())
}
}
macro_rules! rant_fallible_int_conversions {
($int_type: ident) => {
impl TryIntoRant for $int_type {
fn try_into_rant(self) -> ValueResult<RantValue> {
match i64(self).into_cast_result() {
Ok(i) => Ok(RantValue::Int(i)),
Err(err) => Err(rant_cast_error(
stringify!($int_type),
stringify!(RantValue::Int),
err
))
}
}
}
impl TryFromRant for $int_type {
fn try_from_rant(val: RantValue) -> ValueResult<Self> {
macro_rules! cast_int {
(i64, $val:expr) => {
Ok($val)
};
(isize, $val:expr) => {
{
let val = $val;
val.try_into().map_err(|_| if val < 0 {
CastError::Underflow
} else {
CastError::Overflow
})
}
};
($to:ident, $val:expr) => {
$to($val)
};
}
macro_rules! cast_float_to_int {
(i64, $val:expr) => {
Ok($val as i64)
};
($to:ident, $val:expr) => {
$to($val)
};
}
match val {
RantValue::Int(i) => {
let result: Result<$int_type, CastError> = cast_int!($int_type, i);
match result {
Ok(i) => Ok(i),
Err(err) => Err(rant_cast_error(
val.type_name(),
stringify!($int_type),
err
))
}
},
RantValue::Float(f) => {
let result: Result<$int_type, CastError> = cast_float_to_int!($int_type, f);
match result {
Ok(i) => Ok(i),
Err(err) => Err(rant_cast_error(
val.type_name(),
stringify!($int_type),
err
))
}
},
_ => {
let src_type = val.type_name();
let dest_type = stringify!{$int_type};
Err(ValueError::InvalidConversion {
from: src_type,
to: dest_type,
message: None
})
}
}
}
}
};
($int_type: ident, $($int_type2: ident), *) => {
rant_fallible_int_conversions! { $int_type }
rant_fallible_int_conversions! { $($int_type2), + }
};
}
macro_rules! converts_from_rant {
($param:ident -> $t:ty $b:block) => {
impl FromRant for $t {
fn from_rant($param: RantValue) -> $t {
$b
}
}
impl TryFromRant for $t {
fn try_from_rant(val: RantValue) -> Result<$t, ValueError> {
Ok(<$t as FromRant>::from_rant(val))
}
}
}
}
macro_rules! converts_into_rant {
($param:ident: $t:ty $b:block) => {
impl IntoRant for $t {
fn into_rant(self) -> RantValue {
let $param = self;
$b
}
}
impl TryIntoRant for $t {
fn try_into_rant(self) -> Result<RantValue, ValueError> {
Ok(IntoRant::into_rant(self))
}
}
}
}
rant_fallible_int_conversions! { u8, i8, u16, i16, u32, i32, u64, i64, isize, usize }
converts_from_rant!(v -> RantNothing { Self });
converts_from_rant!(v -> RantValue { v });
converts_from_rant!(v -> bool { v.to_bool() });
converts_from_rant!(v -> InternalString { v.to_string().into() });
converts_from_rant!(v -> RantString { v.to_string().into() });
converts_from_rant!(v -> String { v.to_string() });
converts_into_rant!(v: RantValue { v });
converts_into_rant!(v: RantNothing { RantValue::Nothing });
converts_into_rant!(v: bool { RantValue::Boolean(v) });
converts_into_rant!(v: char { RantValue::String(RantString::from(v)) });
converts_into_rant!(v: f32 { RantValue::Float(v as f64) });
converts_into_rant!(v: f64 { RantValue::Float(v) });
converts_into_rant!(v: String { RantValue::String(v.into()) });
converts_into_rant!(v: RantString { RantValue::String(v) });
converts_into_rant!(v: InternalString { RantString::from(v.as_str()).into_rant() });
converts_into_rant!(v: RantMap { RantValue::Map(v.into_handle()) });
converts_into_rant!(v: RantMapHandle { RantValue::Map(v) });
converts_into_rant!(v: RantList { RantValue::List(v.into_handle()) });
converts_into_rant!(v: RantListHandle { RantValue::List(v) });
converts_into_rant!(v: RantTuple { RantValue::Tuple(v.into_handle()) });
converts_into_rant!(v: RantTupleHandle { RantValue::Tuple(v) });
converts_into_rant!(v: RantSelector { RantValue::Selector(v.into_handle()) });
converts_into_rant!(v: RantSelectorHandle { RantValue::Selector(v) });
converts_into_rant!(v: RantRange { RantValue::Range(v) });
impl<'a> IntoRant for &'a str {
fn into_rant(self) -> RantValue {
RantValue::String(self.into())
}
}
impl<'a> TryIntoRant for &'a str {
fn try_into_rant(self) -> Result<RantValue, ValueError> {
Ok(self.into_rant())
}
}
impl IntoRant for isize {
fn into_rant(self) -> RantValue {
RantValue::Int(self as i64)
}
}
impl IntoRant for i64 {
fn into_rant(self) -> RantValue {
RantValue::Int(self)
}
}
impl IntoRant for i32 {
fn into_rant(self) -> RantValue {
RantValue::Int(self as i64)
}
}
impl IntoRant for u32 {
fn into_rant(self) -> RantValue {
RantValue::Int(self as i64)
}
}
impl IntoRant for i16 {
fn into_rant(self) -> RantValue {
RantValue::Int(self as i64)
}
}
impl IntoRant for u16 {
fn into_rant(self) -> RantValue {
RantValue::Int(self as i64)
}
}
impl IntoRant for i8 {
fn into_rant(self) -> RantValue {
RantValue::Int(self as i64)
}
}
impl IntoRant for u8 {
fn into_rant(self) -> RantValue {
RantValue::Int(self as i64)
}
}
impl TryFromRant for f32 {
fn try_from_rant(val: RantValue) -> ValueResult<Self> {
match val {
RantValue::Int(i) => Ok(f32(i)),
RantValue::Float(f) => match f32(f) {
Ok(f) => Ok(f),
Err(err) => Err(rant_cast_error(val.type_name(), "f32", err))
},
_ => Err(ValueError::InvalidConversion {
from: val.type_name(),
to: "f32",
message: Some(format!("Rant value type '{}' cannot be converted to f32", val.type_name()))
})
}
}
}
impl TryFromRant for f64 {
fn try_from_rant(val: RantValue) -> ValueResult<Self> {
match val {
RantValue::Int(i) => Ok(f64(i)),
RantValue::Float(f) => Ok(f),
_ => Err(ValueError::InvalidConversion {
from: val.type_name(),
to: "f64",
message: Some(format!("Rant value type '{}' cannot be converted to f64", val.type_name()))
})
}
}
}
impl<T: IntoRant> IntoRant for Vec<T> {
fn into_rant(mut self) -> RantValue {
let list = self.drain(..).map(|v| v.into_rant()).collect::<RantList>();
RantValue::List(list.into_handle())
}
}
impl<T: TryIntoRant> TryIntoRant for Vec<T> {
fn try_into_rant(mut self) -> Result<RantValue, ValueError> {
let list = self.drain(..).map(|v| v.try_into_rant()).collect::<Result<RantList, ValueError>>()?;
Ok(list.into_rant())
}
}
impl TryFromRant for RantTupleHandle {
fn try_from_rant(val: RantValue) -> ValueResult<Self> {
if let RantValue::Tuple(tuple_ref) = val {
Ok(tuple_ref)
} else {
Err(ValueError::InvalidConversion { from: val.type_name(), to: RantValueType::Tuple.name(), message: None })
}
}
}
impl TryFromRant for RantListHandle {
fn try_from_rant(val: RantValue) -> ValueResult<Self> {
if let RantValue::List(list_ref) = val {
Ok(list_ref)
} else {
Err(ValueError::InvalidConversion { from: val.type_name(), to: RantValueType::List.name(), message: None })
}
}
}
impl TryFromRant for RantMapHandle {
fn try_from_rant(val: RantValue) -> ValueResult<Self> {
if let RantValue::Map(map_ref) = val {
Ok(map_ref)
} else {
Err(ValueError::InvalidConversion { from: val.type_name(), to: RantValueType::Map.name(), message: None })
}
}
}
impl TryFromRant for RantFunctionHandle {
fn try_from_rant(val: RantValue) -> Result<Self, ValueError> {
if let RantValue::Function(func_ref) = val {
Ok(func_ref)
} else {
Err(ValueError::InvalidConversion { from: val.type_name(), to: RantValueType::Function.name(), message: None })
}
}
}
impl TryFromRant for RantSelectorHandle {
fn try_from_rant(val: RantValue) -> Result<Self, ValueError> {
if let RantValue::Selector(sel_ref) = val {
Ok(sel_ref)
} else {
Err(ValueError::InvalidConversion { from: val.type_name(), to: RantValueType::Selector.name(), message: None })
}
}
}
impl<T: TryFromRant> TryFromRant for Option<T> {
fn try_from_rant(val: RantValue) -> ValueResult<Self> {
match val {
RantValue::Nothing => Ok(None),
other => Ok(Some(T::try_from_rant(other)?))
}
}
fn is_optional_param_type() -> bool {
true
}
}
impl<T: TryIntoRant> TryIntoRant for Option<T> {
fn try_into_rant(self) -> ValueResult<RantValue> {
match self {
Some(val) => Ok(val.try_into_rant()?),
None => Ok(RantValue::Nothing),
}
}
}
impl<T: IntoRant> IntoRant for Option<T> {
fn into_rant(self) -> RantValue {
match self {
Some(val) => val.into_rant(),
None => RantValue::Nothing,
}
}
}
impl<T: TryFromRant> TryFromRant for Vec<T> {
fn try_from_rant(val: RantValue) -> ValueResult<Self> {
match val {
RantValue::List(vec) => Ok(vec.borrow().iter().cloned().map(T::try_from_rant).collect::<ValueResult<Vec<T>>>()?),
other => Err(ValueError::InvalidConversion {
from: other.type_name(),
to: stringify!(Vec<T>),
message: Some("only lists can be turned into vectors".to_owned())
})
}
}
}
#[inline(always)]
fn as_varity<T: TryFromRant>() -> Varity {
if T::is_optional_param_type() {
Varity::Optional
} else {
Varity::Required
}
}
#[inline(always)]
fn inc(counter: &mut usize) -> usize {
let prev = *counter;
*counter += 1;
prev
}
pub trait FromRantArgs: Sized {
fn from_rant_args(args: Vec<RantValue>) -> ValueResult<Self>;
fn as_rant_params() -> Vec<Parameter>;
}
impl<T: TryFromRant> FromRantArgs for T {
fn from_rant_args(args: Vec<RantValue>) -> ValueResult<Self> {
let mut args = args.into_iter();
T::try_from_rant(args.next().unwrap_or(RantValue::Nothing))
}
fn as_rant_params() -> Vec<Parameter> {
let varity = if T::is_optional_param_type() {
Varity::Optional
} else {
Varity::Required
};
let param = Parameter {
name: Identifier::new(InternalString::from("arg0")),
varity,
default_value_expr: None,
};
vec![param]
}
}
pub struct VarArgs<T: TryFromRant>(Vec<T>);
impl<T: TryFromRant> VarArgs<T> {
pub fn new(args: Vec<T>) -> Self {
Self(args)
}
}
impl<T: TryFromRant> Deref for VarArgs<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: TryFromRant> DerefMut for VarArgs<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T: TryFromRant> VarArgs<T> {
#[inline]
pub fn into_vec(self) -> Vec<T> {
self.0
}
}
pub struct RequiredVarArgs<T: TryFromRant>(Vec<T>);
impl<T: TryFromRant> RequiredVarArgs<T> {
pub fn new(args: Vec<T>) -> Self {
Self(args)
}
}
impl<T: TryFromRant> Deref for RequiredVarArgs<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: TryFromRant> DerefMut for RequiredVarArgs<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
macro_rules! impl_from_rant_args {
($($generic_types:ident),*) => {
impl<$($generic_types: TryFromRant,)*> FromRantArgs for ($($generic_types,)*) {
fn from_rant_args(args: Vec<RantValue>) -> ValueResult<Self> {
let mut args = args.into_iter();
Ok(($($generic_types::try_from_rant(args.next().unwrap_or(RantValue::Nothing))?,)*))
}
fn as_rant_params() -> Vec<Parameter> {
let mut i: usize = 0;
vec![$(Parameter {
name: Identifier::new(InternalString::from(format!("arg{}", inc(&mut i)))),
varity: as_varity::<$generic_types>(),
default_value_expr: None,
},)*]
}
}
impl<$($generic_types: TryFromRant,)* VarArgItem: TryFromRant> FromRantArgs for ($($generic_types,)* VarArgs<VarArgItem>) {
fn from_rant_args(mut args: Vec<RantValue>) -> ValueResult<Self> {
let mut args = args.drain(..);
Ok(
($($generic_types::try_from_rant(args.next().unwrap_or(RantValue::Nothing))?,)*
VarArgs::new(args
.map(VarArgItem::try_from_rant)
.collect::<ValueResult<Vec<VarArgItem>>>()?
)
))
}
fn as_rant_params() -> Vec<Parameter> {
let mut i: usize = 0;
vec![$(Parameter {
name: Identifier::new(InternalString::from(format!("arg{}", inc(&mut i)))),
varity: as_varity::<$generic_types>(),
default_value_expr: None,
},)*
Parameter {
name: Identifier::new(InternalString::from(format!("arg{}", inc(&mut i)))),
varity: Varity::VariadicStar,
default_value_expr: None,
}]
}
}
impl<$($generic_types: TryFromRant,)* VarArgItem: TryFromRant> FromRantArgs for ($($generic_types,)* RequiredVarArgs<VarArgItem>) {
fn from_rant_args(mut args: Vec<RantValue>) -> ValueResult<Self> {
let mut args = args.drain(..);
Ok(
($($generic_types::try_from_rant(args.next().unwrap_or(RantValue::Nothing))?,)*
RequiredVarArgs::new(args
.map(VarArgItem::try_from_rant)
.collect::<ValueResult<Vec<VarArgItem>>>()?
)
))
}
fn as_rant_params() -> Vec<Parameter> {
let mut i: usize = 0;
vec![$(Parameter {
name: Identifier::new(InternalString::from(format!("arg{}", inc(&mut i)))),
varity: as_varity::<$generic_types>(),
default_value_expr: None,
},)*
Parameter {
name: Identifier::new(InternalString::from(format!("arg{}", inc(&mut i)))),
varity: Varity::VariadicPlus,
default_value_expr: None,
}]
}
}
}
}
impl_from_rant_args!();
impl_from_rant_args!(A);
impl_from_rant_args!(A, B);
impl_from_rant_args!(A, B, C);
impl_from_rant_args!(A, B, C, D);
impl_from_rant_args!(A, B, C, D, E);
impl_from_rant_args!(A, B, C, D, E, F);
impl_from_rant_args!(A, B, C, D, E, F, G);
impl_from_rant_args!(A, B, C, D, E, F, G, H);
impl_from_rant_args!(A, B, C, D, E, F, G, H, I);
impl_from_rant_args!(A, B, C, D, E, F, G, H, I, J);
impl_from_rant_args!(A, B, C, D, E, F, G, H, I, J, K);
pub trait IntoRantFunction<Params: FromRantArgs> {
fn into_rant_func(self) -> RantFunction;
}
impl<Params: FromRantArgs, Function: 'static + Fn(&mut VM, Params) -> RantStdResult> IntoRantFunction<Params> for Function {
fn into_rant_func(self) -> RantFunction {
let body = RantFunctionInterface::Foreign(Rc::new(move |vm, args| {
self(vm, Params::from_rant_args(args).into_runtime_result()?)
}));
let params = Rc::new(Params::as_rant_params());
RantFunction {
body,
captured_vars: vec![],
min_arg_count: params.iter().take_while(|p| p.is_required()).count(),
vararg_start_index: params.iter()
.enumerate()
.find_map(|(i, p)| if p.varity.is_variadic() { Some(i) } else { None })
.unwrap_or_else(|| params.len()),
params,
flavor: None,
}
}
}