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