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 <math.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <ctype.h>
44 #include <float.h>
45 #include <time.h>
46 
47 
48 #include "parser.h"
49 #include "matrix.h"
50 #include "calcnode.h"
51 #include "likefunc.h"
52 #include "polynoml.h"
53 #include "batchlan.h"
54 #include "category.h"
55 #include "function_templates.h"
56 #include "global_things.h"
57 #include "global_object_lists.h"
58 
59 using namespace hy_global;
60 
61 
62 extern   _SimpleList BinOps,
63          opPrecedence,
64          FunctionArgumentCount,
65          associativeOps;
66 
67 extern    _Trie         FunctionNameList;
68 
69 
70 
71 
72 
73 _SimpleList simpleOperationCodes,
74             simpleOperationFunctions;
75 
76 
77 //__________________________________________________________________________________
AddNumbers(hyFloat x,hyFloat y)78 hyFloat  AddNumbers  (hyFloat x, hyFloat y) {
79     return x+y;
80 }
SubNumbers(hyFloat x,hyFloat y)81 hyFloat  SubNumbers  (hyFloat x, hyFloat y) {
82     return x-y;
83 }
MinusNumber(hyFloat x)84 hyFloat  MinusNumber (hyFloat x) {
85     return -x;
86 }
MultNumbers(hyFloat x,hyFloat y)87 hyFloat  MultNumbers (hyFloat x, hyFloat y) {
88     return x*y;
89 }
DivNumbers(hyFloat x,hyFloat y)90 hyFloat  DivNumbers  (hyFloat x, hyFloat y) {
91     return x/y;
92 }
LessThan(hyFloat x,hyFloat y)93 hyFloat  LessThan    (hyFloat x, hyFloat y) {
94     return x<y;
95 }
GreaterThan(hyFloat x,hyFloat y)96 hyFloat  GreaterThan (hyFloat x, hyFloat y) {
97     return x>y;
98 }
LessThanE(hyFloat x,hyFloat y)99 hyFloat  LessThanE   (hyFloat x, hyFloat y) {
100     return x<=y;
101 }
GreaterThanE(hyFloat x,hyFloat y)102 hyFloat  GreaterThanE(hyFloat x, hyFloat y) {
103     return x>=y;
104 }
Power(hyFloat x,hyFloat y)105 hyFloat  Power       (hyFloat x, hyFloat y) {
106     if (x==0.0) {
107       if (y > 0.0) {
108         return 0.0;
109       } else {
110         return 1.0;
111       }
112     }
113     return pow(x,y);
114 }
115 
MaxNumbers(hyFloat x,hyFloat y)116 hyFloat  MaxNumbers  (hyFloat x, hyFloat y) {
117     return x<y?y:x;
118 }
MinNumbers(hyFloat x,hyFloat y)119 hyFloat  MinNumbers  (hyFloat x, hyFloat y) {
120     return x<y?x:y;
121 }
ExpNumbers(hyFloat x)122 hyFloat  ExpNumbers  (hyFloat x) {
123     return exp(x);
124 }
LogNumbers(hyFloat x)125 hyFloat  LogNumbers  (hyFloat x) {
126     return log(x);
127 }
FastMxAccess(hyPointer m,hyFloat index)128 hyFloat  FastMxAccess(hyPointer m, hyFloat index) {
129     return ((hyFloat*)m)[(unsigned long)index];
130 }
131 
FastMxWrite(hyPointer m,hyFloat index,hyFloat value)132 void  FastMxWrite(hyPointer m, hyFloat index, hyFloat value) {
133   ((hyFloat*)m)[(unsigned long)index] = value;
134 }
135 
AndNumbers(hyFloat x,hyFloat y)136 hyFloat  AndNumbers  (hyFloat x, hyFloat y) {
137     return x != 0.0 && y != 0.0;
138 }
AbsNumber(hyFloat x)139 hyFloat  AbsNumber  (hyFloat x) {
140     return fabs (x);
141 }
142 
143 //__________________________________________________________________________________
144 
RandomNumber(hyFloat l,hyFloat u)145 hyFloat  RandomNumber(hyFloat l, hyFloat u) {
146     hyFloat r = l;
147     if (u>l) {
148         r =l+(u-l)*genrand_real1();
149     }
150     return r;
151 }
152 
153 
154 
155 //_______________________________________________________________________________________
EqualNumbers(hyFloat a,hyFloat b)156 hyFloat  EqualNumbers(hyFloat a, hyFloat b) {
157     if (a!=0.0) {
158         a = (a>b)?(a-b)/a:(b-a)/a;
159         return a>0. ? a<=kMachineEpsilon : a>=-kMachineEpsilon;
160     }
161     return b<=kMachineEpsilon && b>=-kMachineEpsilon;
162 }
163 
164 //_______________________________________________________________________________________
PopulateArraysForASimpleFormula(_SimpleList & vars,_SimpleFormulaDatum * values)165 void        PopulateArraysForASimpleFormula (_SimpleList& vars, _SimpleFormulaDatum* values) {
166     try {
167         vars.Each ([&] (long var_index, unsigned long array_index) -> void {
168             HBLObjectRef var_value = LocateVar (var_index)->Compute();
169             if (var_value->ObjectClass() == NUMBER) {
170                 values[array_index].value = var_value->Value();
171             } else {
172                 if (var_value->ObjectClass() == MATRIX) {
173                     values[array_index].reference = (hyPointer)((_Matrix*)var_value)->theData;
174                 } else {
175                     throw (_String("Internal error in PopulateArraysForASimpleFormula; this means that a prospectively compiled batch code was passed arguments it does not support (e.g. a dict argument to a cfunction)"));
176                 }
177             }
178         });
179     } catch (const _String& e) {
180         HandleApplicationError (e, true);
181     }
182 }
183 
184 
185 //__________________________________________________________________________________
186 
WarnNotDefined(HBLObjectRef p,long opCode,_hyExecutionContext * context)187 void        WarnNotDefined (HBLObjectRef p, long opCode, _hyExecutionContext* context) {
188     _FString * t = (_FString*)p->Type();
189     context->ReportError  (_String("Operation '")&*(_String*)BuiltInFunctions(opCode)&"' is not implemented/defined for a " & t->get_str());
190     DeleteObject (t);
191 }
192 
193 //__________________________________________________________________________________
194 
WarnWrongNumberOfArguments(HBLObjectRef p,long opCode,_hyExecutionContext * context,_List * args)195 void        WarnWrongNumberOfArguments (HBLObjectRef p, long opCode, _hyExecutionContext* context, _List * args) {
196   _FString * t = (_FString*)p->Type();
197   context->ReportError  (_String("Operation '")&*(_String*)BuiltInFunctions(opCode)&"' was called with an incorrect number of arguments (" & (long) (args ? args->countitems() + 1L : 1L) & ") for " & t->get_str());
198   DeleteObject (t);
199 }
200 
201 
202 //__________________________________________________________________________________
203 
ExecuteFormula(_Formula * f,_Formula * f2,long code,long reference,_VariableContainer * nameSpace,char assignment_type)204 long       ExecuteFormula (_Formula*f , _Formula* f2, long code, long reference, _VariableContainer* nameSpace, char assignment_type) {
205     /** TODO SLKP 20171128: this needs review */
206 
207     if (assignment_type != kStringDirectReference && reference >= 0) {
208         long dereferenced = DereferenceVariable(reference, nameSpace, assignment_type);
209         if (dereferenced < 0) {
210             HandleApplicationError (_String ("Failed to dereference '") & *FetchVar(reference)->GetName() & "' in the " & ((assignment_type == kStringGlobalDeference) ? "global" : "local") & " context");
211             return 0;
212         }
213         reference = dereferenced;
214     }
215 
216 
217     if (code == HY_FORMULA_EXPRESSION || code == HY_FORMULA_VARIABLE_VALUE_ASSIGNMENT || code == HY_FORMULA_REFERENCE_VALUE_ASSIGNMENT) {
218         HBLObjectRef  formulaValue = (code == HY_FORMULA_REFERENCE_VALUE_ASSIGNMENT)?f2->Compute(0, nameSpace):f->Compute(0,nameSpace);
219         if (!formulaValue) {
220             return 0;
221         }
222 
223         if (code == HY_FORMULA_VARIABLE_VALUE_ASSIGNMENT) {
224             // copy by value or by reference?
225             //formulaValue->AddAReference();
226             LocateVar (reference)->SetValue (formulaValue, true,true,NULL);
227             return 1;
228         }
229 
230         if (code == HY_FORMULA_REFERENCE_VALUE_ASSIGNMENT) {
231             _hyExecutionContext localContext (nameSpace);
232             _Variable * theV = f->Dereference(assignment_type == kStringGlobalDeference, &localContext);
233             if (theV) {
234                 theV->SetValue (formulaValue, true,true,NULL);
235             } else {
236                 return 0;
237             }
238             return 1;
239         }
240         return 0;
241     }
242 
243     if (code == HY_FORMULA_VARIABLE_FORMULA_ASSIGNMENT) {
244         _Formula fFixed;
245         fFixed.DuplicateReference(f);
246         LocateVar (reference)->SetFormula (fFixed);
247         return 1;
248     }
249 
250     if (code == HY_FORMULA_REFERENCE_FORMULA_ASSIGNMENT) {
251         _hyExecutionContext localContext (nameSpace);
252         _Variable * theV = f->Dereference(assignment_type == kStringGlobalDeference, &localContext);
253         if (theV) {
254             _Formula fFixed;
255             fFixed.DuplicateReference(f2);
256             theV->SetFormula (fFixed);
257             return 1;
258         } else {
259             return 0;
260         }
261 
262     }
263 
264     if (code == HY_FORMULA_VARIABLE_UPPER_BOUND_ASSIGNMENT || code == HY_FORMULA_VARIABLE_LOWER_BOUND_ASSIGNMENT ||
265         code == HY_FORMULA_REFERENCE_UPPER_BOUND_ASSIGNMENT || code == HY_FORMULA_REFERENCE_LOWER_BOUND_ASSIGNMENT ) {
266         if (f2->IsEmpty()) {
267             HandleApplicationError ("Empty RHS in a constraint assignment.");
268             return 0;
269         }
270 
271         HBLObjectRef varObj = f2->Compute(0, nameSpace);
272         if (varObj->ObjectClass()!=NUMBER) {
273             HandleApplicationError ("Not a numeric RHS in a constraint assignment.");
274             return 0;
275         }
276 
277         _Variable * theV;
278 
279         if (code == HY_FORMULA_VARIABLE_UPPER_BOUND_ASSIGNMENT || code == HY_FORMULA_VARIABLE_LOWER_BOUND_ASSIGNMENT) {
280             theV= LocateVar (reference);
281         } else {
282             _hyExecutionContext localContext (nameSpace);
283             theV = f->Dereference(assignment_type == kStringGlobalDeference, &localContext);
284             if (!theV) {
285                 return 0;
286             }
287         }
288 
289         if (code == HY_FORMULA_VARIABLE_UPPER_BOUND_ASSIGNMENT || code == HY_FORMULA_REFERENCE_UPPER_BOUND_ASSIGNMENT) {
290             theV->SetBounds(varObj->Value(),theV->GetUpperBound());
291         } else {
292             theV->SetBounds(theV->GetLowerBound(),varObj->Value());
293         }
294 
295 
296         /*
297             SLKP 20110301 if the new constraint makes the current variable value
298             invalid, then the value will be modified to stay in bounds*/
299 
300         theV->EnsureTheValueIsInBounds();
301 
302     }
303 
304 
305     if ( code== HY_FORMULA_FORMULA_FORMULA_ASSIGNMENT || code== HY_FORMULA_FORMULA_VALUE_ASSIGNMENT || code == HY_FORMULA_FORMULA_VALUE_INCREMENT) {
306         _Formula newF;
307         HBLObjectRef rhsValue = nil;
308 
309         if (f2->IsEmpty()) {
310             HandleApplicationError ("Empty RHS in an assignment.");
311             return 0;
312         }
313 
314         if (code == HY_FORMULA_FORMULA_FORMULA_ASSIGNMENT) {
315             newF.DuplicateReference(f2);
316         } else {
317             //newF.theFormula.AppendNewInstance(new _Operation((HBLObjectRef)f2->Compute(0, nameSpace)->makeDynamic()));
318             rhsValue = (HBLObjectRef)f2->Compute(0, nameSpace)->makeDynamic();
319             //rhsValue->makeDynamic();
320             //newF.theFormula.AppendNewInstance(new _Operation(rhs_value));
321         }
322 
323         long stackD = -1L,
324              last0  = 0L;
325 
326         for (long opID = 0; opID < f->theFormula.lLength - 1; opID ++) {
327             ((_Operation*)f->theFormula(opID)) -> StackDepth (stackD);
328             if (stackD == 0L) {
329                 last0 = opID;
330             }
331         }
332 
333         _Matrix          * mmx = nil;
334         _AssociativeList * mma = nil;
335 
336         if (last0 > 0) {
337             stackD = f->theFormula.lLength;
338             f->theFormula.lLength       = last0+1;
339             HBLObjectRef   lvalue  = f->Compute(0, nameSpace);
340             f->theFormula.lLength = stackD;
341             if (lvalue->ObjectClass () == MATRIX) {
342                 mmx = (_Matrix*)lvalue;
343             }
344             if (lvalue->ObjectClass () == ASSOCIATIVE_LIST) {
345                 mma = (_AssociativeList*)lvalue;
346             }
347             last0++;
348         } else {
349 
350             _Operation * lValue = f->GetIthTerm(0L);
351 
352             if (lValue && lValue->IsAVariable(false)) {
353              _Variable* mmo = LocateVar(lValue->GetAVariable());
354              if (mmo->ObjectClass () == MATRIX) {
355                 mmx = (_Matrix*)(mmo->GetValue());
356                 lValue->SetAVariable(-lValue->GetAVariable()-3);
357               } else {
358 
359                 if (mmo->ObjectClass () == ASSOCIATIVE_LIST) {
360                   mma = (_AssociativeList*)(mmo->GetValue());
361                   lValue->SetAVariable(-lValue->GetAVariable()-3);
362                 }
363               }
364             }
365         }
366 
367         HBLObjectRef coordMx = nil;
368         if (mma || mmx) {
369             long expectedType = mmx?MATRIX:STRING;
370             coordMx = f->Compute(last0);
371             if (!coordMx || coordMx->ObjectClass() != expectedType) {
372                 if (mmx) {
373                     HandleApplicationError ("Matrix expected but not supplied.");
374                 } else {
375                     HandleApplicationError ("String key expected but not supplied.");
376                 }
377 
378                 return 0;
379             }
380         } else {
381             HandleApplicationError ("Matrix/List LHS expected but not supplied.");
382             return 0;
383         }
384 
385 
386         if (mmx) { // matrix LHS
387             _Matrix * mcoord = (_Matrix*)coordMx;
388 
389             long hC = mcoord->theData[0],
390                  vC = mcoord->theData[1];
391 
392             if (mmx->CheckCoordinates (hC,vC)) {
393                 if (!ANALYTIC_COMPUTATION_FLAG) {
394                     if (rhsValue) {
395                         mmx->MStore (hC, vC, rhsValue, (code==HY_FORMULA_FORMULA_VALUE_INCREMENT)?HY_OP_CODE_ADD:HY_OP_CODE_NONE);
396                         DeleteObject (rhsValue);
397                     } else {
398                         mmx->MStore (hC, vC, newF, (code==HY_FORMULA_FORMULA_VALUE_INCREMENT)?HY_OP_CODE_ADD:HY_OP_CODE_NONE);
399                     }
400                 } else {
401                     HBLObjectRef newP = newF.ConstructPolynomial();
402                     if (!newP) {
403                         HandleApplicationError ("Can't assign non-polynomial entries to polynomial matrices.");
404                     } else {
405                         mmx->MStore (hC,vC, newP);
406                     }
407                 }
408                 mmx->CheckIfSparseEnough();
409             }
410         } else if (mma) { // Associative array LHS
411             if (rhsValue) {
412                 mma->MStore (coordMx, rhsValue, true, (code==HY_FORMULA_FORMULA_VALUE_INCREMENT)?HY_OP_CODE_ADD:HY_OP_CODE_NONE);
413                 DeleteObject (rhsValue);
414             }
415             else
416                 mma->MStore (coordMx, newF.Compute(), true, (code==HY_FORMULA_FORMULA_VALUE_INCREMENT)?HY_OP_CODE_ADD:HY_OP_CODE_NONE);
417         }
418 
419         return 1;
420     }
421     return 0;
422 }
423 
424 //__________________________________________________________________________________
425 //__________________________________________________________________________________
426 
427 struct      _characterChecker {
_characterChecker_characterChecker428     _characterChecker (_String const s) {
429         InitializeArray(isAllowed,256, false);
430         for (unsigned long r2 = 0UL; r2<s.length(); r2++) {
431             isAllowed [s.get_uchar (r2)] = true;
432         }
433     }
434     bool     isAllowed [256];
435 }
436 
437 alpha       ("ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"),
438             numeric     (".0123456789eE");
439 
440 _String     const kGlobalToken ("global");
441 
442 
443 #define CONTEXT_TRUNCATION 24
444 
445 //__________________________________________________________________________________
HandleFormulaParsingError(_String errMsg,_String * saveError,_String & s,long index)446 long        HandleFormulaParsingError (_String errMsg, _String* saveError, _String& s, long index) {
447     if (index >= 0) {
448         errMsg = errMsg & " in the following context: '"&s.Cut(MAX(0,index-CONTEXT_TRUNCATION),index)&"<ERROR HERE>"&s.Cut(index+1,MIN (index+CONTEXT_TRUNCATION, s.length()-1)) & "'";
449     }
450     if (saveError) {
451         *saveError = errMsg;
452     } else {
453         HandleApplicationError (errMsg);
454     }
455     return HY_FORMULA_FAILED;
456 }
457 
458 //__________________________________________________________________________________
checkLHS(_List * levelOps,_List * levelData,_String & errMsg,char & deref,_Formula * f,_Variable * & lhs,_FormulaParsingContext & context)459 bool        checkLHS (_List* levelOps, _List* levelData, _String& errMsg, char & deref, _Formula * f, _Variable*& lhs, _FormulaParsingContext& context) {
460     bool check = true;
461 
462     lhs = nil;
463 
464     if (f->IsEmpty()) {
465     /* nothing has been added to the formula previously, so this should be a simple assignment
466        to a variable */
467         if (levelOps->lLength == 0) {
468             if (levelData->lLength == 0) {
469                 errMsg = "An empty left-hand side";
470                 return false;
471             }
472         }
473     } else {
474         if (levelData->lLength > 0) {
475              errMsg = "Only simple variable references [e.g. var = value or *ref = value or *(string expression) = value] can appear on the LHS of assignments";
476              return false;
477         }
478     }
479 
480     deref = kStringDirectReference;
481     if (levelOps->lLength > 0) { // this is where 'f is non-empty' cases will go
482         check = false;
483         if (levelOps->lLength == 1) {
484             char buffered_op = ((_Operation*)((*levelOps)(0)))->TheCode();
485             if (buffered_op == HY_OP_CODE_MUL) {
486                 check = true; deref = kStringLocalDeference;
487             } else {
488                 if (buffered_op == HY_OP_CODE_POWER) {
489                     check = true; deref = kStringGlobalDeference;
490                 } else {
491                     errMsg = "* and ^ are the two supported de-referencing operations";
492                 }
493             }
494         } else {
495             errMsg = "Expressions (other than matrix/dict access) cannot appear on the left-hand side of assignments";
496         }
497     } else {
498         if (levelData->lLength != 1) {
499             errMsg = "The left hand side expression does not contain an object reference";
500             check = false;
501         }
502     }
503     if (check && levelData->lLength == 1) {
504         _Operation * theOp = dynamic_cast<_Operation*>(levelData->GetItem(0));
505 
506         check = false;
507         if (theOp) {
508           if (theOp->IsAVariable(false)) {
509             lhs = LocateVar(theOp->GetAVariable());
510             check = true;
511           } else {
512             if (theOp->GetANumber() && theOp->GetANumber()->ObjectClass() == STRING) {
513               // handle things like ^"id" = value
514               if (deref != kStringDirectReference) {
515                 _hyExecutionContext cntx (context.formulaScope(), context.errMsg());
516                 lhs = (_Variable*) ((_FString*)theOp->GetANumber())->Dereference(deref == kStringGlobalDeference, &cntx, true);
517                 if (!lhs) {
518                   errMsg = "The left-hand side of an assignment like ^\"id\" must reference an existing variable";
519                   return false;
520                 } else {
521                   deref = kStringDirectReference;
522                   check = true;
523                 }
524               }
525             }
526           }
527         }
528 
529         if (!check) {
530           errMsg = "The left-hand side of an assignment must be a variable (not a constant)";
531         }
532     }
533     return check;
534 }
535 
536 //__________________________________________________________________________________
_parserHelperHandleInlineBoundCases(_String & s,_FormulaParsingContext & parsingContext,long i,_Variable * lhs_variable,_Formula * f,char deref,_Formula & newF)537 long _parserHelperHandleInlineBoundCases (_String& s, _FormulaParsingContext& parsingContext, long i, _Variable* lhs_variable, _Formula * f, char deref, _Formula &newF) {
538     HBLObjectRef varObj = newF.Compute();
539     if (varObj->ObjectClass()!=NUMBER) {
540         return HandleFormulaParsingError ("Variable bound must evaluate to a number ", parsingContext.errMsg(), s, i);
541     }
542 
543     long varID;
544 
545     if (lhs_variable) {
546         varID = DereferenceVariable(lhs_variable->get_index(), parsingContext.formulaScope(), deref);
547     } else {
548         varID = DereferenceString(f->Compute(0, parsingContext.formulaScope(), nil, parsingContext.errMsg()), parsingContext.formulaScope(), deref);
549     }
550     if (varID < 0) {
551         return HandleFormulaParsingError ("Failed to dereference ", parsingContext.errMsg(), s, i);
552     }
553 
554     _Variable * theV = (_Variable*)LocateVar(varID);
555 
556     if (s.get_char(i)=='>') {
557         theV->SetBounds(varObj->Value(),theV->GetUpperBound());
558     } else {
559         theV->SetBounds(theV->GetLowerBound(),varObj->Value());
560     }
561     return HY_FORMULA_EXPRESSION;
562 }
563 
564 //__________________________________________________________________________________
_parserHelperHandleInlineAssignmentCases(_String & s,_FormulaParsingContext & parsingContext,long i,_Variable * lhs_variable,_Formula * f,char deref,_Formula & newF,bool twoToken)565 long _parserHelperHandleInlineAssignmentCases (_String& s, _FormulaParsingContext& parsingContext, long i, _Variable* lhs_variable, _Formula * f, char deref, _Formula &newF, bool twoToken) {
566 
567 
568     long varID;
569 
570     if (lhs_variable) {
571         varID = DereferenceVariable(lhs_variable->get_index(), parsingContext.formulaScope(), deref);
572     } else {
573         varID = DereferenceString(f->Compute(0, parsingContext.formulaScope(), nil, parsingContext.errMsg()), parsingContext.formulaScope(), deref);
574     }
575     if (varID < 0) {
576         return HandleFormulaParsingError ("Failed to dereference ", parsingContext.errMsg(), s, i);
577     }
578     _Variable * theV = (_Variable*)LocateVar(varID);
579 
580     if (s.get_char(i-1) != ':') {
581         HBLObjectRef varObj = newF.Compute();
582         if (!varObj) {
583             return HandleFormulaParsingError ("Invalid RHS in an assignment ", parsingContext.errMsg(), s, i);
584         }
585         if (twoToken && s.get_char(i-1) == '+') {
586             _List arg;
587             arg <<  varObj;
588             theV->SetValue(theV->Compute()->ExecuteSingleOp(HY_OP_CODE_ADD,&arg), true,true,NULL);
589         } else {
590             theV->SetValue(varObj, true,true,NULL);
591         }
592     } else {
593         theV->SetFormula (newF);
594     }
595     return HY_FORMULA_EXPRESSION;
596 }
597 
598 //__________________________________________________________________________________
599 
_parse_new_level(long & level,_List & operations,_List & operands,_List * & levelOps,_List * & levelData,_String & curOp,_SimpleList & functionCallTags,long function_tag=-1L)600 void        _parse_new_level (long & level, _List & operations, _List& operands, _List*& levelOps, _List*& levelData, _String& curOp, _SimpleList& functionCallTags, long function_tag = -1L) {
601 
602   level ++;
603   operations.AppendNewInstance (new _List);
604   operands.AppendNewInstance (new _List);
605 
606   levelOps  = (_List*)(operations(level));
607   levelData = (_List*)(operands(level));
608 
609   functionCallTags << function_tag;
610 
611   curOp = kEmptyString;
612 }
613 
614 
615 //#define _TRACK_PARSE_COUNTS
616 
617 #ifdef _TRACK_PARSE_COUNTS
618     unsigned long parse_counter = 0UL;
619     _List       _parse_counter_list;
620     _AVLListX   _parse_counter_dict (&_parse_counter_list);
621 #endif
622 
623 
624 //__________________________________________________________________________________
Parse(_Formula * f,_String & s,_FormulaParsingContext & parsingContext,_Formula * f2)625 long        Parse (_Formula* f, _String& s, _FormulaParsingContext& parsingContext, _Formula* f2)
626 /* SLKP 20110908: added the concept of a 'volatile' formula, i.e. something that should be reparsed every time in ExecuteCase0
627                 : currently those include
628                 :    inline constructors (matrices, dictionaries)
629                 :    `` substitutions in strings
630 
631 
632    SLKP 20100817: decoupled return code from variable reference return
633 */
634 
635 // returns:
636 
637 /*
638 
639  case                       | return value                                  | parsingContext.assignment_ref_id value
640 
641  parse failed               | HY_FORMULA_FAILED                             | undefined
642  expresion (no LHS)         | HY_FORMULA_EXPRESSION                         | undefined
643  z = x/y                    | HY_FORMULA_VARIABLE_VALUE_ASSIGNMENT          | index of the LHS
644  *|^(expr) = expr           | HY_FORMULA_REFERENCE_VALUE_ASSIGNMENT         | undefined
645  z := x/y                   | HY_FORMULA_VARIABLE_FORMULA_ASSIGNMENT        | index of the LHS
646  object[a] := x/y           | HY_FORMULA_FORMULA_FORMULA_ASSIGNMENT         | undefined
647  object[a] = x/y            | HY_FORMULA_FORMULA_VALUE_ASSIGNMENT           | undefined
648  z :< expr                  | HY_FORMULA_VARIABLE_LOWER_BOUND_ASSIGNMENT    | index of the LHS
649  z :> expr                  | HY_FORMULA_VARIABLE_UPPER_BOUND_ASSIGNMENT    | index of the LHS
650 
651  Further, for (HY_FORMULA_VARIABLE_VALUE_ASSIGNMENT,  HY_FORMULA_VARIABLE_FORMULA_ASSIGNMENT,
652  HY_FORMULA_VARIABLE_LOWER_BOUND_ASSIGNMENT, HY_FORMULA_VARIABLE_UPPER_BOUND_ASSIGNMENT,
653  HY_FORMULA_REFERENCE_VALUE_ASSIGNMENT):
654 
655  case            |   parsingContext.assignment_ref_type value
656 
657  z op x/y        |   kStringDirectReference
658  *z op x/y       |   kStringLocalDeference
659  ^z op x/y       |   kStringGlobalDeference
660 
661 
662 */
663 
664 {
665   //static bool inAssignment = false;
666 
667     static _String kEmptyDict   = "{}";
668     static _String kEmptyStringQuote = "\"\"";
669     if ( s == kEmptyDict) {
670         // SLKP 20200921: this is a common enough case that its worth shortcutting it
671         f->theFormula.AppendNewInstance (new _Operation (new _AssociativeList));
672         return HY_FORMULA_EXPRESSION;
673     }
674     if ( s == kEmptyStringQuote) {
675         // SLKP 20200921: this is a common enough case that its worth shortcutting it
676         f->theFormula.AppendNewInstance (new _Operation (new _FString));
677         return HY_FORMULA_EXPRESSION;
678     }
679 
680     // also check to see if the expression is a number
681 
682     if ( s.length () > 0 && s.length () < 30) {
683         hyFloat number;
684         int upto;
685         if (sscanf (s.get_str(), "%lf%n", &number, &upto) == 1) {
686             if (upto == s.length()) {
687                 f->theFormula.AppendNewInstance (new _Operation (new _Constant (number)));
688                 return HY_FORMULA_EXPRESSION;
689             }
690         }
691     }
692 
693     _List           operations,
694                     operands,
695                     *levelOps,
696                     *levelData;
697 
698     /*04252006*/
699 
700     _SimpleList     squareBrackets,
701                     mergeMAccess,
702                     mergeMAccessLevel,
703                     functionCallTags
704                     /*
705                       for each context level, stores -1, if this level is not a function call,
706                       or the first operation associated with the argument list for this function
707                       call
708                      */
709                     ;
710 
711 
712 
713 #ifdef _TRACK_PARSE_COUNTS
714     if (s.nonempty()) {
715         _parse_counter_dict.UpdateValue (new _String (s), 1, 0);
716         parse_counter++;
717         if (parse_counter % 50000 == 0) {
718             printf ("\n>>%ld FORMULA PARSE<<\n", parse_counter);
719             for (AVLListXIteratorKeyValue variable_record : AVLListXIterator (&_parse_counter_dict)) {
720                 if (variable_record.get_value() > parse_counter * 0.001) {
721                     printf ("%s: %ld\n", ((_String*)_parse_counter_dict.Retrieve (variable_record.get_index()))->get_str(), variable_record.get_value());
722 
723                 }
724             }
725             NLToConsole(); NLToConsole();
726         }
727     }
728 #endif
729 
730     long            level                 = -1;
731     /* 04252006 mlevel = -1, */
732     /* mcount = 0 ; */
733 
734     _String curOp;
735 
736     bool            impliedMult = false,
737                     globalKey   = false,
738                     twoToken    = false;
739 
740     char            storage     = 0;
741 
742 
743     _parse_new_level (level, operations, operands, levelOps, levelData, curOp, functionCallTags);
744     for (long i = 0; i<=s.length(); i++) {
745         char     lookAtMe = s.get_char(i);
746 
747         if (isspace(lookAtMe)) { // skip spaces and tabs
748             continue;
749         }
750 
751         storage = 0; // no implied ops by default
752 
753         //printf ("at '%c', the formula looks like this %s\n", lookAtMe, (const char*)_String ((_String*)f->GetList().toStr()));
754 
755         if (i==s.length() || lookAtMe == ')' || lookAtMe == ']' || lookAtMe == ',') {
756             // closing ) or ]
757             // or a parameter list
758                 /* 04252006 if (level == mlevel && s.get_char(i)!=']')*/
759             if (squareBrackets.lLength && squareBrackets.list_data[squareBrackets.lLength-1] == level && lookAtMe != ']') {
760                 return HandleFormulaParsingError ("Missing or unbalanced '[]' ", parsingContext.errMsg(), s, i);
761             }
762 
763             if (lookAtMe != ',') {
764               if (i != s.length()) {
765                 level--;
766               } else {
767                 if (level != 0L) {
768                   level = -1L;
769                 }
770               }
771             }
772 
773             if (level<0) {
774                 return HandleFormulaParsingError ("Unbalanced '()' parentheses ", parsingContext.errMsg(), s, i);
775             }
776 
777             if (lookAtMe ==',' && (level<1 || (squareBrackets.lLength && squareBrackets.list_data[squareBrackets.lLength-1] == level))) {
778                 return HandleFormulaParsingError ("Parameter list is out of context ", parsingContext.errMsg(), s, i);
779             }
780 
781             if (levelOps->lLength) { // there are some buffered operations left
782                 if (levelOps->lLength > 3 || levelData->lLength > 2) {
783                     return HandleFormulaParsingError ("Syntax error ", parsingContext.errMsg(), s, i);
784                 }
785 
786                 for (unsigned long i = 0UL; i<levelData->countitems(); i++) {
787                     f->PushTerm (levelData->GetItem (i));
788                 }
789 
790                 for (long k = levelOps->countitems()-1L; k>=0; k--) {
791                     f->PushTerm (levelOps->GetItem(k));
792                 }
793 
794                 levelOps->Clear();
795             } else {
796                 if (levelData->lLength>1) {
797                     return HandleFormulaParsingError ("Syntax error ", parsingContext.errMsg(), s, i);
798                 } else if (levelData->lLength) {
799                   //f->theFormula << (*levelData)(0);    // mod 07072006 to not duplicate
800                   f->PushTerm (levelData->GetItem(0));
801                 }
802 
803             }
804 
805             levelData->Clear();
806 
807             if (i<s.length() && lookAtMe !=',' ) {
808                 operations.Delete (level+1);
809                 operands.Delete   (level+1);
810                 functionCallTags.Pop();
811 
812                 levelOps          = (_List*)operations(level);
813                 levelData         = (_List*)operands(level);
814 
815                 long function_call_pop = functionCallTags.Element (-1);
816 
817                 if (function_call_pop >= 0) {
818                   if (levelData->lLength == 0L && levelOps->lLength == 1L) {
819                     long argument_count = f->StackDepth(function_call_pop);
820 
821                     _Operation* function_call = (_Operation*)levelOps->GetItem(0);
822                     if (function_call->IsHBLFunctionCall()) {
823                       function_call->SetTerms(-argument_count-1L);
824                     } else { // built-in
825                       long op_terms = function_call->GetNoTerms();
826                       if (op_terms < 0) { // variable # of arguments
827                           if (argument_count < -op_terms - 1) {
828                               return HandleFormulaParsingError (_String("Expected a minimum of ") & (-op_terms - 1) & " arguments", parsingContext.errMsg(), s, i);
829                           }
830                       } else {
831                           long max_ops = op_terms >> 16;
832                           if (max_ops > 0) {
833                               long min_ops = op_terms - (max_ops << 16);
834                               if (argument_count < min_ops || argument_count > max_ops) {
835                                   return HandleFormulaParsingError (_String ("Expected between ") & min_ops & " and " & max_ops & " arguments" , parsingContext.errMsg(), s, i);
836                               }
837 
838                           } else { // fixed # of arguments
839                               if (argument_count != op_terms) {
840                                   return HandleFormulaParsingError (_String ("Expected ") & op_terms & " arguments" , parsingContext.errMsg(), s, i);
841                               }
842 
843                           }
844                       }
845 
846                       function_call->SetTerms(argument_count);
847 
848                       // need to check that the number of arguments is allowed for the built-in
849                       //function_call->SetTerms(argument_count);
850                     }
851 
852                     f->PushTerm (function_call);
853 
854                     operations.Delete (level);
855                     operands.Delete   (level);
856                     functionCallTags.Pop();
857 
858                     levelOps          = (_List*)operations(--level);
859                     levelData         = (_List*)operands(level);
860                  } else {
861                     return HandleFormulaParsingError ("Syntax error ", parsingContext.errMsg(), s, i);
862                   }
863                 }
864 
865                 if (lookAtMe !=']')
866                     if ( BinOps.Find(s.get_char(i+1))==-1 && i + 1 <s.length() && s.get_char(i+1)!=')' && s.get_char(i+1)!=']' && s.get_char(i+1)!='[' && HalfOps.Find(s.get_char(i+1))==-1 && s.get_char(i+1)!=',') {
867                         storage = s.get_char(i);
868                         s.set_char(i,'*');
869                     }
870             }
871 
872             if (lookAtMe ==']') {
873                 if (!squareBrackets.lLength || squareBrackets.list_data [squareBrackets.lLength-1] != level + 1) {
874                     return HandleFormulaParsingError ("Unexpected ']' ", parsingContext.errMsg(), s, i);
875                 }
876                 squareBrackets.Delete(squareBrackets.lLength-1);
877                 curOp = *(_String*)BuiltInFunctions(HY_OP_CODE_MACCESS);
878                 if (mergeMAccess.lLength && mergeMAccess.list_data[mergeMAccess.lLength-1] >= 0 && mergeMAccessLevel.list_data[mergeMAccessLevel.lLength-1] == level) {
879                     long mergeIndex              = mergeMAccess.list_data[mergeMAccess.lLength-1];
880                     _Operation * previousMaccess = (_Operation*) f->theFormula (mergeIndex);
881                     if (previousMaccess->GetCode () != curOp) {
882                         return HandleFormulaParsingError ("Internal error in Parse. Incorrect matrix access token code ", parsingContext.errMsg(), s, i);
883                     }
884 
885                     if (previousMaccess->GetNoTerms() > 2) {
886                         mergeMAccess.Delete (mergeMAccess.lLength-1,false);
887                         mergeMAccessLevel.Delete (mergeMAccessLevel.lLength-1,false);
888                         f->theFormula.AppendNewInstance(new _Operation (curOp ,2));
889                     } else {
890                         previousMaccess->SetTerms(3);
891                         mergeMAccess.Delete (mergeMAccess.lLength-1,false);
892                         mergeMAccessLevel.Delete (mergeMAccessLevel.lLength-1,false);
893                         previousMaccess->AddAReference();
894                         f->theFormula.Delete (mergeIndex);
895                         f->theFormula.AppendNewInstance(previousMaccess);
896                     }
897                 } else {
898                     f->theFormula.AppendNewInstance(new _Operation (curOp ,2));
899                 }
900             }
901 
902             if (!storage) {
903                 continue;
904             }
905         }
906 
907 
908         if (s.get_char(i) == '=' && s.get_char(i+1) != '=' && (!twoToken || s.get_char(i-1)==':' || s.get_char (i-1) == '+')) { // assignment operator
909             _String  errMsg;
910 
911             bool check               = !parsingContext.inAssignment(),
912                  is_array_assignment = f->IsArrayAccess() && levelOps->lLength == 0UL;
913 
914 
915             char deref = 0;
916 
917             _Variable *lhs_variable = nil;
918 
919 
920             if (check) {
921                 if (is_array_assignment) {
922                     (((_Operation*)((f->theFormula)(f->theFormula.lLength-1)))->TheCode()) = HY_OP_CODE_MCOORD;
923                 } else {
924                     check = checkLHS (levelOps, levelData, errMsg, deref, f, lhs_variable, parsingContext);
925                 }
926             } else {
927                 errMsg = "Can't assign within another assignment";
928             }
929 
930 
931             if (!check) {
932                 return HandleFormulaParsingError (errMsg, parsingContext.errMsg(), s, i);
933             }
934 
935             parsingContext.inAssignment() = true;
936             _String ss (s,i+1,-1); // this is the RHS
937             _Formula  newF;
938 
939             if (Parse(&newF,ss,parsingContext, f2) != HY_FORMULA_EXPRESSION) {
940                 parsingContext.inAssignment() = false;
941                 return HY_FORMULA_FAILED;
942             }
943             parsingContext.inAssignment() = false;
944             if (!is_array_assignment && lhs_variable)
945                 // normal variable assignment
946             {
947                 if (!f2) { // immediate execution
948                     if (_parserHelperHandleInlineAssignmentCases (s,parsingContext, i, lhs_variable, f,  deref, newF, twoToken) == HY_FORMULA_FAILED) {
949                         return HY_FORMULA_FAILED;
950                     }
951                 } else { // this gets called from ExecuteCase0...
952                     if (twoToken && s.get_char(i-1) == '+') { // += gets handled here
953 
954                         _Operation* self = new _Operation ();
955                         self->SetAVariable(lhs_variable->get_index());
956                         newF.theFormula.InsertElement (self,0,false);
957                         DeleteObject (self);
958                         if (deref != kStringDirectReference) {
959                              _Operation* ref = new _Operation (*(_String*)BuiltInFunctions(deref == kStringGlobalDeference ? HY_OP_CODE_POWER : HY_OP_CODE_MUL),1);
960                              newF.theFormula.InsertElement (ref,1,false);
961                              DeleteObject (ref);
962                       }
963                       newF.theFormula.AppendNewInstance (new _Operation (*(_String*)BuiltInFunctions(HY_OP_CODE_ADD),2));
964                     }
965                     f->Duplicate((_Formula const*)&newF);
966                 }
967 
968                 parsingContext.assignmentRefID()   = lhs_variable->get_index();
969                 parsingContext.assignmentRefType() = deref;
970 
971                 return (s.get_char(i-1)==':')?HY_FORMULA_VARIABLE_FORMULA_ASSIGNMENT:HY_FORMULA_VARIABLE_VALUE_ASSIGNMENT;
972             } else
973                 // matrix/associative array element assignment
974             {
975                 if (is_array_assignment) {
976                     long stackD = -1,
977                          last0  = 0;
978 
979                     for (unsigned long opID = 0; opID < f->theFormula.lLength - 1; opID ++) {
980                         ((_Operation*)f->theFormula(opID)) -> StackDepth (stackD);
981                         if (stackD == 0) {
982                             last0 = opID;
983                         }
984                     }
985 
986                     if (!f2) { // immediate execution
987                         bool       anError = false;
988 
989                         if (newF.IsAConstant() || s.get_char(i-1) !=':') {
990                             HBLObjectRef       currentValue = (HBLObjectRef)newF.Compute();
991                             currentValue->AddAReference();
992                             newF.theFormula.Clear();
993                             newF.theFormula.AppendNewInstance (new _Operation(currentValue));
994                         }
995 
996 
997                         _Matrix          * mmx = nil;
998                         _AssociativeList * mma = nil;
999 
1000                         if (last0 > 0) {
1001                             stackD = f->theFormula.lLength;
1002                             f->theFormula.lLength   = last0+1;
1003                             HBLObjectRef   lvalue      = f->Compute();
1004                             f->theFormula.lLength   = stackD;
1005 
1006                             if (lvalue->ObjectClass () == MATRIX) {
1007                                 mmx = (_Matrix*)lvalue;
1008                             } else if (lvalue->ObjectClass () == ASSOCIATIVE_LIST) {
1009                                 mma = (_AssociativeList*)lvalue;
1010                             }
1011 
1012                             last0++;
1013                         } else {
1014                             _Operation * first_op = f->GetIthTerm(0);
1015 
1016                             _Variable* mmo = first_op->IsAVariable() ? LocateVar(first_op->GetAVariable()):nil;
1017 
1018                             if (mmo) {
1019                               if (mmo->ObjectClass () == MATRIX) {
1020                                 mmx = (_Matrix*)(mmo->GetValue());
1021                                 ((_Operation*)f->theFormula(0))->SetAVariable(-first_op->GetAVariable()-3);
1022                               } else {
1023 
1024                                 if (mmo->ObjectClass () == ASSOCIATIVE_LIST) {
1025                                   mma = (_AssociativeList*)(mmo->GetValue());
1026                                   ((_Operation*)f->theFormula(0))->SetAVariable(first_op->GetAVariable()-3);
1027                                 }
1028                               }
1029                             }
1030                         }
1031 
1032                         if (mmx) {
1033                             _Matrix  *mcoord;
1034                             HBLObjectRef coordMx = f->Compute(last0);
1035 
1036                             if (!coordMx|| coordMx->ObjectClass()!=MATRIX) {
1037                                 anError = true;
1038                             } else {
1039                                 mcoord = (_Matrix*)coordMx;
1040                                 _Constant hC ((*mcoord)[0]),
1041                                           vC ((*mcoord)[1]);
1042 
1043                                 mmx->MStore (&hC, &vC, newF, (twoToken && s.get_char(i-1) =='+')?HY_OP_CODE_ADD:HY_OP_CODE_NONE);
1044                             }
1045                         } else if (mma) {
1046                             HBLObjectRef coordIdx = f->Compute(last0);
1047 
1048                             if (!coordIdx|| coordIdx->ObjectClass() != STRING ) {
1049                                 anError = true;
1050                             } else {
1051                                 mma->MStore (coordIdx, newF.Compute(),true, (twoToken && s.get_char(i-1) =='+')?HY_OP_CODE_ADD:HY_OP_CODE_NONE);
1052                             }
1053                         } else {
1054                             anError = true;
1055                         }
1056 
1057 
1058                         if (anError) {
1059                             return HandleFormulaParsingError ("Invalid matrix/associative list ident supplied ", parsingContext.errMsg(), s, i);
1060                         }
1061 
1062                         return HY_FORMULA_EXPRESSION;
1063                     } else {
1064                         bool isSimple = (s.get_char(i-1) != ':');
1065                         f2->Duplicate   (&newF);
1066                         if (last0 == 0) {
1067                             ((_Operation*)f->theFormula(0))->SetAVariable(-((_Operation*)f->theFormula(0))->GetAVariable()-3);
1068                         }
1069                         return isSimple?((s.get_char(i-1) == '+')?HY_FORMULA_FORMULA_VALUE_INCREMENT:HY_FORMULA_FORMULA_VALUE_ASSIGNMENT):HY_FORMULA_FORMULA_FORMULA_ASSIGNMENT;
1070                     }
1071                 } else {
1072                 // *(expression) reference
1073                     if (f2) {
1074                         bool isSimple = (s.get_char(i-1) != ':');
1075 
1076                         if (twoToken && s.get_char(i-1) == '+') { // += gets handled here
1077                             newF.theFormula.InsertElement (new _Operation (*(_String*)BuiltInFunctions(deref == kStringGlobalDeference ? HY_OP_CODE_POWER : HY_OP_CODE_MUL),1), 0, false);
1078                             for (long lhs_ops = f->theFormula.lLength-1; lhs_ops >= 0; lhs_ops --) {
1079                                 newF.theFormula.InsertElement (f->theFormula(lhs_ops), 0, true);
1080                             }
1081                             newF.theFormula.AppendNewInstance (new _Operation (*(_String*)BuiltInFunctions(HY_OP_CODE_ADD),2));
1082                         }
1083                         f2->Duplicate   (&newF);
1084                         parsingContext.assignmentRefType() = deref;
1085                         return isSimple?HY_FORMULA_REFERENCE_VALUE_ASSIGNMENT:HY_FORMULA_REFERENCE_FORMULA_ASSIGNMENT;
1086 
1087                     } else {
1088                         if (_parserHelperHandleInlineAssignmentCases (s,parsingContext, i, lhs_variable, f,  deref, newF, twoToken) == HY_FORMULA_FAILED) {
1089                             return HY_FORMULA_FAILED;
1090                         }
1091                     }
1092                 }
1093             }
1094         }
1095 
1096         if ( s.get_char(i-1)==':' && (s.get_char(i)=='<' || s.get_char(i)=='>')) { // variable bounds
1097             _Variable * lhs = nil;
1098             _String errMsg;
1099             char    deref;
1100 
1101             if (parsingContext.inAssignment()||f->IsArrayAccess()||! checkLHS (levelOps, levelData, errMsg, deref, f, lhs, parsingContext)) {
1102                return HandleFormulaParsingError ("Can't set bounds like this ", parsingContext.errMsg(), s, i);
1103             }
1104 
1105             parsingContext.inAssignment() = true;
1106 
1107             _String ss (s,i+1,-1);
1108             _Formula newF;
1109 
1110             if (Parse(&newF,ss,parsingContext,f2) != HY_FORMULA_EXPRESSION) {
1111                 parsingContext.inAssignment() = false;
1112                 return HY_FORMULA_FAILED;
1113             }
1114 
1115 
1116             parsingContext.inAssignment() = false;
1117 
1118 
1119 
1120             if (lhs) {
1121                 if (!f2) {
1122                     if (_parserHelperHandleInlineBoundCases (s,parsingContext,i,lhs,f, deref, newF) == HY_FORMULA_FAILED) {
1123                         return HY_FORMULA_FAILED;
1124                     }
1125                 } else { // BOUND ASSIGNMENTS
1126                     f2->Duplicate   (&newF);
1127 
1128                     parsingContext.assignmentRefID()   = lhs->get_index();
1129                     parsingContext.assignmentRefType() = deref;
1130 
1131                     return (s.get_char(i)=='>')?HY_FORMULA_VARIABLE_UPPER_BOUND_ASSIGNMENT:HY_FORMULA_VARIABLE_LOWER_BOUND_ASSIGNMENT;
1132                 }
1133             } else {
1134                 if (!f2) {
1135                     if (_parserHelperHandleInlineBoundCases (s,parsingContext,i,lhs,f, deref, newF) == HY_FORMULA_FAILED) {
1136                         return HY_FORMULA_FAILED;
1137                     }
1138                 } else { // BOUND ASSIGNMENTS
1139                     f2->Duplicate   (&newF);
1140                     parsingContext.assignmentRefType() = deref;
1141                     return (s.get_char(i)=='>')?HY_FORMULA_REFERENCE_UPPER_BOUND_ASSIGNMENT:HY_FORMULA_REFERENCE_LOWER_BOUND_ASSIGNMENT;
1142                 }
1143 
1144             }
1145 
1146             return HY_FORMULA_EXPRESSION;
1147         }
1148 
1149 
1150         if (s.get_char(i) == '{') // a matrix
1151             /* 20090803 SLKP:
1152                  fixed the code to deal with
1153             */
1154         {
1155 
1156             parsingContext.isVolatile() = true;
1157 
1158             int     j       = s.ExtractEnclosedExpression (i,'{','}',fExtractRespectQuote | fExtractRespectEscape);
1159 
1160             if (j<0) {
1161                 return HandleFormulaParsingError ("Poorly formed matrix/associative array construct ", parsingContext.errMsg(), s, i);
1162             }
1163 
1164             _StringBuffer matrixDef   (s,i,j);
1165             bool has_values = false;
1166 
1167             if (matrixDef.length() == 2UL || (has_values = matrixDef.FindTerminator(1, ":") >= 0L) || matrixDef.FirstNonSpaceIndex(1,-1) + 1 == matrixDef.length()) {
1168                 _AssociativeList *theList = new _AssociativeList ();
1169                 if (has_values) {
1170                     matrixDef.Trim (1,matrixDef.length()-2);
1171                     if (!theList->ParseStringRepresentation (matrixDef,parsingContext)) {
1172                         return HandleFormulaParsingError ("Poorly formed associative array construct ", parsingContext.errMsg(), s, i);
1173                     }
1174                 }
1175 
1176                 levelData->AppendNewInstance (new _Operation (theList));
1177             } else {
1178                 levelData->AppendNewInstance (new _Operation ( new _Matrix (matrixDef,false,parsingContext)));
1179             }
1180 
1181             i = j;
1182             continue;
1183 
1184         }
1185 
1186         if (s.get_char(i) == '[') { // opening [
1187             long  lastCode = -1;
1188 
1189             if (!f->IsEmpty()) {
1190                 lastCode = ((_Operation*)((f->theFormula)(f->theFormula.lLength-1)))->TheCode();
1191             }
1192 
1193             if (lastCode == HY_OP_CODE_MACCESS && s.get_char(i-1) == ']') {
1194                 mergeMAccess << f->theFormula.lLength-1;
1195                 mergeMAccessLevel << level;
1196             } else {
1197                 if (levelData->lLength == 0 && f->IsEmpty()) {
1198                    // try JSON style matrix definition
1199                    int     j       = s.ExtractEnclosedExpression (i,'[',']',fExtractRespectQuote | fExtractRespectEscape);
1200                    _String matrixDef   (s,i,j);
1201                    if (matrixDef.length() >= 2UL) {
1202                        levelData->AppendNewInstance (new _Operation ( new _Matrix (matrixDef,false,parsingContext, true)));
1203                        i = j;
1204                        continue;
1205                    } else {
1206                        return HandleFormulaParsingError ("[..] must be preceded by an object to index ", parsingContext.errMsg(), s, i);
1207                    }
1208                 }
1209                 if (levelData->lLength) {
1210                     //f->theFormula.AppendNewInstance((*levelData)[levelData->lLength-1]);
1211                     f->PushTerm(levelData->GetItem(levelData->lLength-1));
1212                     levelData->Delete(levelData->lLength-1);
1213                 }
1214             }
1215 
1216 
1217             _parse_new_level (level, operations, operands, levelOps, levelData, curOp, functionCallTags);
1218             squareBrackets << level;
1219             continue;
1220         }
1221 
1222 
1223         if (s.get_char(i) == '(') { // opening (
1224           // check to see if this is a function call
1225 
1226           _parse_new_level (level, operations, operands, levelOps, levelData, curOp, functionCallTags);
1227           continue;
1228         }
1229 
1230         if (s.get_char(i)=='"' || s.get_char (i) == '\'') { // a string literal
1231             long j             = 1,
1232                  inPlaceID     = -1;
1233 
1234           char terminator = s.get_char (i);
1235 
1236             _StringBuffer * literal = new _StringBuffer (16UL);
1237             _List * formula_list = nil;
1238 
1239             while (i+j<s.length()) {
1240                 char aChar = s.char_at(i+j);
1241                 if (aChar =='\\') {
1242                     if (i+j+1<s.length()) {
1243                         char char_at_index = s.char_at(i+j+1);
1244                         if (char_at_index=='"' || char_at_index=='`' ||  char_at_index =='\'') {
1245                             j++;
1246                             (*literal)<<s.char_at(i+j++);
1247                         } else {
1248                             (*literal)<<s.char_at(i+j++);
1249                             (*literal)<<s.char_at(i+j++);
1250                         }
1251                     }
1252                     continue;
1253                 }
1254 
1255                 if (aChar == terminator && inPlaceID < 0) {
1256                     break;
1257                 }
1258 
1259 
1260                 if (aChar == '`') {
1261                     if (inPlaceID < 0) {
1262                         inPlaceID = ++j;
1263                     } else if (j == inPlaceID) {
1264                       //return HandleFormulaParsingError ("Attempted to string substitute an empty quotation ", parsingContext.errMsg(), s, i);
1265                       (*literal) << '`';
1266                       inPlaceID = -1L;
1267                       j++;
1268 
1269                     } else {
1270                         _String     inPlaceVID (s,i+inPlaceID,i+j-1);
1271                         _Formula    expressionProcessor;
1272 
1273                         long parse_result = Parse(&expressionProcessor, inPlaceVID, parsingContext, nil);
1274 
1275                         if (parse_result != HY_FORMULA_EXPRESSION) {
1276                           return HandleFormulaParsingError ("Not a valid/simple expression inside `` ", parsingContext.errMsg(), s, i);
1277                         }
1278 
1279 
1280                         if (expressionProcessor.IsConstant(true)) {
1281                           HBLObjectRef constant_literal = expressionProcessor.Compute (0, nil, nil, nil, STRING);
1282                           if (constant_literal) {
1283                             (*literal) << ((_FString*)constant_literal)->get_str();
1284                           }
1285                           else {
1286                             return HandleFormulaParsingError ("Constant expression inside `` did not evaluate to a string ", parsingContext.errMsg(), s, i);
1287                           }
1288                         } else {
1289                           // push this expression down
1290                           if (!formula_list) {
1291                             formula_list = new _List;
1292                           }
1293 
1294                           literal->TrimSpace();
1295                           if (literal->nonempty()) {
1296                             formula_list->AppendNewInstance(new _Operation (new _FString(literal)));
1297                           } else {
1298                             DeleteObject (literal);
1299                           }
1300                           if (formula_list->lLength > 1L) {
1301                             formula_list->AppendNewInstance(new _Operation (*(_String*)BuiltInFunctions(HY_OP_CODE_ADD),2));
1302                           }
1303                           literal = new _StringBuffer (16UL);
1304                           (*formula_list) << expressionProcessor.theFormula;
1305                           if (formula_list->lLength > expressionProcessor.theFormula.lLength) {
1306                             formula_list->AppendNewInstance(new _Operation (*(_String*)BuiltInFunctions(HY_OP_CODE_ADD),2));
1307                           }
1308                         }
1309                         inPlaceID = -1L;
1310                         //parsingContext.isVolatile() = true;
1311                         j++;
1312 
1313 
1314                     }
1315 
1316                 } else {
1317                     if (inPlaceID < 0) {
1318                         (*literal)<<s.get_char(i+j);
1319                     }
1320                     j++;
1321                 }
1322             }
1323 
1324 
1325             literal->TrimSpace();
1326 
1327             if (formula_list) {
1328               if (literal->nonempty()) {
1329                 formula_list->AppendNewInstance(new _Operation (new _FString(literal)));
1330                 formula_list->AppendNewInstance(new _Operation (*(_String*)BuiltInFunctions(HY_OP_CODE_ADD),2));
1331               } else {
1332                 DeleteObject (literal);
1333               }
1334               formula_list->AppendNewInstance(new _Operation (*(_String*)BuiltInFunctions(HY_OP_CODE_MCOORD),1));
1335 
1336               levelData->AppendNewInstance(new _List(*formula_list));
1337               DeleteObject (formula_list);
1338 
1339             } else {
1340               levelData->AppendNewInstance (new _Operation (new _FString(*literal)));
1341               DeleteObject(literal);
1342             }
1343 
1344 
1345             if (inPlaceID >= 0) {
1346               return HandleFormulaParsingError ("Unterminated string substitution (``) inside a literal ", parsingContext.errMsg(), s, i);
1347             }
1348 
1349             i += j;
1350             continue;
1351 
1352         }
1353 
1354         if (alpha.isAllowed [(unsigned char)s.get_char(i)]) { // an identifier
1355             bool takeVarReference = false;
1356 
1357             if (twoToken) {
1358                 char opChar = s.get_char(i-1);
1359                 if (((_String*)BuiltInFunctions(HY_OP_CODE_REF))->Equal(opChar)) {
1360                     takeVarReference = true;
1361                     twoToken = false;
1362                 } else {
1363                     _String thisOp (opChar);
1364                     levelOps->AppendNewInstance (new _Operation (thisOp,1L));
1365                 }
1366             }
1367 
1368             impliedMult = (i && numeric.isAllowed [(unsigned char)s.get_char(i-1)]);
1369 
1370             long j = 1L;
1371             while ( i+j<s.length() ) {
1372                 unsigned char look_ahead = s.get_char(i+j);
1373                 if (alpha.isAllowed [look_ahead]|| numeric.isAllowed [look_ahead] || parsingContext.allowTemplate() == look_ahead) {
1374                     j++;
1375                 } else {
1376                     break;
1377                 }
1378             }
1379 
1380 
1381             curOp =  s.Cut(i,i+j-1L);
1382             i+=j-1L;
1383 
1384             if (curOp == kGlobalToken) {
1385                 if (takeVarReference) {
1386                     return HandleFormulaParsingError (_String("Cannot make a reference from a reserved word ") & kGlobalToken, parsingContext.errMsg(), s, i);
1387                 }
1388                 globalKey = true;
1389                 continue;
1390             }
1391 
1392             bool noneObject = false;
1393             if (curOp == kNoneToken || curOp == kNullToken) {
1394                  if (takeVarReference) {
1395                     return HandleFormulaParsingError (_String("Cannot make a reference from a reserved word ") & kNoneToken, parsingContext.errMsg(), s, i);
1396                 }
1397                 noneObject = true;
1398                 globalKey  = true;
1399             }
1400 
1401             if (UnOps.FindKey(curOp)>=0) { // a standard function
1402                 if (takeVarReference) {
1403                     return HandleFormulaParsingError ("Cannot make a reference from a built-in function", parsingContext.errMsg(), s, i);
1404                 }
1405 
1406                 levelOps->AppendNewInstance (new _Operation (curOp,1));
1407                 continue;
1408             } else { // a variable
1409                 // check if this is a function defined  in the list of "standard functions"
1410                 long bLang = noneObject?-1:FunctionNameList.FindKey (curOp);
1411                 if (bLang>=0) {
1412                     if (takeVarReference) {
1413                         return HandleFormulaParsingError ("Cannot make a reference from a built-in function", parsingContext.errMsg(), s, i);
1414                     }
1415                     // built-in function
1416                     _Operation * built_in_call = new _Operation (curOp,FunctionNameList.GetValue (bLang));
1417                     _parse_new_level (level, operations, operands, levelOps, levelData, curOp, functionCallTags, f->NumberOperations());
1418                     levelOps->AppendNewInstance (built_in_call);
1419                     continue;
1420                 }
1421 
1422                 // check if this is a function defined in the batch language
1423 
1424                 if ((bLang =  noneObject?-1:hyphy_global_objects::FindBFFunctionName (curOp, parsingContext.formulaScope()))>=0) {
1425                     if (takeVarReference) {
1426                         return HandleFormulaParsingError ("Cannot make a reference from user-defined function", parsingContext.errMsg(), s, i);
1427                     }
1428                     // HBL function
1429                     _Operation * hbl_call = new _Operation (curOp,-bLang-1);
1430                     _parse_new_level (level, operations, operands, levelOps, levelData, curOp, functionCallTags, f->NumberOperations());
1431                     levelOps->AppendNewInstance (hbl_call);
1432                     continue;
1433                 }
1434 
1435                 long curOpl = curOp.length();
1436                 if (curOpl>2 && curOp[curOpl-1]=='_' && curOp[curOpl-2]=='_') { // instant variable refrence
1437                     _String realVarName (curOp,0,curOpl-3);
1438 
1439                     realVarName = parsingContext.contextualizeRef (realVarName);
1440 
1441 
1442                     long realVarLoc = LocateVarByName (realVarName);
1443                     if (realVarLoc<0) { // bad instant variable reference
1444                         if (! (parsingContext.allowTemplate() && f2)) {
1445                             return HandleFormulaParsingError ("Attempted to evaluate an undeclared variable ", parsingContext.errMsg(), s, i);
1446                         }
1447                     }
1448                     // 20181021 handle deferrals for templates
1449 
1450 
1451                     if (!f2) { // 03/25/2004 ? Confused why the else
1452                         levelData->AppendNewInstance(new _Operation((_MathObject*)FetchVar (realVarLoc)->Compute()->makeDynamic()));
1453                     } else {
1454                         _Operation * variable_op = new _Operation (true, realVarName, globalKey, parsingContext.formulaScope());
1455                         // this will create the variable even if did not exist before
1456                         realVarLoc = variable_op->RetrieveVar()->get_index();
1457                         //if (realVarLoc >= 0) {
1458                         variable_op -> SetTerms(-variableNames.GetXtra (realVarLoc)-1);
1459                         //}
1460                         variable_op -> SetAVariable(-2);
1461                         (*levelData) < variable_op;
1462                     }
1463                 } else {
1464                     if (noneObject)
1465                         levelData->AppendNewInstance (new _Operation (false, curOp));
1466                     else
1467                         if (parsingContext.formulaScope() && _hy_application_globals.Find(&curOp) >= 0) {
1468                             levelData->AppendNewInstance (new _Operation(true, curOp, globalKey, nil, takeVarReference));
1469                         } else {
1470                             levelData->AppendNewInstance (new _Operation(true, curOp, globalKey, parsingContext.formulaScope(), takeVarReference));
1471                         }
1472                 }
1473                 globalKey = false;
1474                 if (impliedMult) {
1475                     storage = s.get_char(i);
1476                     s.set_char(i,((_String*)BuiltInFunctions(HY_OP_CODE_MUL))->get_char(0));
1477                 } else if (s.get_char(i+1)=='(') {
1478                     if (!storage) {
1479                         storage = s.get_char(i);
1480                         s.set_char(i,((_String*)BuiltInFunctions(HY_OP_CODE_MUL))->get_char(0));
1481                     } else {
1482                         curOp = *(_String*)BuiltInFunctions(HY_OP_CODE_MUL);
1483                         levelOps->AppendNewInstance(new _Operation (curOp,2));
1484                     }
1485                 }
1486                 if (!storage) {
1487                     continue;
1488                 }
1489             }
1490         }
1491 
1492         if (numeric.isAllowed [(unsigned char)s.get_char(i)]) {
1493             if (twoToken) {
1494                 _String thisOp (s.get_char(i-1));
1495                 levelOps->AppendNewInstance (new _Operation (thisOp,1L));
1496             }
1497             long j = 1;
1498 
1499             while ( i+j<s.length() && (numeric.isAllowed [(unsigned char)s.get_char(i+j)] || ((s.get_char(i+j)=='-' || s.get_char(i+j)=='+' )&& tolower(s.get_char(i+j-1))=='e')) ) {
1500                 j++;
1501             }
1502 
1503             curOp =  (s.Cut(i,i+j-1));
1504             i+=j-1;
1505             levelData->AppendNewInstance (new _Operation (false, curOp));
1506             if (i + 1 <s.length() && s.get_char(i+1)=='(') {
1507                 storage = s.get_char(i);
1508                 s.set_char(i,((_String*)BuiltInFunctions(HY_OP_CODE_MUL))->get_char(0));
1509             } else {
1510                 continue;
1511             }
1512         }
1513 
1514         if ( BinOps.Find (s.get_char(i)) != -1L || (twoToken&&  _Operation::BinOpCode (s, i) != -1L)) {
1515 
1516             bool look_ahead = _Operation::BinOpCode (s, i+1) != -1L;
1517 
1518             if (!twoToken && look_ahead) {
1519                 twoToken = true;
1520                 continue;
1521             }
1522 
1523             if (twoToken|| look_ahead) {
1524                 if (!twoToken) {
1525                     i++;
1526                 }
1527                 curOp = _String(s.get_char(i-1)) & s.get_char(i);
1528             } else {
1529                 curOp = s.get_char(i);
1530             }
1531 
1532             long twoOrOne = 2;
1533 
1534             if (storage) {
1535                 s.set_char(i,storage);
1536             }
1537 
1538             if (levelData->countitems()==0) {
1539               char check_char = s.get_char(i-curOp.length());
1540                 if (check_char !=')' && storage!=')' && check_char !=']') {
1541                     if (!twoToken && UnOps.FindKey (s.get_char(i)) >= 0) {
1542                         twoOrOne = 1;
1543                     } else {
1544                         return HandleFormulaParsingError ("Bad binary operator placement ", parsingContext.errMsg(), s, i);
1545                     }
1546                 }
1547             }
1548 
1549             twoToken = false;
1550 
1551             if (levelData->countitems()) {
1552                 if (storage) {
1553                     BaseRef newS = (*levelData)(levelData->countitems()-1)->makeDynamic();
1554                     for (unsigned long k = 0; k<levelData->countitems()-1; k++) {
1555                         f->PushTerm (levelData->GetItem (k));
1556                         //f->theFormula << ((*levelData)(k));
1557                     }
1558 
1559                     levelData->Clear();
1560                     levelData->AppendNewInstance (newS);
1561                 } else {
1562                     for (unsigned long k = 0; k<levelData->countitems(); k++) {
1563                         f->PushTerm (levelData->GetItem (k));
1564                         //f->theFormula << ((*levelData)(k));
1565                     }
1566                     levelData->Clear();
1567                 }
1568             }
1569 
1570             if (!levelOps->countitems()) {
1571                 levelOps->AppendNewInstance (new _Operation (curOp,twoOrOne));
1572                 if (terminate_execution) {
1573                     return HY_FORMULA_FAILED;
1574                 }
1575                 continue;
1576             }
1577 
1578             // check operation precedence
1579 
1580             long h,g;
1581             _String prevOp = *((((_Operation*)((*levelOps)(levelOps->countitems()-1)))->GetCode()));
1582 
1583             h = _Operation::BinOpCode (prevOp);
1584             g = _Operation::BinOpCode (curOp);
1585 
1586             if (h >= 0L) {
1587                 h = opPrecedence (h);
1588             }
1589             g = opPrecedence (g);
1590 
1591 
1592            if (g>h && h!=-1) { // store the op, don't do it yet!
1593                 levelOps->AppendNewInstance (new _Operation (curOp,twoOrOne));
1594                 if (terminate_execution) {
1595                     return HY_FORMULA_FAILED;
1596                 }
1597                 continue;
1598             }
1599 
1600             // do the stored operations now
1601 
1602             for (int j = levelOps->countitems()-1; j>=0; j--) {
1603                 _String  sss = (((_Operation*)((*levelOps)(levelOps->countitems()-1)))->GetCode());
1604                 h = _Operation::BinOpCode (sss);
1605                 if (h < 0L) {
1606                     h = 0xFFFF;
1607                 } else {
1608                     h = opPrecedence (h);
1609                 }
1610 
1611                 if (h<g) {
1612                     break;
1613                 }
1614                 f->theFormula << levelOps->GetItem(j);
1615                 levelOps->Delete(levelOps->lLength-1);
1616             }
1617             levelOps->AppendNewInstance (new _Operation (curOp,twoOrOne));
1618             if (terminate_execution) {
1619                 return HY_FORMULA_FAILED;
1620             }
1621             continue;
1622         } else if (UnOps.FindKey (s.get_char(i)) >= 0) {
1623             if ((s.get_char(i)=='-' || s.get_char(i)=='+') && (!i|| s.get_char(i-1)=='(')) { // unary minus or plus
1624                 curOp   = s.get_char(i);
1625                 levelOps->AppendNewInstance (new _Operation (curOp,1));
1626                 continue;
1627             } else {
1628                 if (HalfOps.Find(s.get_char(i)) != kNotFound) {
1629                     twoToken = true;
1630                     continue;
1631                 }
1632                 return HandleFormulaParsingError ("Bad binary operator placement ", parsingContext.errMsg(), s, i);
1633             }
1634         } else {
1635             if (HalfOps.Find(s.get_char(i)) == kNotFound) {
1636                 return HandleFormulaParsingError ("Unexpected symbol ", parsingContext.errMsg(), s, i);
1637             } else {
1638                 twoToken = true;
1639             }
1640 
1641         }
1642     }
1643     return HY_FORMULA_EXPRESSION;
1644 }
1645 //__________________________________________________________________________________
1646 
VerbosityLevel(void)1647 long     VerbosityLevel (void) {
1648     if (force_verbosity_from_cli)  verbosity_level = 10L;
1649     else verbosity_level = hy_env::EnvVariableGetNumber(hy_env::verbosity_level_string, -1.);
1650     return verbosity_level;
1651 }
1652 
1653 
1654 //__________________________________________________________________________________
stashParameter(_String const & name,hyFloat v,bool set)1655 void  stashParameter (_String const& name, hyFloat v, bool set) {
1656     static  hyFloat stash = 0.0;
1657 
1658     long f = LocateVarByName (name);
1659     if (f>=0) {
1660         _Variable *thisV = FetchVar(f);
1661         if (set) {
1662             stash = thisV->Value();
1663             thisV->SetValue (new _Constant (v),false,true,NULL);
1664         } else {
1665             thisV->SetValue (new _Constant (stash), false,true,NULL);
1666         }
1667     } else if (set) {
1668         stash = v;
1669         setParameter (name,v);
1670     }
1671 }
1672 
1673 
1674 //__________________________________________________________________________________
setParameter(_String const & name,hyFloat def,_String * namespc)1675 void  setParameter (_String const & name, hyFloat def, _String* namespc)
1676 {
1677     if (namespc) {
1678         _String namespcd = AppendContainerName(name,namespc);
1679         setParameter (namespcd,def);
1680     } else {
1681         long f = LocateVarByName (name);
1682         if (f<0) {
1683             _Variable cornholio(name);
1684             setParameter (name,def);
1685         } else {
1686             FetchVar(f)->SetValue(new _Constant (def), false,true,NULL);
1687         }
1688     }
1689 }
1690 
1691 //__________________________________________________________________________________
1692 
setParameter(_String const & name,HBLObjectRef def,_String * namespc,bool dup)1693 void  setParameter (_String const& name, HBLObjectRef def, _String* namespc, bool dup)
1694 {
1695     if (namespc) {
1696         _String namespcd = AppendContainerName(name,namespc);
1697         setParameter (namespcd,def,nil, dup);
1698     } else {
1699         long f = LocateVarByName (name);
1700         if (f<0) {
1701             _Variable cornholio(name);
1702             setParameter (name,def,nil, dup);
1703         } else {
1704             FetchVar(f)->SetValue(def,dup,true,NULL);
1705         }
1706     }
1707 }
1708 
1709 //__________________________________________________________________________________
1710 
ExportIndVariables(_StringBuffer & glVars,_StringBuffer & locVars,_SimpleList * indepVarList)1711 void ExportIndVariables (_StringBuffer& glVars, _StringBuffer& locVars, _SimpleList* indepVarList)
1712 {
1713     _StringBuffer * stIn;
1714     _String str;
1715 
1716     for (unsigned long   i=0; i<indepVarList->lLength; i++) {
1717         _Variable *thisVar = LocateVar(indepVarList->list_data[i]);
1718         if (thisVar->IsGlobal()) {
1719             str = _String ("\nglobal ") & *thisVar->GetName() & '=' & _String((_String*)parameterToString(thisVar->Compute()->Value())) & ';';
1720             stIn = &glVars;
1721         } else {
1722             str = _String ("\n") & *thisVar->GetName() & '=' & _String((_String*)parameterToString(thisVar->Compute()->Value())) & ';';
1723             stIn = &locVars;
1724         }
1725         *stIn << str;
1726         if (!CheckEqual(thisVar->GetLowerBound(),DEFAULTPARAMETERLBOUND)) {
1727             str = _String ("\n") & *thisVar->GetName() & ":>" & _String((_String*)parameterToString(thisVar->GetLowerBound())) & ';';
1728             *stIn << str;
1729         }
1730         if (!CheckEqual(thisVar->GetUpperBound(),DEFAULTPARAMETERUBOUND)) {
1731             str = _String ("\n") & *thisVar->GetName() & ":<" & _String((_String*)parameterToString(thisVar->GetUpperBound())) & ';';
1732             *stIn << str;
1733         }
1734     }
1735 }
1736 
1737 //__________________________________________________________________________________
1738 
ExportDepVariables(_StringBuffer & glVars,_StringBuffer & locVars,_SimpleList * depVarList)1739 void ExportDepVariables (_StringBuffer& glVars, _StringBuffer& locVars, _SimpleList* depVarList)
1740 {
1741     if (depVarList->lLength) {
1742         _StringBuffer * stIn;
1743         _String str;
1744 
1745       /* first we have to reorder global variables, so that dependent global variables which depend
1746            on other dependent global variables are written afterwards (lest they be implicitly declared
1747            as local).
1748            The algorithm is very ugly, but since there are only a few global dependent variables (in general...) */
1749 
1750         _SimpleList     _globalVariablesList,
1751                         lfDepGlobs,
1752                         tl1;
1753 
1754         _List           dependancyLists;
1755         {
1756             for (unsigned long i=0; i<depVarList->lLength; i++)
1757                 if (LocateVar(depVarList->list_data[i])->IsGlobal()) {
1758                     lfDepGlobs << depVarList->list_data[i];
1759                 }
1760         }
1761         lfDepGlobs.Sort();
1762 
1763         for (unsigned long i=0; i<depVarList->lLength; i++) {
1764             _Variable * thisVar = LocateVar(depVarList->list_data[i]);
1765             if (thisVar->IsGlobal()) {
1766                 _SimpleList                 globDependancyList,
1767                                             prunedList;
1768 
1769                 _AVLList                    globDependancyListAVL (&globDependancyList);
1770 
1771                 thisVar->ScanForVariables (globDependancyListAVL,true);
1772 
1773                 globDependancyListAVL.ReorderList ();
1774 
1775                 prunedList.Intersect (globDependancyList,lfDepGlobs);
1776 
1777                 if (prunedList.lLength) {
1778                     _globalVariablesList << i;
1779                     dependancyLists && & prunedList;
1780                     continue;
1781                 }
1782                 str = _String("\nglobal ") & *thisVar->GetName();
1783                 stIn = &glVars;
1784             } else {
1785                 str = _String("\n") & *thisVar->GetName();
1786                  stIn = &locVars;
1787             }
1788             (*stIn)<<str;
1789             (*stIn)<<":=";
1790             stIn->AppendNewInstance(thisVar->GetFormulaString(kFormulaStringConversionNormal));
1791             (*stIn)<<';';
1792             if (!CheckEqual(thisVar->GetLowerBound(),DEFAULTPARAMETERLBOUND)) {
1793                 str = _String ("\n") & *thisVar->GetName() & ":>" & _String((_String*)parameterToString(thisVar->GetLowerBound())) & ';';
1794                 (*stIn)<<str;
1795             }
1796             if (!CheckEqual(thisVar->GetUpperBound(),DEFAULTPARAMETERUBOUND)) {
1797                 str = _String ("\n") & *thisVar->GetName() & ":<" & _String((_String*)parameterToString(thisVar->GetUpperBound())) & ';';
1798                 (*stIn)<<str;
1799             }
1800         }
1801 
1802         if (_globalVariablesList.lLength)
1803             // check internal dependancies
1804         {
1805             _SimpleList writeOrder (_globalVariablesList.lLength,0,1),
1806                         indexList  (_globalVariablesList.lLength,0,1);
1807 
1808 
1809             for (unsigned long i2 = 0; i2 < _globalVariablesList.lLength; i2++) {
1810                 long updatedIndex = writeOrder.list_data[i2];
1811                 _SimpleList * depList = (_SimpleList*)dependancyLists(i2);
1812                 for (unsigned long i3 = 0; i3 < depList->lLength; i3 ++) {
1813                     long i4 = _globalVariablesList.Find (depList->list_data[i3]);
1814                     if (i4 >= 0 && updatedIndex < writeOrder.list_data[i4]) {
1815                         updatedIndex = writeOrder.list_data[i4] + 1;
1816                     }
1817                 }
1818                 writeOrder.list_data[i2] = updatedIndex;
1819             }
1820 
1821             SortLists (&writeOrder, &indexList);
1822 
1823             for (unsigned long i=0; i<_globalVariablesList.lLength; i++) {
1824                 _Variable * thisVar = LocateVar(depVarList->list_data[_globalVariablesList.list_data[indexList.list_data[i]]]);
1825                 str = _String("\nglobal ") & *thisVar->GetName();
1826                 glVars<<str;
1827                 glVars<<":=";
1828                 glVars<< thisVar->GetFormulaString(kFormulaStringConversionNormal);
1829                 glVars<<';';
1830                 if (!CheckEqual(thisVar->GetLowerBound(),DEFAULTPARAMETERLBOUND)) {
1831                     str = _String ("\n") & *thisVar->GetName() & ":>" & _String((_String*)parameterToString(thisVar->GetLowerBound())) & ';';
1832                     glVars<<str;
1833                 }
1834                 if (!CheckEqual(thisVar->GetUpperBound(),DEFAULTPARAMETERUBOUND)) {
1835                     str = _String ("\n") & *thisVar->GetName() & ":<" & _String((_String*)parameterToString(thisVar->GetUpperBound())) & ';';
1836                     glVars<<str;
1837                 }
1838             }
1839         }
1840     }
1841 }
1842 
1843 //__________________________________________________________________________________
1844 
ExportCatVariables(_StringBuffer & rec,_SimpleList * catVarList)1845 void ExportCatVariables (_StringBuffer & rec, _SimpleList* catVarList) {
1846     _SimpleList     nonInd;
1847 
1848     for (long idx = 0; idx < catVarList->lLength; idx++)
1849         if (((_CategoryVariable*)LocateVar(catVarList->list_data[idx]))->IsUncorrelated()) {
1850             ((_CategoryVariable*)LocateVar(catVarList->list_data[idx]))->SerializeCategory (rec);
1851         } else {
1852             nonInd << idx;
1853         }
1854     {
1855         for (long idx = 0; idx < nonInd.lLength; idx++) {
1856             ((_CategoryVariable*)LocateVar(catVarList->list_data[nonInd.list_data[idx]]))->SerializeCategory (rec);
1857         }
1858     }
1859 }
1860 
1861 //__________________________________________________________________________________
1862 
SplitVariablesIntoClasses(_SimpleList & all,_SimpleList & i,_SimpleList & d,_SimpleList & c)1863 void SplitVariablesIntoClasses (_SimpleList& all, _SimpleList& i, _SimpleList& d, _SimpleList& c)
1864 {
1865     for (long idx = 0; idx < all.lLength; idx++) {
1866         _Variable* thisVar = LocateVar (all.list_data[idx]);
1867         if (thisVar->IsCategory()) {
1868             c << all.list_data[idx];
1869         } else if (thisVar->IsIndependent()) {
1870             i << all.list_data[idx];
1871         } else {
1872             d << all.list_data[idx];
1873         }
1874     }
1875 }
1876