lang_interpreter/
macros.rs

1/// This macro generates a [Function](crate::interpreter::data::function::Function)
2/// instance for the given function identifier and metadata combination
3///
4/// The return type of this macro is `(FunctionMetadata, Box<dyn NativeFunctionAdapter>)`
5///
6/// The function provided to this macro must start with a parameter of type `&mut Interpreter` and
7/// the must be an implementation of [FromLangArgs](lang_interpreter::interpreter::data::function::native::FromLangArgs)
8/// for the tuple of all parameter types after the `&mut Interpreter`.
9///
10/// The return type of the function must one of the following:
11/// - `Result<OptionDataObjectRef, NativeError>`
12/// - `Result<DataObjectRet, NativeError>`
13/// - `Result<(), NativeError>`
14/// - `OptionDataObjectRef`
15/// - `DataObjectRef`
16/// - `()` (= No return value)
17///
18/// If move is used to capture local values in a closure,
19/// a copy for basic values (like i32) or a clone for Arc/Rc/Gc values must be created and must be
20/// provided to the second argument (`$value_dependencies`) (After function name and before function metadata) of this macro
21///
22/// # Arguments
23///
24/// ## 2 Argument variant
25///
26/// * `$func` - An identifier of a rust function or lambda
27/// * `$metadata` - The Lang function metadata ([FunctionMetadata](crate::interpreter::data::function::FunctionMetadata))
28///
29/// ## 3 Argument variant
30///
31/// * `$func` - An identifier of a rust function or lambda
32/// * `$value_dependencies` - A vector (`vec![val1, val2, ...]`) which contains all dependencies which are captured inside closure function
33///   (This is important for the equals and strict equals operators when comparing lang functions)
34/// * `$metadata` - The Lang function metadata ([FunctionMetadata](crate::interpreter::data::function::FunctionMetadata))
35///
36/// # Examples
37///
38/// ```
39/// use lang_interpreter::interpreter::data::{DataObject, DataObjectRef};
40/// use lang_interpreter::interpreter::data::function::{Function, FunctionMetadata, FunctionPointerObject, Parameter, ParameterType};
41/// use lang_interpreter::interpreter::{conversions, Interpreter};
42/// use lang_interpreter::{lang_func, lang_func_metadata};
43/// use lang_interpreter::lexer::CodePosition;
44///
45/// //The rust implementation of the lang native function "func.trim"
46/// fn trim_function(
47///     interpreter: &mut Interpreter,
48///     text_object: DataObjectRef,
49/// ) -> DataObjectRef {
50///     DataObjectRef::new(DataObject::new_text(
51///         conversions::to_text(interpreter, &text_object, CodePosition::EMPTY).trim(),
52///     ))
53/// }
54///
55/// let (metadata, function): (FunctionMetadata, Function) = lang_func!(
56///     trim_function,
57///     lang_func_metadata!(
58///         name="trim",
59///         return_type_constraint(
60///             allowed=["TEXT"],
61///         ),
62///         parameter(
63///             name="$text",
64///         ),
65///     ),
66/// );
67/// ```
68///
69/// `FunctionPointerObject::new` can be used to create a [FunctionPointerObject](crate::interpreter::data::function::FunctionPointerObject) with a single non-overloaded function:
70/// ```
71/// # use lang_interpreter::interpreter::data::{DataObject, DataObjectRef};
72/// # use lang_interpreter::interpreter::data::function::{Function, FunctionMetadata, Parameter, ParameterType};
73/// # use lang_interpreter::interpreter::{conversions, Interpreter};
74/// # use lang_interpreter::{lang_func, lang_func_metadata};
75/// # use lang_interpreter::lexer::CodePosition;
76/// #
77/// # fn trim_function(
78/// #     interpreter: &mut Interpreter,
79/// #     text_object: DataObjectRef,
80/// # ) -> DataObjectRef {
81/// #     DataObjectRef::new(DataObject::new_text(
82/// #         conversions::to_text(interpreter, &text_object, CodePosition::EMPTY).trim(),
83/// #     ))
84/// # }
85/// #
86/// # let (metadata, function): (FunctionMetadata, Function) = lang_func!(
87/// #     trim_function,
88/// #     lang_func_metadata!(
89/// #         name="trim",
90/// #         return_type_constraint(
91/// #             allowed=["TEXT"],
92/// #         ),
93/// #         parameter(
94/// #             name="$text",
95/// #         ),
96/// #     ),
97/// # );
98/// #
99/// use lang_interpreter::interpreter::data::function::FunctionPointerObject;
100///
101/// //`(metadata, function)` is used from the example above
102///
103/// let fp: FunctionPointerObject = FunctionPointerObject::new(&metadata, function);
104///
105/// assert_eq!(fp.function_name(), Some("trim"));
106/// assert_eq!(fp.function_info(), None);
107/// assert_eq!(fp.functions().len(), 1);
108/// ```
109///
110/// Overloaded functions can be created with `FunctionPointerObject::create_function_pointer_objects_from_native_functions`:
111/// ```
112/// # use lang_interpreter::interpreter::data::{DataObject, DataObjectRef};
113/// # use lang_interpreter::interpreter::data::function::{Function, FunctionMetadata, Parameter, ParameterType};
114/// # use lang_interpreter::interpreter::{conversions, Interpreter};
115/// # use lang_interpreter::{lang_func, lang_func_metadata};
116/// # use lang_interpreter::lexer::CodePosition;
117/// #
118/// # fn trim_function(
119/// #     interpreter: &mut Interpreter,
120/// #     text_object: DataObjectRef,
121/// # ) -> DataObjectRef {
122/// #     DataObjectRef::new(DataObject::new_text(
123/// #         conversions::to_text(interpreter, &text_object, CodePosition::EMPTY).trim(),
124/// #     ))
125/// # }
126/// #
127/// # let (metadata, function): (FunctionMetadata, Function) = lang_func!(
128/// #     trim_function,
129/// #     lang_func_metadata!(
130/// #         name="trim",
131/// #         return_type_constraint(
132/// #             allowed=["TEXT"],
133/// #         ),
134/// #         parameter(
135/// #             name="$text",
136/// #         ),
137/// #     ),
138/// # );
139/// #
140/// use std::collections::HashMap;
141/// use lang_interpreter::interpreter::data::function::FunctionPointerObject;
142///
143/// //`(metadata, function)` is used from the example above
144///
145/// let overloaded_functions: HashMap<Box<str>, FunctionPointerObject> = FunctionPointerObject::create_function_pointer_objects_from_native_functions(vec![
146///     (metadata, function),
147/// ]);
148///
149/// assert_eq!(overloaded_functions.len(), 1);
150///
151/// let fp = &overloaded_functions["trim"];
152///
153/// assert_eq!(fp.function_name(), Some("trim"));
154/// assert_eq!(fp.function_info(), None);
155/// assert_eq!(fp.functions().len(), 1);
156/// ```
157#[macro_export]
158macro_rules! lang_func {
159    ( $func:ident, $metadata:expr $(,)? ) => {{
160        let (metadata, func, id) = $crate::lang_func_adapter!($func, $metadata);
161
162        let native_function = $crate::interpreter::data::function::native::create_native_function(func, id, ::std::vec![]);
163        let function = $crate::interpreter::data::function::Function::new_native(native_function, &metadata);
164
165        (metadata, function)
166    }};
167
168    ( $func:ident, $value_dependencies:expr, $metadata:expr $(,)? ) => {{
169        let (metadata, func, id) = $crate::lang_func_adapter!($func, $metadata);
170
171        let native_function = $crate::interpreter::data::function::native::create_native_function(func, id, $value_dependencies);
172        let function = $crate::interpreter::data::function::Function::new_native(native_function, &metadata);
173
174        (metadata, function)
175    }};
176}