ExpressionFunction.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.oorexx.org/license.html */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /******************************************************************************/
39 /* REXX Translator */
40 /* */
41 /* Primitive Function Invocation Class */
42 /* */
43 /******************************************************************************/
44 #include <stdlib.h>
45 #include "RexxCore.h"
46 #include "StringClass.hpp"
47 #include "QueueClass.hpp"
48 #include "DirectoryClass.hpp"
49 #include "RexxActivation.hpp"
50 #include "RexxInstruction.hpp"
51 #include "ExpressionFunction.hpp"
52 #include "Token.hpp"
53 #include "StackClass.hpp"
54 #include "RexxActivity.hpp"
55 #include "ProtectedObject.hpp"
56 
58  RexxString *function_name, /* name of the function */
59  size_t argCount, /* count of positional arguments */
60  RexxQueue *arglist, /* function positional arguments */
61  size_t namedArgCount, /* count of named arguments */
62  RexxQueue *namedArglist, /* function named arguments */
63  size_t builtinIndex, /* index of possible built-in func */
64  bool string ) /* string or symbol invocation */
65 /******************************************************************************/
66 /* Function: Create a function expression object */
67 /******************************************************************************/
68 {
69  /* NOTE: the name oref needs to */
70  /* be filled in prior to doing any */
71  /* thing that might cause a gc */
72  /* set the default target */
73  OrefSet(this, this->functionName, function_name);
74 
75  /* save the positional argument count */
76  this->argument_count = (uint8_t)argCount;
77  while (argCount > 0) /* now copy the argument pointers */
78  {
79  /* in reverse order */
80  OrefSet(this, this->arguments[--argCount], arglist->pop());
81  }
82 
83  // The named arguments are stored after the positional arguments
84  // Each named argument has 2 entries : name, expression
85  // named_argument_count = the number of named arguments
86  this->named_argument_count = (uint8_t)namedArgCount;
87  while (namedArgCount > 0) /* now copy the argument pointers */
88  {
89  /* in reverse order */
90  --namedArgCount;
91  OrefSet(this, this->arguments[this->argument_count + (2 * namedArgCount) + 1], namedArglist->pop()); // expression
92  OrefSet(this, this->arguments[this->argument_count + (2 * namedArgCount) + 0], namedArglist->pop()); // name
93  }
94 
95  /* set the builtin index for later */
96  /* resolution step */
97  this->builtin_index = (uint16_t)builtinIndex;
98 
99  if (string) /* have a string lookup? */
100  {
101  this->flags |= function_nointernal;/* do not check for internal routines*/
102  }
103 }
104 
106  RexxDirectory *labels) /* current table of labels */
107 /******************************************************************************/
108 /* Function: Resolve a function target location */
109 /******************************************************************************/
110 {
111  /* internal routines allowed? */
112  if (!(this->flags&function_nointernal))
113  {
114  if (labels != OREF_NULL) /* have a labels table? */
115  {
116  /* check the label table */
117  OrefSet(this, this->target, (RexxInstruction *)labels->at(this->functionName));
118  }
119  this->flags |= function_internal; /* this is an internal call */
120  }
121  if (this->target == OREF_NULL) /* not found yet? */
122  {
123  /* have a builtin function? */
124  if (this->builtin_index != NO_BUILTIN)
125  {
126  this->flags |= function_builtin; /* this is a builtin function */
127  }
128  else
129  {
130  this->flags |= function_external;/* have an external routine */
131  }
132  }
133 }
134 
135 void RexxExpressionFunction::live(size_t liveMark)
136 /******************************************************************************/
137 /* Function: Normal garbage collection live marking */
138 /******************************************************************************/
139 {
140  size_t i; /* loop counter */
141  size_t count; /* argument count */
142 
143  memory_mark(this->functionName);
144  memory_mark(this->target);
145  for (i = 0, count = this->argument_count + (2 * this->named_argument_count); i < count; i++)
146  {
147  memory_mark(this->arguments[i]);
148  }
149 }
150 
152 /******************************************************************************/
153 /* Function: Generalized object marking */
154 /******************************************************************************/
155 {
156  size_t i; /* loop counter */
157  size_t count; /* argument count */
158 
161  for (i = 0, count = this->argument_count + (2 * this->named_argument_count); i < count; i++)
162  {
163  memory_mark_general(this->arguments[i]);
164  }
165 }
166 
168 /******************************************************************************/
169 /* Function: Flatten an object */
170 /******************************************************************************/
171 {
172  size_t i; /* loop counter */
173  size_t count; /* argument count */
174 
176 
177  flatten_reference(newThis->functionName, envelope);
178  flatten_reference(newThis->target, envelope);
179  for (i = 0, count = this->argument_count + (2 * this->named_argument_count); i < count; i++)
180  {
181  flatten_reference(newThis->arguments[i], envelope);
182  }
183 
185 }
186 
188  RexxActivation *context, /* current activation context */
189  RexxExpressionStack *stack ) /* evaluation stack */
190 /******************************************************************************/
191 /* Function: Execute a REXX function */
192 /******************************************************************************/
193 {
194  ProtectedObject result; /* returned result */
195  size_t argcount; /* count of positional arguments */
196  size_t namedArgcount; /* count of named arguments */
197  size_t i; /* loop counter */
198  size_t stacktop; /* top location on the stack */
199 
200  ActivityManager::currentActivity->checkStackSpace(); /* have enough stack space? */
201 
202  stacktop = stack->location(); /* save the stack top */
203 
204  // Positional arguments
205  argcount = this->argument_count; /* get the argument count */
206  for (i = 0; i < argcount; i++) /* loop through the argument list */
207  {
208  /* real argument? */
209  if (this->arguments[i] != OREF_NULL)
210  {
211  /* evaluate the expression */
212  result = this->arguments[i]->evaluate(context, stack);
213  /* trace if necessary */
214  context->traceIntermediate(result, TRACE_PREFIX_ARGUMENT);
215  }
216  else
217  {
218  stack->push(OREF_NULL); /* push an non-existent argument */
219  /* trace if necessary */
220  context->traceIntermediate(OREF_NULLSTRING, TRACE_PREFIX_ARGUMENT);
221  }
222  }
223 
224  // Named arguments
225  namedArgcount = this->named_argument_count;
226  for (i = argcount; i < argcount + (2 * namedArgcount); i+=2)
227  {
228  // Argument name: string literal
229  RexxObject *name = this->arguments[i];
230  stack->push(name); // a string
232 
233  // Argument expression
234  RexxObject *argResult = this->arguments[i+1]->evaluate(context, stack);
235  context->traceIntermediate(argResult, TRACE_PREFIX_ARGUMENT);
236  }
237 
238  // More easy to work with an array of arguments (address of the first argument) than a stack of arguments (address of the last argument).
239  RexxObject **_arguments = stack->arguments(argcount + (2 * namedArgcount));
240 
241  /* process various call types */
242  switch (this->flags&function_type_mask)
243  {
244 
245  case function_internal: /* need to process internal routine */
246  /* go process the internal call */
247  context->internalCall(this->functionName, this->target, _arguments, argcount, namedArgcount, result);
248  break;
249 
250  case function_builtin: /* builtin function call */
251  {
252  // Check the global functions directory
253  // this is actually considered part of the built-in functions, but these are
254  // written in ooRexx. The names are also case sensitive
255  RoutineClass *routine = OREF_NULL;
256  // Ignore the overridings if the flag function_nointernal is set
257  // this->functionName should not be OREF_NULL, but just in case...
258  if (!(this->flags&function_nointernal) && this->functionName != OREF_NULL) routine = (RoutineClass *)TheFunctionsDirectory->get(this->functionName);
259  if (routine != OREF_NULL)
260  {
261  // call the user-defined routine
262  routine->call(ActivityManager::currentActivity, this->functionName, _arguments, argcount, namedArgcount, OREF_SUBROUTINE, OREF_NULL, EXTERNALCALL, result);
263  }
264  else
265  {
266  /* call the function */
267  result = (RexxObject *) (*(RexxSource::builtinTable[this->builtin_index]))(context, _arguments, argcount, namedArgcount, stack);
268  }
269  }
270  break;
271 
272  case function_external: /* need to call externally */
273  /* go process the internal call */
274  context->externalCall(this->functionName, _arguments, argcount, namedArgcount, OREF_FUNCTIONNAME, result);
275  break;
276  }
277  if ((RexxObject *)result == OREF_NULL) /* result returned? */
278  {
279  /* raise an error */
280  if (this->functionName)
281  {
283  }
284  else
285  {
286  reportException(Error_Function_no_data); // no name => don't try to print one out...!
287  }
288  }
289  stack->setTop(stacktop); /* remove arguments from the stack */
290  stack->push((RexxObject *)result); /* push onto the stack */
291  /* trace if necessary */
292  context->traceFunction(functionName, (RexxObject *)result);
293  return(RexxObject *)result; /* and return this to the caller */
294 }
295 
296 void *RexxExpressionFunction::operator new(size_t size,
297  size_t argCount) /* count of arguments */
298  // REMEMBER: argCount includes the count of named arguments, no need to pass a separated named_argCount
299 /******************************************************************************/
300 /* Function: Create a new translator object */
301 /******************************************************************************/
302 {
303  if (argCount == 0)
304  {
305  // allocate with singleton item chopped off
306  return new_object(size - sizeof(RexxObject *), T_FunctionCallTerm);
307  }
308  else
309  {
310  // argCount = positionalCount + (2 * namedCount)
311  // Ex: (p1, p2, p3, n1:v1, n2:v2, n3:v3)
312  // positionalCount = 3
313  // namedCount = 3
314  // argCount = 3 + 2*3 = 9
315  /* Get new object */
316  return new_object(size + (argCount - 1) * sizeof(RexxObject *), T_FunctionCallTerm);
317  }
318 }
void reportException(wholenumber_t error)
@ T_FunctionCallTerm
#define function_type_mask
#define function_nointernal
#define function_builtin
#define function_internal
#define function_external
#define EXTERNALCALL
@ TRACE_PREFIX_NAMED_ARGUMENT
@ TRACE_PREFIX_ARGUMENT
#define OREF_NULL
Definition: RexxCore.h:61
#define OrefSet(o, r, v)
Definition: RexxCore.h:101
#define TheFunctionsDirectory
Definition: RexxCore.h:185
#define Error_Function_no_data_function
#define Error_Function_no_data
#define memory_mark(oref)
Definition: RexxMemory.hpp:450
RexxObject * new_object(size_t s)
Definition: RexxMemory.hpp:436
#define flatten_reference(oref, envel)
Definition: RexxMemory.hpp:498
#define memory_mark_general(oref)
Definition: RexxMemory.hpp:451
#define cleanUpFlatten
Definition: RexxMemory.hpp:484
#define setUpFlatten(type)
Definition: RexxMemory.hpp:478
#define NO_BUILTIN
Definition: Token.hpp:319
static RexxActivity *volatile currentActivity
RexxObject * externalCall(RexxString *, RexxObject **, size_t, size_t, RexxString *, ProtectedObject &)
RexxObject * internalCall(RexxString *, RexxInstruction *, RexxObject **, size_t, size_t, ProtectedObject &)
void traceIntermediate(RexxObject *v, int p)
void traceFunction(RexxString *n, RexxObject *v)
void checkStackSpace()
RexxObject * at(RexxString *)
RexxObject * evaluate(RexxActivation *, RexxExpressionStack *)
void flatten(RexxEnvelope *)
RexxExpressionFunction(RexxString *, size_t, RexxQueue *, size_t, RexxQueue *, size_t, bool)
void resolve(RexxDirectory *)
void push(RexxObject *value)
void setTop(size_t v)
RexxObject ** arguments(size_t count)
virtual RexxObject * evaluate(RexxActivation *, RexxExpressionStack *)
RexxObject * pop()
Definition: QueueClass.hpp:80
static pbuiltin builtinTable[]
Definition: SourceFile.hpp:421
void call(RexxActivity *, RexxString *, RexxObject **, size_t, size_t, RexxString *, RexxString *, int, ProtectedObject &)
unsigned short uint16_t
unsigned char uint8_t