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