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}