1use crate::{
4 error::Error,
5 eval::{CompileContext, C},
6 span::{ResultExt, Span, SpanExt, S},
7 value::Value,
8};
9
10use std::{convert::TryFrom, fmt::Debug};
11
12pub mod array;
13pub mod debug;
14pub mod ops;
15pub mod rand;
16pub mod string;
17pub mod time;
18
19pub type Arguments = smallvec::SmallVec<[S<Value>; 2]>;
21
22pub trait Function: Sync + Debug {
24 fn compile(&self, ctx: &CompileContext, span: Span, args: Arguments) -> Result<C, S<Error>>;
26}
27
28trait TryFromSpannedValue: Sized {
29 fn try_from_spanned_value(value: S<Value>) -> Result<Self, S<Error>>;
30}
31
32impl<T> TryFromSpannedValue for T
33where
34 T: TryFrom<Value>,
35 Error: From<T::Error>,
36{
37 fn try_from_spanned_value(value: S<Value>) -> Result<Self, S<Error>> {
38 let span = value.span;
39 Self::try_from(value.inner).span_err(span)
40 }
41}
42
43impl TryFromSpannedValue for S<String> {
44 fn try_from_spanned_value(value: S<Value>) -> Result<Self, S<Error>> {
45 String::try_from(value.inner).span_ok_err(value.span)
46 }
47}
48
49impl TryFromSpannedValue for S<Value> {
50 fn try_from_spanned_value(value: S<Value>) -> Result<Self, S<Error>> {
51 Ok(value)
52 }
53}
54
55macro_rules! declare_arg_fn {
56 (
57 $(#[$meta:meta])*
58 fn $name:ident($($def:ident: $ty:ident),+);
59 ) => {
60 $(#[$meta])*
61 fn $name<$($ty),+>(span: Span, args: Arguments, $($def: Option<$ty>),+) -> Result<($($ty),+), S<Error>>
62 where
63 $($ty: TryFromSpannedValue,)+
64 {
65 let mut it = args.into_iter();
66 $(
67 let $def = if let Some(arg) = it.next() {
68 $ty::try_from_spanned_value(arg)
69 } else {
70 $def.ok_or(Error::NotEnoughArguments.span(span))
71 }?;
72 )+
73 Ok(($($def),+))
74 }
75 }
76}
77
78declare_arg_fn! {
79 #[allow(unused_parens)] fn args_1(d1: T1);
82}
83declare_arg_fn! {
84 fn args_2(d1: T1, d2: T2);
86}
87declare_arg_fn! {
88 fn args_3(d1: T1, d2: T2, d3: T3);
90}
91declare_arg_fn! {
92 fn args_4(d1: T1, d2: T2, d3: T3, d4: T4);
94}
95
96fn iter_args<T>(args: Arguments) -> impl Iterator<Item = Result<T, S<Error>>>
98where
99 T: TryFromSpannedValue,
100{
101 args.into_iter().map(T::try_from_spanned_value)
102}
103
104fn require(span: Span, cond: bool, cause: impl FnOnce() -> String) -> Result<(), S<Error>> {
105 if cond {
106 Ok(())
107 } else {
108 Err(Error::InvalidArguments(cause()).span(span))
109 }
110}