1 /****************************************************************************
2  * Copyright (C) 2012 by Matteo Franchin                                    *
3  *                                                                          *
4  * This file is part of Box.                                                *
5  *                                                                          *
6  *   Box is free software: you can redistribute it and/or modify it         *
7  *   under the terms of the GNU Lesser General Public License as published  *
8  *   by the Free Software Foundation, either version 3 of the License, or   *
9  *   (at your option) any later version.                                    *
10  *                                                                          *
11  *   Box is distributed in the hope that it will be useful,                 *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
14  *   GNU Lesser General Public License for more details.                    *
15  *                                                                          *
16  *   You should have received a copy of the GNU Lesser General Public       *
17  *   License along with Box.  If not, see <http://www.gnu.org/licenses/>.   *
18  ****************************************************************************/
19 
20 /**
21  * @file callable.h
22  * @brief Declaration of BoxCallable and related functionality.
23  *
24  * This header defines the BoxCallable object, an abstraction for a callable
25  * entity in Box which may be implemented in either C or Box VM code and may
26  * have links to associated data (what - in other languages - is referred to
27  * as a closure). The callable object also contains details which allow
28  * generating Box VM code which calls the object.
29  */
30 
31 #ifndef _BOX_CALLABLE_H
32 #  define _BOX_CALLABLE_H
33 
34 #  include <box/exception.h>
35 #  include <box/types.h>
36 #  include <box/obj.h>
37 #  include <box/vm.h>
38 
39 /**
40  * @brief Unique identifier.
41  *
42  * This is typically a string used to identify procedures.
43  */
44 typedef char BoxUid;
45 
46 /**
47  * First (and simplest) C implementation of a BoxCallable object: takes just a
48  * pointer to the parent.
49  * @param parent The pointer to the parent (object over which the callable
50  *   operates).
51  * @return A BoxException object in case of errors, NULL otherwise.
52  */
53 typedef BoxException *(*BoxCCall1)(BoxPtr *parent);
54 
55 /**
56  * Second C implementation of a BoxCallable object: takes a pointer to the
57  * parent and a pointer to the child.
58  * @param parent The pointer to the parent.
59  * @param child The pointer to the child.
60  * @return A BoxException object in case of errors, NULL otherwise.
61  */
62 typedef BoxException *(*BoxCCall2)(BoxPtr *parent, BoxPtr *child);
63 
64 /**
65  * Third (and most complete) C implementation of a BoxCallable object: takes a
66  * pointer to the corresponding BoxCallable object (from which the callable
67  * context can be retrieved, thus implementing a closure), a pointer to the
68  * parent and a pointer to the child.
69  * @param callable The BoxCallable object corresponding to this function. This
70  *   is typically what is returned by BoxCallable_Create_From_CCall3.
71  * @param parent The pointer to the parent.
72  * @param child The pointer to the child.
73  * @return A BoxException object in case of errors, NULL otherwise.
74  */
75 typedef BoxException *(*BoxCCall3)(BoxPtr *callable, BoxPtr *parent,
76                                    BoxPtr *child);
77 
78 /**
79  * Fourth C implementation of a BoxCallable object. This type is provided for
80  * compatibility with old code, where the C implementation is a function which
81  * takes just a pointer to the VM object.
82  * @param vm The calling VM.
83  * @return A BoxException object in case of errors, NULL otherwise.
84  */
85 typedef BoxTask (*BoxCCallOld)(BoxVMX *vm);
86 
87 /**
88  * @brief Abstraction of function in the Box language implementation.
89  *
90  * A @c BoxCallable object is an object which can be called by passing one
91  * parent and one child objects. The parent object is often the result of
92  * the call, while the child is typically the input argument.
93  * A @a BoxCallable object can be implemented as a C function or as a
94  * @c BoxVM procedure.
95  *
96  * @see BoxVM
97  */
98 typedef struct BoxCallable_struct BoxCallable;
99 
100 /**
101  * @brief Enumeration of the possible implementation for a @c BoxCallable
102  * object.
103  *
104  * @see BoxCallable
105  */
106 typedef enum {
107   BOXCALLABLEKIND_UNDEFINED, /**< Undefined callable. */
108   BOXCALLABLEKIND_C_1,       /**< BoxCCall1. */
109   BOXCALLABLEKIND_C_2,       /**< BoxCCall2. */
110   BOXCALLABLEKIND_C_3,       /**< BoxCCall3. */
111   BOXCALLABLEKIND_C_OLD,     /**< BoxCCallOld. */
112   BOXCALLABLEKIND_VM         /**< VM call. */
113 } BoxCallableKind;
114 
115 /**
116  * Equivalent to #BoxSPtr_Link, but does type casting for #BoxCallable.
117  * @see BoxSPtr_Link
118  */
119 #define BoxCallable_Link(t) ((BoxCallable *) BoxSPtr_Link(t))
120 
121 /**
122  * Equivalent to #BoxSPtr_Unlink, but does type casting for #BoxCallable.
123  * @see BoxSPtr_Unlink
124  */
125 #define BoxCallable_Unlink(t) ((BoxCallable *) BoxSPtr_Unlink(t))
126 
127 /**
128  * @brief Create an undefined callable.
129  *
130  * The callable maps an object of type @p t_in to an object of type @p t_out.
131  * The object can be later defined using BoxCallable_Define_From_CCall1() and
132  * friends.
133  * @param t_out Type of the output object.
134  * @param t_in Type of the input object.
135  * @return A new #BoxCallable object.
136  */
137 BOXEXPORT BOXOUT BoxCallable *
138 BoxCallable_Create_Undefined(BoxType *t_out, BoxType *t_in);
139 
140 /**
141  * @brief Set the unique identifier for the callable.
142  *
143  * @param cb The callable.
144  * @brief uid A unique identifier for @p cb.
145  * @return Whether the operation succeeded. @c BOXBOOL_FALSE is returned if
146  *   the uid has been already set.
147  */
148 BOXEXPORT BoxBool
149 BoxCallable_Set_Uid(BoxCallable *cb, BoxUid *uid);
150 
151 /**
152  * @brief Return the unique identifier associated to the given callable.
153  *
154  * @param cb The callable.
155  * @return Return the unique identifier (a #BoxUid object) for @p cb or @c NULL
156  *   if @c cb does not have a unique identifier.
157  */
158 BOXEXPORT BoxUid *
159 BoxCallable_Get_Uid(BoxCallable *cb);
160 
161 /**
162  * Define a callable object from a BoxCCall1 C function.
163  * @param call The C function.
164  * @return BOXBOOL_TRUE on success, BOXBOOL_FALSE on failure.
165  */
166 BOXEXPORT BOXOUT BoxCallable *
167 BoxCallable_Define_From_CCall1(BOXIN BoxCallable *cb, BoxCCall1 call);
168 
169 /**
170  * Define a callable object from a BoxCCall2 C function.
171  * @param call The C function.
172  */
173 BOXEXPORT BOXOUT BoxCallable *
174 BoxCallable_Define_From_CCall2(BOXIN BoxCallable *cb, BoxCCall2 call);
175 
176 /**
177  * Define a callable object from old-style C function (BoxCCallOld).
178  */
179 BOXEXPORT BOXOUT BoxCallable *
180 BoxCallable_Define_From_CCallOld(BOXIN BoxCallable *cb, BoxCCallOld call);
181 
182 /**
183  * Create a callable object from a BoxVM procedure.
184  * @param t_out Output type for the callable.
185  * @param t_in Input type for the callable.
186  * @param context Pointer to additional data required by the callable.
187  * @param vm The VM which contains the callable implementation.
188  * @param num The call number for the callable implementation.
189  * @return A new callable which wraps the procedure `num' of the virtual
190  *   machine `vm'.
191  */
192 BOXEXPORT BOXOUT BoxCallable *
193 BoxCallable_Define_From_VM(BOXIN BoxCallable *cb, BoxVM *vm, BoxVMCallNum num);
194 
195 /**
196  * @brief Return whether the callable is implemented.
197  *
198  * @param cb The callable.
199  * @return Whether the callable is implemented.
200  * @note A callable is implemented when it is
201  */
202 BOXEXPORT BoxBool
203 BoxCallable_Is_Implemented(BoxCallable *cb);
204 
205 /**
206  * @brief Return the call number for a VM callable.
207  *
208  * @param cb The input callable.
209  * @param vm The VM to which the call number refers to.
210  * @param cn Where to store the call number.
211  * @return If @p cb is a callable for a procedure defined in @p vm, then its
212  * call number is returned in <tt>*cn</tt> and @c BOXBOOL_TRUE is returned.
213  * In all the other cases, @c BOXBOOL_FALSE is returned.
214  */
215 BOXEXPORT BoxBool
216 BoxCallable_Get_VM_Call_Num(BoxCallable *cb, BoxVM *vm, BoxVMCallNum *cn);
217 
218 /**
219  * @brief Request a call number for a given callable.
220  *
221  * Request a call number (relative to the given virtual machine @p vm) for
222  * the given callable @p cb. A new callable is returned in <tt>*cb_out</tt>
223  * which references the new call number. Note that the call number is not
224  * allocated, if a valid call number is found in @p cb. For this reason,
225  * it is important to use the value returned in @p cb_out for subsequent calls
226  * to the function (as doing so will not generate new spurious call numbers).
227  * @param cb The callable for which a call number is requested.
228  * @param vm The virtual machine the call number should refer to.
229  * @param num Pointer to the location where the call number must be returned.
230  * @param cb_out Pointer to the location where a callable referencing the
231  *   new call number should be stored.
232  * @return @c BOXBOOL_TRUE, if the function succeeded and @p num and @p cb_out
233  *   were written with values, else @c BOXBOOL_FALSE.
234  */
235 BOXEXPORT BoxBool
236 BoxCallable_Request_VM_Call_Num(BoxCallable *cb, BoxVM *vm, BoxVMCallNum *num,
237                                 BOXOUT BoxCallable **cb_out);
238 
239 /**
240  *
241  */
242 BOXEXPORT BoxException *
243 BoxCallable_Call1(BoxCallable *cb, BoxPtr *parent);
244 
245 /**
246  *
247  */
248 BOXEXPORT BoxException *
249 BoxCallable_Call2(BoxCallable *cb, BoxPtr *parent, BoxPtr *child);
250 
251 BOXEXPORT BoxTask
252 BoxCallable_CallOld(BoxCallable *cb, BoxVMX *vmx);
253 
254 #endif /* _BOX_CALLABLE_H */
255