1 /*
2 
3  HyPhy - Hypothesis Testing Using Phylogenies.
4 
5  Copyright (C) 1997-now
6  Core Developers:
7  Sergei L Kosakovsky Pond (sergeilkp@icloud.com)
8  Art FY Poon    (apoon42@uwo.ca)
9  Steven Weaver (sweaver@temple.edu)
10 
11  Module Developers:
12  Lance Hepler (nlhepler@gmail.com)
13  Martin Smith (martin.audacis@gmail.com)
14 
15  Significant contributions from:
16  Spencer V Muse (muse@stat.ncsu.edu)
17  Simon DW Frost (sdf22@cam.ac.uk)
18 
19  Permission is hereby granted, free of charge, to any person obtaining a
20  copy of this software and associated documentation files (the
21  "Software"), to deal in the Software without restriction, including
22  without limitation the rights to use, copy, modify, merge, publish,
23  distribute, sublicense, and/or sell copies of the Software, and to
24  permit persons to whom the Software is furnished to do so, subject to
25  the following conditions:
26 
27  The above copyright notice and this permission notice shall be included
28  in all copies or substantial portions of the Software.
29 
30  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
31  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
34  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
35  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
36  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 
38  */
39 
40 #include "defines.h"
41 #include "variable.h"
42 #include "operation.h"
43 
44 #include "parser.h"
45 #include "polynoml.h"
46 #include "batchlan.h"
47 #include "parser.h"
48 #include "global_things.h"
49 
50 using namespace hy_global;
51 
52 
53 extern _SimpleList BinOps,
54        opPrecedence,
55        FunctionArgumentCount,
56        associativeOps;
57 
58 _SimpleList     _Operation::ListOfInverseOps;
59 
60 
61 //__________________________________________________________________________________
62 
_Operation(void)63 _Operation::_Operation  (void) {
64     Initialize();
65  }
66 
67 //__________________________________________________________________________________
Initialize(bool)68 void    _Operation::Initialize(bool) {
69     numberOfTerms = 0;
70     theData = -1;
71     theNumber = nil;
72     cachedResult = nil;
73     opCode = -1;
74 }
75 
76 //__________________________________________________________________________________
makeDynamic(void) const77 BaseRef _Operation::makeDynamic (void) const {
78     _Operation * res = new _Operation;
79     res->Duplicate(this);
80     return res;
81 }
82 
83 //__________________________________________________________________________________
84 
_Operation(_Operation const & rhs)85 _Operation::_Operation (_Operation const& rhs) {
86     numberOfTerms  = rhs.numberOfTerms;
87     theData        = rhs.theData;
88     theNumber      = rhs.theNumber;
89     opCode         = rhs.opCode;
90     cachedResult   = rhs.cachedResult;
91     if (theNumber) {
92         theNumber->AddAReference();
93     }
94     if (cachedResult) {
95         cachedResult->AddAReference();
96     }
97 }
98 
99 
100 
101 //__________________________________________________________________________________
Duplicate(BaseRefConst r)102 void    _Operation::Duplicate(BaseRefConst r) {
103     _Operation const * o = (_Operation const*)r;
104     numberOfTerms  = o->numberOfTerms;
105     theData        = o->theData;
106     theNumber      = o->theNumber;
107     opCode         = o->opCode;
108     cachedResult   = o->cachedResult;
109     if (theNumber) {
110         theNumber->AddAReference();
111     }
112     if (cachedResult) {
113         cachedResult->AddAReference();
114     }
115 }
116 
117 //__________________________________________________________________________________
operator =(_Operation const & rhs)118 void    _Operation::operator = (_Operation const & rhs) {
119     Duplicate (&rhs);
120 }
121 
122 
123 //__________________________________________________________________________________
toStr(unsigned long)124 BaseRef _Operation::toStr (unsigned long) {
125 
126     if (theData != -1) {
127         return new _String (_String("Variable ")& *LocateVar(GetAVariable())->GetName());
128     } else if (theNumber) {
129         _FString * type = (_FString*)theNumber->Type();
130         _String res = _String("Constant (")& type->get_str() & ")" & _String((_String*)theNumber->toStr());
131         DeleteObject(type);
132         return new _String (res);
133     } else {
134         if (IsHBLFunctionCall())
135           return new _String (_String ("Call HBL function ") & GetBFFunctionNameByIndex(UserFunctionID()));
136         else
137           return new _String (_String("Operation ") & *(_String*)BuiltInFunctions(opCode) & " with " & _String((long)numberOfTerms) & " arguments");
138     }
139 
140 
141     return new _String ("This should not happen");
142 
143 }
144 
145 //__________________________________________________________________________________
_Operation(const long theCode,const long opNo=2)146 _Operation::_Operation  (const long theCode, const long opNo = 2) {
147 // by opcode
148     opCode = theCode;
149     numberOfTerms = opNo;
150     theData       = -1;
151     theNumber     = nil;
152     cachedResult  = nil;
153 }
154 
155 //__________________________________________________________________________________
_Operation(_String const & opc,const long opNo=2)156 _Operation::_Operation  (_String const& opc, const long opNo = 2) {
157 // construct the operation by its symbol and, if relevant -
158 // number of operands
159     if(opNo>=0) {
160         opCode = BuiltInFunctions.BinaryFindObject (&opc);
161     } else {
162         opCode = -opNo-1;
163     }
164 
165     if (opCode<0L) {
166         HandleApplicationError (_String ("Operation: ") & opc.Enquote() &" is not defined." );
167         opCode = 0;
168     }
169 
170     numberOfTerms = opNo;
171     theData       = -1;
172     theNumber     = nil;
173     cachedResult  = nil;
174 }
175 //__________________________________________________________________________________
_Operation(HBLObjectRef theObj)176 _Operation::_Operation  (HBLObjectRef theObj) {
177     numberOfTerms = 0;
178     theData       = -1;
179     opCode        = -1;
180     theNumber     = theObj;
181     cachedResult = nil;
182 }
183 
184 //__________________________________________________________________________________
_Operation(_Variable const & v)185 _Operation::_Operation  (_Variable const & v) {
186     numberOfTerms = 0;
187     theData       = v.get_index();
188     opCode        = -1;
189     theNumber     = nil;
190     cachedResult  = nil;
191 }
192 
193 //__________________________________________________________________________________
CanResultsBeCached(_Operation * prev,bool exp_only)194 bool _Operation::CanResultsBeCached (_Operation* prev, bool exp_only) {
195     if (theNumber == nil && theData == -1 && numberOfTerms == 1) {
196         if ((prev->theNumber && prev->theNumber->ObjectClass() == MATRIX)
197            || (prev->theData >= 0 && LocateVar (prev->theData)->ObjectClass () == MATRIX)) {
198             if (! exp_only || opCode == HY_OP_CODE_EXP)
199                 return true;
200         }
201     }
202     return false;
203 }
204 
205 //__________________________________________________________________________________
206 
IsConstantOfType(const long type) const207 bool   _Operation::IsConstantOfType   (const long type) const {
208   if (theNumber && (theNumber->ObjectClass() & type)) {
209     return true;
210   }
211   return false;
212 }
213 
214 
215 //__________________________________________________________________________________
216 
HasChanged(void)217 bool _Operation::HasChanged (void) {
218     if (theNumber) {
219         return theNumber->HasChanged();
220     }
221     if (theData >= 0) {
222         return LocateVar (GetAVariable())->HasChanged();
223     }
224 
225     return false;
226 }
227 
228 //__________________________________________________________________________________
_Operation(bool isVar,_String & stuff,bool isG,_VariableContainer const * theParent,bool take_a_reference)229 _Operation::_Operation  (bool isVar, _String& stuff, bool isG, _VariableContainer const* theParent, bool take_a_reference) {
230     if (isVar) { // creating a variable
231         long f;
232         _String theS (stuff);
233         if (theParent) {
234             // SLKP 20210223 : why is this here
235             // if a global variable aleady exists, ignore the context?
236             f = LocateVarByName(theS);
237 
238             if (f>=0L && !FetchVar(f)->IsGlobal()) {
239                 f = -1L;
240             }
241 
242             if (f<0L) {
243                 theS = (*theParent->theName)&"."&theS;
244             }
245         }
246 
247         f = LocateVarByName(theS);
248 
249         if (f<0L) {
250             _Variable v (theS, isG);
251             f = v.theIndex;
252         } else {
253             f = variableNames.GetXtra(f);
254         }
255 
256         theData       = f;
257         theNumber     = nil;
258         numberOfTerms = take_a_reference?(1):0;
259 
260     } else {
261         numberOfTerms = 0L;
262         if (stuff == kNoneToken || stuff == kNullToken)
263             theNumber = new _MathObject;
264         else
265             theNumber = new _Constant (stuff);
266         theData = -1L;
267     }
268     opCode = -1L;
269     cachedResult = nil;
270 }
271 
272 
273 //__________________________________________________________________________________
~_Operation(void)274 _Operation::~_Operation (void) {
275    DeleteAndZeroObject (theNumber);
276    DeleteAndZeroObject (cachedResult);
277 }
278 
279 //__________________________________________________________________________________
IsAVariable(bool deep)280 bool _Operation::IsAVariable(bool deep) {
281     if (theData == -1 || theData == -2) {
282         if (deep&&theNumber) {
283             return theNumber->IsVariable();
284         }
285         return false;
286     }
287     return true;
288 }
289 
290 //__________________________________________________________________________________
IsHBLFunctionCall(void) const291 bool _Operation::IsHBLFunctionCall (void) const {
292     return theData == -1 && numberOfTerms < 0;
293 }
294 
295 //__________________________________________________________________________________
GetHBLFunctionID(void) const296 long _Operation::GetHBLFunctionID (void) const {
297   return opCode;
298 }
299 
300 
301 //__________________________________________________________________________________
IsConstant(bool strict)302 bool _Operation::IsConstant (bool strict)
303 {
304     if (theData==-1) {
305         if (theNumber) {
306             return theNumber->IsConstant();
307         }
308 
309         return !(opCode == HY_OP_CODE_BRANCHLENGTH||opCode == HY_OP_CODE_RANDOM||opCode == HY_OP_CODE_TIME);
310     }
311     if (strict) {
312       return false;
313     }
314     return LocateVar(GetAVariable())->IsConstant();
315 
316 }
317 
318 //__________________________________________________________________________________
EqualOp(_Operation * otherOp)319 bool        _Operation::EqualOp (_Operation* otherOp)
320 {
321     if (theNumber) {
322         if (otherOp->theNumber) {
323             long oc = theNumber->ObjectClass();
324 
325             if ((oc == NUMBER) && (oc==otherOp->theNumber->ObjectClass())) {
326                 return CheckEqual (theNumber->Value(), otherOp->theNumber->Value());
327             }
328         }
329         return false;
330     } else if (theData==-1) {
331         if (numberOfTerms<0) {
332             return numberOfTerms == otherOp->numberOfTerms;
333         } else {
334             return opCode == otherOp->opCode;
335         }
336     } else {
337         return theData == otherOp->theData;
338     }
339 
340     return false;
341 }
342 
343 //__________________________________________________________________________________
344 
345 
BinOpCode(_String const & op_token,long index)346 long     _Operation::BinOpCode           (_String const & op_token, long index) {
347   if (index >= 0)
348     return BinOps.Find (op_token.char_at (index-1L) * 256L + op_token.char_at (index));
349 
350   return BinOps.Find (op_token.length () == 2 ? op_token.char_at(0) * 256L + op_token.char_at (1) : op_token.char_at (0));
351 }
352 
353 
354 //__________________________________________________________________________________
355 
ReportOperationExecutionError(_String text,_String * errMsg)356 bool        _Operation::ReportOperationExecutionError(_String text, _String * errMsg) {
357     _String theError = text & ". ";
358 
359     if (errMsg) {
360         *errMsg = theError;
361     } else {
362         HandleApplicationError (theError);
363     }
364 
365     return false;
366 }
367 
368 //__________________________________________________________________________________
StackDepth(void) const369 long        _Operation::StackDepth (void) const {
370   if (theNumber || theData != -1L) {
371     return 1L;
372   }
373 
374   if (numberOfTerms<0L) { // execute a user-defined function
375     return (numberOfTerms + 2); // assumes a return value
376   }
377 
378   return (1-numberOfTerms);
379 }
380 
381 
382 //__________________________________________________________________________________
Execute(_Stack & theScrap,_VariableContainer const * nameSpace,_String * errMsg,bool canCache)383 bool        _Operation::Execute (_Stack& theScrap, _VariableContainer const* nameSpace, _String* errMsg, bool canCache) {
384   if (theNumber) { // push value
385     theScrap.Push(theNumber);
386     return true;
387   }
388 
389   if (theData >= 0L) { // variable reference
390     if (numberOfTerms <= 0L) { // compute and push value
391       theScrap.Push(((_Variable*)((BaseRef*)variablePtrs.list_data)[theData])->Compute());
392     } else { // compute reference and push value
393       theScrap.Push (((_Variable*)((BaseRef*)variablePtrs.list_data)[theData])->ComputeReference(nameSpace),false);
394     }
395     return true;
396   }
397   if (theData < -2L) { // place variable value (no compute, i.e. pass by reference)
398     theScrap.Push(((_Variable*)((BaseRef*)variablePtrs.list_data)[-theData-3])->GetValue());
399     return true;
400   }
401   if (numberOfTerms<0) { // execute a user-defined function
402 
403       if (!IsBFFunctionIndexValid(opCode)) {
404         return ReportOperationExecutionError ("Attempted to call an undefined/deleted user function ", errMsg);
405       }
406 
407       long arguments = GetBFFunctionArgumentCount (opCode);
408 
409       if (theScrap.StackDepth()<arguments) {
410         return ReportOperationExecutionError (_String("User-defined function ") &
411                                               GetBFFunctionNameByIndex (opCode).Enquote()
412                                               &" needs "&_String(long(arguments))& " parameters, but "&_String(theScrap.StackDepth())&" were supplied ", errMsg);
413       }
414 
415       _List       displacedVars,
416       *funcVarList = &GetBFFunctionArgumentList(opCode),
417       displacedValues,
418       referenceArgs;
419 
420       _SimpleList existingIVars,
421       existingDVars,
422       displacedReferences,
423       *funcVarTypes = &GetBFFunctionArgumentTypes (opCode);
424 
425       bool        need_to_purge = false;
426 
427       //printf ("***** Calling %s\n", GetBFFunctionNameByIndex (opCode).sData);
428 
429       for (long k = arguments-1L; k >= 0; k--) {
430         bool            isRefVar = (funcVarTypes->Element (k) == kBLFunctionArgumentReference);
431 
432         _String         *argument_k = (_String*)funcVarList->Element(k);
433         HBLObjectRef       nthterm = theScrap.Pop();
434 
435         //printf ("\tArgument %d : %s (%s)\n", k, argument_k->get_str(), _String((_String*)nthterm->toStr()).get_str());
436 
437         if (isRefVar) {
438           need_to_purge = true;
439           if (nthterm->ObjectClass()!=STRING) {
440             _FString * type = (_FString*)nthterm->Type();
441             _String errText = _String ("User-defined function '")
442             & GetBFFunctionNameByIndex(opCode)
443             &"' expected a string for the reference variable '"
444             & *argument_k
445             &"' but was passed a " & type->get_str()
446             & " with the value of " & _String((_String*)nthterm->toStr());
447 
448             DeleteObject (type);
449             return ReportOperationExecutionError (errText, errMsg);
450           }
451         }
452 
453         _Variable* argument_var = CheckReceptacle (argument_k, kEmptyString, false, false, false);
454 
455         if (!isRefVar) {
456           if (argument_var->IsIndependent() && (argument_var->ObjectClass() & (TREE|TOPOLOGY)) == 0) {
457             // if the variable exists and is independent then
458             // simply swap the value of the var, otherwise
459             // duplicate the entire variable
460             argument_var->varFlags &= HY_VARIABLE_SET;
461             if (!argument_var->varValue) {
462               argument_var->Compute();
463             }
464             displacedValues<<argument_var->varValue;
465             argument_var->varFlags |= HY_VARIABLE_CHANGED;
466             argument_var->varValue = nthterm;
467             existingIVars<<argument_var->get_index();
468           } else {
469             _Variable *newV = new _Variable (*argument_k);
470             newV->SetValue(nthterm,false,true, NULL);
471             existingDVars<<argument_var->get_index();
472             displacedVars<<argument_var; // 2 references
473             argument_var->AddAReference(); // 3 references
474             variablePtrs.Replace (argument_var->get_index(),newV,false); // 2 references
475           }
476         } else {
477 
478           long new_index = argument_var->get_index();
479 
480           referenceArgs << argument_var->GetName();
481           displacedReferences<<new_index;
482 
483           _String const * refArgName = &((_FString*)nthterm)->get_str();
484 
485           _Variable* reference_var;
486           // TODO SLKP 20170928 Check that this doesn't break reference variable calls
487           // used to write namespaced variable to nthterm
488           if (nameSpace) {
489               reference_var =  CheckReceptacle (&AppendContainerName (*refArgName, nameSpace), kEmptyString, false, false, false);
490           } else {
491               reference_var =  CheckReceptacle (refArgName, kEmptyString, false, false, false);
492           }
493 
494           variableNames.SetXtra (new_index, reference_var->get_index());
495           DeleteObject (nthterm);
496         }
497       }
498 
499       _ExecutionList * function_body = &GetBFFunctionBody(opCode);
500 
501       if (need_to_purge) {
502         function_body->ResetFormulae();
503       }
504 
505       HBLObjectRef ret;
506 
507       bool update_kw = false;
508       if (currentExecutionList && (currentExecutionList->has_stdin_redirect() || currentExecutionList->has_keyword_arguments())) {
509           // 20180620: SLKP, need to split this off because if Execute fails
510           // then there will be a double free on stdinRedirect
511 
512         auto stash1 = currentExecutionList->stdinRedirect;
513         auto stash2 = currentExecutionList->stdinRedirectAux;
514         auto stash_kw_tags = currentExecutionList->kwarg_tags;
515         auto stash_kw = currentExecutionList->kwargs;
516 
517         if (currentExecutionList->has_stdin_redirect()) {
518             function_body -> stdinRedirect    = currentExecutionList->stdinRedirect;
519             function_body -> stdinRedirectAux = currentExecutionList->stdinRedirectAux;
520 
521             currentExecutionList->stdinRedirect->AddAReference();
522             currentExecutionList->stdinRedirectAux->AddAReference();
523         }
524 
525 
526         if (currentExecutionList->has_keyword_arguments()) {
527             function_body -> kwarg_tags    = currentExecutionList->kwarg_tags;
528             function_body -> kwargs = currentExecutionList->kwargs;
529             function_body -> currentKwarg = currentExecutionList->currentKwarg;
530 
531             if (stash_kw_tags) currentExecutionList->kwarg_tags->AddAReference();
532             if (stash_kw) currentExecutionList->kwargs->AddAReference();
533             update_kw = true;
534 
535         }
536 
537         ret = function_body->Execute();
538 
539         if (stash1) stash1 -> RemoveAReference();
540         if (stash2) stash2 -> RemoveAReference();
541         if (stash_kw_tags) stash_kw_tags->RemoveAReference();
542         if (stash_kw) stash_kw->RemoveAReference();
543 
544       } else {
545           ret = function_body->Execute();
546       }
547 
548       function_body -> stdinRedirect    = nil;
549       function_body -> stdinRedirectAux = nil;
550       if (update_kw) {
551           function_body -> kwarg_tags    = nil;
552           function_body -> kwargs = nil;
553           currentExecutionList->currentKwarg = function_body->currentKwarg;
554       }
555 
556       if (terminate_execution) {
557         theScrap.Push (new _Constant (0.0));
558         return true;
559       }
560 
561       if (ret) {
562         theScrap.Push (ret);
563       } else {
564         theScrap.Push (new _MathObject);
565       }
566 
567     //printf ("\nFunction result = %s\n", _String ((_String*)theScrap.Pop (false)->toStr()).getStr());
568 
569       for (unsigned long di = 0UL; di < referenceArgs.lLength; di++) {
570         variableNames.SetXtra(LocateVarByName (*(_String*)referenceArgs(di)),displacedReferences.list_data[di]);
571       }
572 
573       for (unsigned long dv = 0UL; dv < displacedVars.lLength; dv++) {
574         variablePtrs.Replace (existingDVars.list_data[dv],(HBLObjectRef)displacedVars(dv), false);
575       }
576 
577 
578       for (unsigned long dv2 = 0; dv2 < displacedValues.lLength; dv2++) {
579         _Variable* theV = LocateVar (existingIVars.list_data[dv2]);
580         DeleteObject(theV->varValue);
581         theV->varValue = ((HBLObjectRef)displacedValues(dv2));
582       }
583 
584       return true;
585 
586   }
587 
588   if (theScrap.theStack.lLength<numberOfTerms) {
589     return ReportOperationExecutionError (_String((_String*)toStr())&
590                                           " needs "&_String(numberOfTerms)& " arguments; "&_String(theScrap.StackDepth())&" were supplied", errMsg);
591 
592   }
593 
594   HBLObjectRef arg0 = ((HBLObjectRef)theScrap.theStack.list_data[theScrap.theStack.lLength-numberOfTerms]),
595             temp;
596 
597   _hyExecutionContext localContext (nameSpace, errMsg);
598 
599   if (numberOfTerms > 1) {
600     _List arguments;
601 
602     if (numberOfTerms == 2) {
603         arguments.AppendNewInstance ((HBLObjectRef)theScrap.theStack.list_data[theScrap.theStack.lLength - 1]);
604     } else {
605         for (long k = 1; k < numberOfTerms; k ++) {
606           arguments.AppendNewInstance ((HBLObjectRef)theScrap.theStack.list_data[theScrap.theStack.lLength - numberOfTerms + k]);
607         }
608     }
609 
610     if (canCache) {
611         temp =  arg0->ExecuteSingleOp(opCode, &arguments, &localContext, cachedResult);
612         if (temp != cachedResult) {
613             DeleteObject(cachedResult);
614             cachedResult = temp;
615         }
616         temp->AddAReference();
617     } else {
618         temp =  arg0->ExecuteSingleOp(opCode, &arguments, &localContext);
619     }
620     theScrap.theStack.lLength -= (numberOfTerms);
621 
622   } else {
623     temp =  ((HBLObjectRef)theScrap.theStack.list_data[theScrap.theStack.lLength-1])->ExecuteSingleOp(opCode, nil, &localContext);
624     theScrap.theStack.lLength--;
625   }
626 
627   DeleteObject (arg0);
628 
629   if (temp) {
630     theScrap.theStack.Place(temp);
631     return true;
632   } else {
633     return false;
634   }
635 
636 }
637 
638 //__________________________________________________________________________________
StackDepth(long & depth)639 void        _Operation::StackDepth (long& depth)
640 {
641     if (theNumber || theData > -1 || theData < -2) {
642         depth++;
643         return;
644     }
645 
646     if (numberOfTerms<0) { // execute a user-defined function
647         depth -= GetBFFunctionArgumentCount(opCode) - 1L;
648         return;
649     }
650     depth -= numberOfTerms - 1;
651 }
652 
653 
654 //__________________________________________________________________________________
ExecutePolynomial(_Stack & theScrap,_VariableContainer * nameSpace,_String * errMsg)655 bool        _Operation::ExecutePolynomial (_Stack& theScrap, _VariableContainer* nameSpace, _String* errMsg) {
656     if (theData<=-2 || numberOfTerms < 0) {
657         return false;
658     }
659 
660     _Polynomial*p = nil;
661     if (theNumber) {
662         if (theNumber->ObjectClass() == NUMBER) {
663             p= new _Polynomial(theNumber->Value());
664         } else {
665             return false;
666         }
667     } else {
668         if (theData>-1) {
669             p=  new _Polynomial(*LocateVar(theData>-1?theData:-theData-2));
670         }
671     }
672 
673     if (p) {
674         theScrap.Push(p);
675         DeleteObject(p);
676         return true;
677     }
678 
679     if (theScrap.StackDepth()<numberOfTerms) {
680         _String s((_String*)toStr());
681         return ReportOperationExecutionError (s&
682                    " needs "&_String(numberOfTerms)& " arguments. Only "&_String(theScrap.StackDepth())&" were given", errMsg);
683     }
684 
685 
686     HBLObjectRef arg0 = ((HBLObjectRef)theScrap.theStack.list_data[theScrap.theStack.lLength-numberOfTerms]),
687     temp;
688 
689     _hyExecutionContext localContext (nameSpace, errMsg);
690 
691     if (numberOfTerms > 1) {
692       _List arguments;
693 
694       for (long k = numberOfTerms-1; k >= 1; k --) {
695         arguments.AppendNewInstance ((HBLObjectRef)theScrap.theStack.list_data[theScrap.theStack.lLength-k]);
696       }
697 
698       temp =  arg0->ExecuteSingleOp(opCode, &arguments, &localContext);
699       theScrap.theStack.lLength -= (numberOfTerms);
700 
701     } else {
702       temp =  ((HBLObjectRef)theScrap.theStack.list_data[theScrap.theStack.lLength-1])->ExecuteSingleOp(opCode, nil, &localContext);
703       theScrap.theStack.lLength--;
704     }
705 
706     DeleteObject (arg0);
707 
708 
709     if (temp && temp->ObjectClass() != HY_UNDEFINED ) {
710       theScrap.theStack.Place(temp);
711       return true;
712     } else {
713      DeleteObject (temp);
714      return false;
715     }
716 
717 
718 }
719 
720