ForwardInstruction.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 Forward Translator Class */
42 /* */
43 /******************************************************************************/
44 #include <stdlib.h>
45 #include "RexxCore.h"
46 #include "StringClass.hpp"
47 #include "ArrayClass.hpp"
49 #include "RexxActivation.hpp"
50 #include "ForwardInstruction.hpp"
51 #include "DirectoryClass.hpp"
52 
53 void RexxInstructionForward::live(size_t liveMark)
54 /******************************************************************************/
55 /* Function: Process live calls */
56 /******************************************************************************/
57 {
58  memory_mark(this->nextInstruction); /* must be first one marked */
59  memory_mark(this->target);
60  memory_mark(this->message);
61  memory_mark(this->superClass);
62  memory_mark(this->arguments);
63  memory_mark(this->array);
66 }
67 
69 /******************************************************************************/
70 /* Function: Process general live calls */
71 /******************************************************************************/
72 {
73  /* must be first one marked */
82 }
83 
85 /******************************************************************************/
86 /* Function: Flatten an instruction object */
87 /******************************************************************************/
88 {
90 
91  flatten_reference(newThis->nextInstruction, envelope);
92  flatten_reference(newThis->target, envelope);
93  flatten_reference(newThis->message, envelope);
94  flatten_reference(newThis->superClass, envelope);
95  flatten_reference(newThis->arguments, envelope);
96  flatten_reference(newThis->array, envelope);
97  flatten_reference(newThis->namedArgumentsExpression, envelope);
98  flatten_reference(newThis->namedArgumentsArray, envelope);
99 
101 }
102 
104  RexxActivation *context, /* current activation context */
105  RexxExpressionStack *stack) /* evaluation stack */
106 /******************************************************************************/
107 /* Function: Execute a forward instruction */
108 /******************************************************************************/
109 {
110  RexxObject *_target; /* evaluated target */
111  RexxString *_message; /* evaluated message */
112  RexxObject *_superClass; /* evaluated super class */
113  RexxObject *result; /* message result */
114  RexxObject *temp; /* temporary object */
115  size_t count = 0; /* count of array expressions */
116  size_t namedCount = 0; /* count of named arguments */
117  size_t i; /* loop counter */
118  RexxObject **_arguments;
119  RexxArray *newArguments;
120 
121  ProtectedObject p_newArguments;
122  ProtectedObject p_argArray;
123  ProtectedObject p_argDirectory;
124 
125  context->traceInstruction(this); /* trace if necessary */
126  if (!context->inMethod()) /* is this a method clause? */
127  {
128  /* raise an error */
130  }
131  _target = OREF_NULL; /* no object yet */
132  _message = OREF_NULL; /* no message over ride */
133  _superClass = OREF_NULL; /* no super class over ride */
134  _arguments = OREF_NULL; /* no argument over ride */
135 
136  if (this->target != OREF_NULL) /* sent to a different object? */
137  {
138  /* get the expression value */
139  _target = this->target->evaluate(context, stack);
140  }
141 
142  if (this->message != OREF_NULL) /* sending a different message? */
143  {
144  /* get the expression value */
145  temp = this->message->evaluate(context, stack);
146  _message = REQUEST_STRING(temp); /* get the string version */
147  stack->replace(0, _message);
148  _message = _message->upper(); /* and force to uppercase */
149  stack->replace(0, _message);
150  }
151 
152  if (this->superClass != OREF_NULL) /* overriding the super class? */
153  {
154  /* get the expression value */
155  _superClass = this->superClass->evaluate(context, stack);
156  }
157 
158  // Overriding the positional or named arguments ?
159  if (this->arguments != OREF_NULL ||
160  this->array != OREF_NULL ||
163  {
164 
165  // From here, I build an array of positional and named arguments.
166  // Initially, I pushed the arguments onto the stack.
167  // But I realized that I can't use the stack to store the items because the stack has a limited size, calculated at parse time.
168  // When the items are calculated by an expression, there is no way to guess the right size at parse time.
169  // TODO:
170  // Optimize by calculating the size of the array before creating it.
171 
172  newArguments = new_array(); // Careful if you want to preallocate ! Don't pass an arbitray size.
173  p_newArguments = newArguments; // GC protect
174 
175  // *************************
176  // * Positional Parameters *
177  // *************************
178 
179  // Remember :
180  // - this->arguments: an expression returning an array
181  // - this->array: a literal array
182  // They are exclusive (enforced by the parser).
183 
184  if (this->arguments != OREF_NULL) /* overriding the arguments? */
185  {
186  /* get the expression value */
187  temp = this->arguments->evaluate(context, stack);
188  /* get an array version */
189  RexxArray *argArray = REQUEST_ARRAY(temp);
190  p_argArray = argArray; // GC protect without using the stack
191  stack->toss();
192 
193  /* not an array item or a multiple */
194  /* dimension one? */
195  if (argArray == TheNilObject || argArray->getDimension() != 1)
196  {
197  /* this is an error */
199  }
200  count = argArray->size(); /* get the size */
201 #if 0 // jlf: keep omitted trailing arguments
202  /* omitted trailing arguments? */
203  if (count != 0 && argArray->get(count) == OREF_NULL)
204  {
205  count--; /* decrement the count */
206  while (count > 0) /* loop down to first full one */
207  {
208  /* find a real argument */
209  if (argArray->get(count) != OREF_NULL)
210  {
211  break; /* break out of here */
212  }
213  count--; /* step back the count */
214  }
215  }
216 #endif
217  // _arguments = argArray->data(); /* point directly to the argument data */
218 
219  for (i = 1; i <= count; i++)
220  {
221  RexxObject *item = argArray->get(i);
222  newArguments->append(item);
223  }
224  }
225 
226  else if (this->array != OREF_NULL) /* have an array of extra info? */
227  {
228  count = this->array->size(); /* get the expression count */
229  for (i = 1; i <= count; i++) /* loop through the expression list */
230  {
231  RexxObject *argElement = this->array->get(i);
232  /* real argument? */
233  if (argElement != OREF_NULL)
234  {
235  /* evaluate the expression */
236  RexxObject * value = argElement->evaluate(context, stack);
237  newArguments->append(value);
238  stack->toss();
239  }
240  else
241  {
242  /* just push a null reference for the missing ones */
243  newArguments->append(OREF_NULL);
244  }
245  }
246  }
247 
248  else // not overriding the positional arguments, get them from the context
249  {
250  RexxObject **arglist = context->getMethodArgumentList();
251  count = context->getMethodArgumentCount();
252  for (i = 0; i < count; i++)
253  {
254  RexxObject *arg = arglist[i];
255  newArguments->append(arg);
256  }
257  }
258 
259  // ********************
260  // * Named Parameters *
261  // ********************
262 
263  // Remember:
264  // - this->namedArgumentsExpression: an expression returning a directory
265  // - this->namedArgumentsArray: an array of name, value, name, value, etc...
266  // Both are exclusive (enforced by the parser)
267 
268  if (this->namedArgumentsExpression != OREF_NULL) /* overriding the named arguments? */
269  {
270  /* get the expression value */
271  temp = this->namedArgumentsExpression->evaluate(context, stack);
272 
273  // Due to the optimization in processUnknown (returning .nil instead of a directory when 0 named arguments), accept .nil
274  if (temp == TheNilObject) namedCount = 0;
275  else
276  {
277  /* get a directory version */
278  RexxDirectory *argDirectory = temp->requestDirectory();
279  p_argDirectory = argDirectory; // GC protect without using the stack
280  stack->toss(); // pop the temp directory, the indexes-items of argDirectory will be pushed.
281 
282  /* not a directory item ? */
283  if (argDirectory == TheNilObject)
284  {
285  // Similar to Error_Execution_forward_arguments 98.946 "FORWARD arguments must be a single-dimensional array of values"
286  // todo: Should create the error Error_Execution_forward_namedarguments
287  reportException(Error_Execution_user_defined , "FORWARD namedArguments must be a directory or NIL");
288  }
289  namedCount = argDirectory->appendAllIndexesItemsTo(newArguments, /*from*/ count+1); // from is 1-based index
290  }
291  }
292 
293  else if (this->namedArgumentsArray != OREF_NULL) /* have an array of named arguments? */
294  {
295  namedCount = this->namedArgumentsArray->size() / 2; /* get the count of pairs(name,expression) */
296  for (i = 1; i <= (2 * namedCount); i+=2) /* loop through the name,expression list */
297  {
298  RexxString *argName = (RexxString *)this->namedArgumentsArray->get(i);
299  newArguments->append(argName);
300 
301  RexxObject *argExpression = this->namedArgumentsArray->get(i+1); // can't be OREF_NULL
302  RexxObject *argValue = argExpression->evaluate(context, stack);
303  newArguments->append(argValue);
304  stack->toss();
305  }
306  }
307  else // not overriding the named arguments, get them from the context
308  {
309  RexxObject **arglist = context->getMethodArgumentList();
310  size_t argcount = context->getMethodArgumentCount();
311  namedCount = context->getMethodNamedArgumentCount();
312  for (i = argcount; i < argcount + (2 * namedCount); i += 2)
313  {
314  RexxString *argName = (RexxString *)arglist[i];
315  newArguments->append(argName);
316 
317  RexxObject *argValue = arglist[i+1];
318  newArguments->append(argValue);
319  }
320  }
321 
322  _arguments = newArguments->data();
323  }
324 
325  /* go forward this */
326  result = context->forward(_target, _message, _superClass, _arguments, count, namedCount, instructionFlags&forward_continue);
327  if (instructionFlags&forward_continue) /* not exiting? */
328  {
329  if (result != OREF_NULL) /* result returned? */
330  {
331  context->traceResult(result); /* trace if necessary */
332  /* set the RESULT variable to the */
333  /* message return value */
334  context->setLocalVariable(OREF_RESULT, VARIABLE_RESULT, result);
335  }
336  else /* drop the variable RESULT */
337  {
338  context->dropLocalVariable(OREF_RESULT, VARIABLE_RESULT);
339  }
340  context->pauseInstruction(); /* do debug pause if necessary */
341  }
342 }
343 
void reportException(wholenumber_t error)
RexxArray * new_array(size_t s)
Definition: ArrayClass.hpp:259
#define forward_continue
#define OREF_NULL
Definition: RexxCore.h:61
RexxArray * REQUEST_ARRAY(RexxObject *obj)
Definition: RexxCore.h:457
RexxString * REQUEST_STRING(RexxObject *object)
Definition: RexxCore.h:295
#define TheNilObject
Definition: RexxCore.h:191
#define Error_Execution_user_defined
#define Error_Execution_forward
#define Error_Execution_forward_arguments
#define VARIABLE_RESULT
#define memory_mark(oref)
Definition: RexxMemory.hpp:450
#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
size_t getMethodArgumentCount()
void setLocalVariable(RexxString *name, size_t index, RexxObject *value)
void traceResult(RexxObject *v)
void traceInstruction(RexxInstruction *v)
RexxObject * forward(RexxObject *, RexxString *, RexxObject *, RexxObject **, size_t, size_t, bool)
RexxObject ** getMethodArgumentList()
size_t getMethodNamedArgumentCount()
void dropLocalVariable(RexxString *name, size_t index)
size_t getDimension()
Definition: ArrayClass.cpp:693
size_t append(RexxObject *)
Definition: ArrayClass.cpp:485
size_t size()
Definition: ArrayClass.hpp:202
RexxObject * get(size_t pos)
Definition: ArrayClass.hpp:203
RexxObject ** data()
Definition: ArrayClass.hpp:204
size_t appendAllIndexesItemsTo(RexxArray *array, size_t from)
void replace(size_t offset, RexxObject *value)
void liveGeneral(int reason)
void execute(RexxActivation *, RexxExpressionStack *)
RexxObject * namedArgumentsExpression
void flatten(RexxEnvelope *)
uint16_t instructionFlags
RexxInstruction * nextInstruction
virtual RexxObject * evaluate(RexxActivation *, RexxExpressionStack *)
RexxDirectory * requestDirectory()
RexxString * upper()