Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_value_call.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Interface afw_value Implementation for call
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
9 
15 #include "afw_internal.h"
16 
17 
18 #define impl_afw_value_optional_release NULL
19 #define impl_afw_value_get_reference NULL
20 
21 
22 
23 #define impl_afw_value_get_evaluated_meta \
24  afw_value_internal_get_evaluated_meta_default
25 
26 #define impl_afw_value_get_evaluated_metas \
27  afw_value_internal_get_evaluated_metas_default
28 
29 /* Declares and rti/inf defines for interface afw_value */
30 #define AFW_IMPLEMENTATION_ID "call"
31 #define AFW_IMPLEMENTATION_INF_SPECIFIER AFW_DEFINE_CONST_DATA
32 #define AFW_IMPLEMENTATION_INF_LABEL afw_value_call_inf
34 
35 
36 
37 static const afw_value_t *
38 impl_call_script_function(
39  const afw_value_t *lambda,
40  afw_size_t argc,
41  const afw_value_t * const * argv,
42  const afw_pool_t *p,
43  afw_xctx_t *xctx)
44 {
46  const afw_value_t *result;
47  const afw_value_t *value;
48  afw_size_t parameter_number;
49  const afw_value_script_function_parameter_t *const *params;
50  const afw_value_t *const *arg;
51  afw_name_value_t *cur;
52  const afw_value_t *const *rest_argv;
53  afw_size_t rest_argc;
54  const afw_list_t *rest_list;
55  int local_top;
56 
57  result = NULL;
58  if (!afw_value_is_script_function(lambda)) {
59  AFW_THROW_ERROR_Z(general,
60  "impl_call_script_function() must be called with script function",
61  xctx);
62  }
63  l = (const afw_value_script_function_definition_t *)lambda;
64  if (!afw_value_is_script_function(lambda)) {
65  lambda = afw_value_evaluate(lambda, p, xctx);
66  if (!afw_value_is_script_function(lambda)) {
67  AFW_THROW_ERROR_Z(general,
68  "impl_call_script_function() expects lambda value",
69  xctx);
70  }
71  l = (const afw_value_script_function_definition_t *)lambda;
72  }
73 
74  /* Save stack top which will be restored on return. */
75  local_top = afw_xctx_begin_stack_frame(xctx);
76  AFW_TRY {
77 
78  /*
79  * Push parameters without names onto stack. This is so
80  * afw_function_evaluate_parameter_with_type() will not
81  * see these parameters yet.
82  *
83  * First argument starts at argv[1] so index in argv is the parameter
84  * number.
85  */
86  for (parameter_number = 1, params = l->parameters, arg = argv + 1;
87  parameter_number <= l->count;
88  parameter_number++, params++, arg++)
89  {
90  /* If this is rest parameter ... */
91  if ((*params)->is_rest) {
92 
93  /* If extra unused parameters, pass them in rest object. */
94  if (argc >= l->count) {
95  rest_argc = argc - l->count + 1;
96  rest_argv = arg;
97  }
98 
99  /* If no extra unused parameters, rest object is empty. */
100  else {
101  rest_argc = 0;
102  rest_argv = NULL;
103  }
104 
105  /* Create rest list. */
107  rest_argv, rest_argc, p, xctx);
108  value = afw_value_create_list(rest_list, p, xctx);
109  }
110 
111  /* If not rest parameter */
112  else {
113  value = NULL;
114  if (parameter_number <= argc) {
116  *arg, parameter_number,
117  (*params)->type,
118  p, xctx);
119  }
120 
121  if (!value) {
122  if ((*params)->default_value) {
123  value = (*params)->default_value;
124  }
125  else if (!(*params)->is_optional) {
126  AFW_THROW_ERROR_FZ(general, xctx,
127  "Parameter %" AFW_SIZE_T_FMT " is required",
128  parameter_number);
129  }
130  }
131  }
132 
133  cur = (afw_name_value_t *)apr_array_push(xctx->stack);
134  cur->name = &afw_s_a_empty_string;
135  cur->value = value;
136  }
137 
138  /* Set parameter names so they will be seen as local variables. */
139  for (
140  cur = ((afw_name_value_t *)xctx->stack->elts) + local_top,
141  parameter_number = 1,
142  params = l->parameters;
143  parameter_number <= l->count;
144  cur++,
145  parameter_number++,
146  params++)
147  {
148  cur->name = (*params)->name;
149  }
150 
151  /* Evaluate body. */
152  result = afw_value_evaluate(l->body, p, xctx);
153  }
154 
155  AFW_FINALLY{
156 
157  /* Restore xctx stack top to what it was on entry. */
158  afw_xctx_end_stack_frame(local_top, xctx);
159 
160  }
161 
162  AFW_ENDTRY;
163 
164  /* Return result. */
165  return result;
166 }
167 
168 
169 
170 /* Create function for call value. */
171 AFW_DEFINE(const afw_value_t *)
173  const afw_compile_value_contextual_t *contextual,
174  afw_size_t argc,
175  const afw_value_t * const *argv,
176  const afw_pool_t *p,
177  afw_xctx_t *xctx)
178 {
179  afw_value_call_t *result;
180 
181  if (!argv[0]) {
182  AFW_THROW_ERROR_Z(general,
183  "afw_value_call_create() argv[0] must be specified",
184  xctx);
185  }
186 
187  /*
188  * If this is a function definition, return the result of the more specific
189  * afw_value_call_built_in_function_create() to reduce the execution time
190  * code path.
191  */
192  if (afw_value_is_function_definition(argv[0])) {
194  contextual, argc, argv, p, xctx);
195  }
196 
197  result = afw_pool_calloc_type(p, afw_value_call_t, xctx);
198  result->inf = &afw_value_call_inf;
199  result->function_value = argv[0];
200  result->args.contextual = contextual;
201  result->args.argc = argc;
202  result->args.argv = argv;
203 
204  return (const afw_value_t *)result;
205 }
206 
207 
208 
209 /*
210  * Implementation of method optional_evaluate for interface afw_value.
211  */
212 const afw_value_t *
214  const afw_value_t * instance,
215  const afw_pool_t * p,
216  afw_xctx_t *xctx)
217 {
218  const afw_value_call_t *self =
219  (const afw_value_call_t *)instance;
220  const afw_compile_value_contextual_t *saved_contextual;
221  const afw_value_t *function_value;
222  const afw_value_t *result;
223 
224  /* Push value on evaluation stack. */
225  afw_xctx_evaluation_stack_push_value(instance, xctx);
226  saved_contextual = xctx->error->contextual;
227  xctx->error->contextual = self->args.contextual;
228 
229  /*
230  * The function value may need to be evaluated since it's likely to be
231  * a variable reference or something else that needs to be evaluated
232  * first.
233  */
234  function_value = afw_value_evaluate(self->function_value, p, xctx);
235 
236  /*
237  * @fixme
238  *
239  * This extra evaluate was put in for some reason but I'm not sure it's
240  * needed anymore. I've left it here commented out in case that need is
241  * discovered.
242  *
243  * The original fixme comment was:
244  * this should be done at the time variable is defined???
245  */
246  //if (afw_value_is_compiled_value(function_value)) {
247  //function_value = afw_value_evaluate(function_value, p, xctx);
248  //}
249 
250  /*
251  * This is most likely a script function call since built-ins are usually
252  * handled by afw_value_built_in_function. Check and handle for script
253  * functions first.
254  */
255  if (afw_value_is_script_function(function_value)) {
256  result = impl_call_script_function(function_value,
257  self->args.argc, self->args.argv, p, xctx);
258  }
259 
260  /*
261  * This may still be a call to a built in function if a variable is assigned
262  * a built-in function definition.
263  */
264  else if (afw_value_is_function_definition(function_value)) {
265  result = afw_value_call_built_in_function(
266  self->args.contextual,
267  (const afw_value_function_definition_t *)function_value,
268  self->args.argc, self->args.argv, p, xctx);
269  }
270 
271  /* Otherwise, this must be a thunk call. */
272  else if (afw_value_is_function_thunk(function_value)) {
273  result = ((const afw_value_function_thunk_t *)function_value)->
274  execute(
275  (const afw_value_function_thunk_t *)function_value,
276  self->args.argc, self->args.argv, p, xctx);
277  }
278  else {
279  AFW_THROW_ERROR_Z(general, "Invalid function_value", xctx);
280  }
281 
282  /* Pop value from evaluation stack and return result. */
284  xctx->error->contextual = saved_contextual;
285  return result;
286 }
287 
288 
289 /*
290  * Implementation of method get_data_type for interface afw_value.
291  */
292 const afw_data_type_t *
293 impl_afw_value_get_data_type(
294  const afw_value_t * instance,
295  afw_xctx_t *xctx)
296 {
297  return NULL;
298 }
299 
300 /*
301  * Implementation of method get_evaluated_data_type for interface afw_value.
302  */
303 const afw_data_type_t *
304 impl_afw_value_get_evaluated_data_type(
305  const afw_value_t * instance,
306  afw_xctx_t *xctx)
307 {
308  return NULL;
309 }
310 
311 /*
312  * Implementation of method get_evaluated_data_type_parameter for interface
313  * afw_value.
314  */
315 const afw_utf8_t *
316 impl_afw_value_get_evaluated_data_type_parameter(
317  const afw_value_t * instance,
318  afw_xctx_t *xctx)
319 {
320  return NULL;
321 }
322 
323 
324 
325 /*
326  * Implementation of method decompile for interface afw_value.
327  */
328 void
329 impl_afw_value_produce_compiler_listing(
330  const afw_value_t *instance,
331  const afw_writer_t *writer,
332  afw_xctx_t *xctx)
333 {
334  const afw_value_call_t *self =
335  (const afw_value_call_t *)instance;
336 
337  afw_value_compiler_listing_begin_value(writer, instance,
338  self->args.contextual, xctx);
339  afw_writer_write_z(writer, ": [", xctx);
340  afw_writer_write_eol(writer, xctx);
341  afw_writer_increment_indent(writer, xctx);
342 
343  afw_value_compiler_listing_call_args(writer, &self->args, xctx);
344 
345  afw_writer_decrement_indent(writer, xctx);
346  afw_writer_write_z(writer, "]", xctx);
347  afw_writer_write_eol(writer, xctx);
348 }
349 
350 
351 
352 /*
353  * Implementation of method decompile for interface afw_value.
354  */
355 void
356 impl_afw_value_decompile(
357  const afw_value_t * instance,
358  const afw_writer_t * writer,
359  afw_xctx_t *xctx)
360 {
361  /*FIXME
362 
363  const afw_value_call_t *self =
364  (const afw_value_call_t *)instance;
365 
366  if (self->qualifier.len > 0) {
367  afw_writer_write_utf8(writer, &self->qualifier, xctx);
368  afw_writer_write_z(writer, "::", xctx);
369  }
370  afw_writer_write_utf8(writer, &self->name, xctx);
371  afw_value_decompile_call_args(writer, 0, &self->args, xctx);
372  */
373 }
374 
375 
376 /*
377  * Implementation of method get_info for interface afw_value.
378  */
379 void
380 impl_afw_value_get_info(
381  const afw_value_t *instance,
382  afw_value_info_t *info,
383  const afw_pool_t *p,
384  afw_xctx_t *xctx)
385 {
386  const afw_value_call_t *self =
387  (const afw_value_call_t *)instance;
388 
389  afw_memory_clear(info);
390  info->value_inf_id = &instance->inf->rti.implementation_id;
391  info->contextual = self->args.contextual;
392 }
AFW_DEFINE(const afw_object_t *)
Adaptive Framework Core Internal.
Interface afw_interface implementation declares.
afw_value_create_list(const afw_list_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type list value.
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
#define AFW_SIZE_T_FMT
Format string specifier used for afw_size_t.
Definition: afw_common.h:341
#define AFW_FINALLY
Always executed regardless of error.
Definition: afw_error.h:702
#define AFW_ENDTRY
Ends an AFW try block.
Definition: afw_error.h:727
#define AFW_TRY
Begin an AFW TRY block.
Definition: afw_error.h:634
#define AFW_THROW_ERROR_FZ(code, xctx, format_z,...)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:319
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:283
afw_function_evaluate_parameter_with_type(const afw_value_t *value, afw_size_t parameter_number, const afw_value_type_t *type, const afw_pool_t *p, afw_xctx_t *xctx)
Evaluate a parameter with dataTypeParameter.
Definition: afw_function.c:243
const afw_list_t * afw_list_const_create_array_of_values(const afw_value_t *const *values, afw_size_t count, const afw_pool_t *p, afw_xctx_t *xctx)
Create an immutable list from an array of values.
#define afw_memory_clear(to)
Clear preallocated memory for sizeof(*(to)).
Definition: afw_memory.h:47
#define afw_pool_calloc_type(instance, type, xctx)
Macro to allocate cleared memory to hold type in pool.
Definition: afw_pool.h:167
const afw_value_t * impl_afw_value_optional_evaluate(const afw_value_t *instance, const afw_pool_t *p, afw_xctx_t *xctx)
#define afw_value_is_function_thunk(A_VALUE)
Macro to determine if value is a function thunk.
Definition: afw_value.h:627
#define afw_value_evaluate(value, p, xctx)
Evaluate value if needed using specific pool.
Definition: afw_value.h:841
afw_value_call_inf
Value call inf.
Definition: afw_value.h:237
#define afw_value_is_function_definition(A_VALUE)
Macro to determine if value is a function definition.
Definition: afw_value.h:614
afw_value_call_create(const afw_compile_value_contextual_t *contextual, afw_size_t argc, const afw_value_t *const *argv, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for call value.
const afw_value_t * afw_value_call_built_in_function_create(const afw_compile_value_contextual_t *contextual, afw_size_t argc, const afw_value_t *const *argv, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for call_built_in_function value.
#define afw_value_is_script_function(A_VALUE)
Macro to determine if value is lambda definition.
Definition: afw_value.h:666
#define afw_writer_increment_indent(instance, xctx)
Call method increment_indent of interface afw_writer.
#define afw_writer_write_eol(instance, xctx)
Call method write_eol of interface afw_writer.
#define afw_writer_decrement_indent(instance, xctx)
Call method decrement_indent of interface afw_writer.
#define afw_writer_write_z(writer, s_z, xctx)
Call afw_writer_write() with zero terminated string.
Definition: afw_writer.h:35
int afw_xctx_begin_stack_frame(afw_xctx_t *xctx)
Begin stack frame.
Definition: afw_xctx.h:329
#define afw_xctx_evaluation_stack_push_value(VALUE, xctx)
Push VALUE onto execution stack.
Definition: afw_xctx.h:78
#define afw_xctx_evaluation_stack_pop_value(xctx)
Pop top VALUE off execution stack.
Definition: afw_xctx.h:113
void afw_xctx_end_stack_frame(int top, afw_xctx_t *xctx)
Set stack top.
Definition: afw_xctx.h:343
Contextual information provided in some values.
Interface afw_data_type public struct.
const afw_compile_value_contextual_t * contextual
Contextual information or NULL.
Definition: afw_error.h:83
Interface afw_list public struct.
Typedef for name/value pair.
Definition: afw_common.h:680
Interface afw_pool public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
const afw_value_t *const * argv
const afw_compile_value_contextual_t * contextual
Struct for call value.
Struct for function value.
Definition: afw_value.h:102
Struct for function thunk value.
Filled in by afw_value get_info method.
Definition: afw_value.h:49
Interface afw_value public struct.
Struct for script function parameter.
Interface afw_writer public struct.
Interface afw_xctx public struct.