1 /*
2 Qalculate
3
4 Copyright (C) 2008 Hanna Knutsson (hanna.knutsson@protonmail.com)
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 */
11
12 #include "support.h"
13
14 #include "Function.h"
15 #include "util.h"
16 #include "Calculator.h"
17 #include "MathStructure.h"
18 #include "Variable.h"
19 #include "Number.h"
20 #include "Unit.h"
21 #include "BuiltinFunctions.h"
22
23 #include <limits.h>
24
25 #if HAVE_UNORDERED_MAP
26 # include <unordered_map>
27 using std::unordered_map;
28 #elif defined(__GNUC__)
29 # ifndef __has_include
30 # define __has_include(x) 0
31 # endif
32
33 # if (defined(__clang__) && __has_include(<tr1/unordered_map>)) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 3)
34 # include <tr1/unordered_map>
35 namespace Sgi = std;
36 # define unordered_map std::tr1::unordered_map
37 # else
38 # if __GNUC__ < 3
39 # include <hash_map.h>
40 namespace Sgi { using ::hash_map; }; // inherit globals
41 # else
42 # include <ext/hash_map>
43 # if __GNUC__ == 3 && __GNUC_MINOR__ == 0
44 namespace Sgi = std; // GCC 3.0
45 # else
46 namespace Sgi = ::__gnu_cxx; // GCC 3.1 and later
47 # endif
48 # endif
49 # define unordered_map Sgi::hash_map
50 # endif
51 #else // ... there are other compilers, right?
52 namespace Sgi = std;
53 # define unordered_map Sgi::hash_map
54 #endif
55
56 #include "MathStructure-support.h"
57
58 using std::string;
59 using std::vector;
60 using std::iterator;
61 using std::cout;
62 using std::endl;
63
64 class MathFunction_p {
65 public:
66 unordered_map<size_t, Argument*> argdefs;
67 };
68
MathFunction(string name_,int argc_,int max_argc_,string cat_,string title_,string descr_,bool is_active)69 MathFunction::MathFunction(string name_, int argc_, int max_argc_, string cat_, string title_, string descr_, bool is_active) : ExpressionItem(cat_, name_, title_, descr_, false, true, is_active) {
70 priv = new MathFunction_p;
71 // arc = min number of arguments, max_argc = max arguments (if max_argc=-1, place additional arguments in vector)
72 argc = argc_;
73 if(max_argc_ < 0 || argc < 0) {
74 if(argc < 0) argc = 0;
75 max_argc = -1;
76 } else if(max_argc_ < argc) {
77 max_argc = argc;
78 } else {
79 max_argc = max_argc_;
80 // arguments not required, must have a default value (by default 0)
81 for(int i = 0; i < max_argc - argc; i++) {
82 default_values.push_back("0");
83 }
84 }
85 last_argdef_index = 0;
86 }
MathFunction(const MathFunction * function)87 MathFunction::MathFunction(const MathFunction *function) {
88 priv = new MathFunction_p;
89 set(function);
90 }
MathFunction()91 MathFunction::MathFunction() {
92 priv = new MathFunction_p;
93 argc = 0;
94 max_argc = 0;
95 last_argdef_index = 0;
96 }
~MathFunction()97 MathFunction::~MathFunction() {
98 clearArgumentDefinitions();
99 delete priv;
100 }
101
set(const ExpressionItem * item)102 void MathFunction::set(const ExpressionItem *item) {
103 if(item->type() == TYPE_FUNCTION) {
104 MathFunction *f = (MathFunction*) item;
105 argc = f->minargs();
106 max_argc = f->maxargs();
107 default_values.clear();
108 for(int i = argc + 1; i <= max_argc; i++) {
109 setDefaultValue(i, f->getDefaultValue(i));
110 }
111 last_argdef_index = f->lastArgumentDefinitionIndex();
112 scondition = f->condition();
113 clearArgumentDefinitions();
114 for(size_t i = 1; i <= f->lastArgumentDefinitionIndex(); i++) {
115 if(f->getArgumentDefinition(i)) {
116 setArgumentDefinition(i, f->getArgumentDefinition(i)->copy());
117 }
118 }
119 }
120 ExpressionItem::set(item);
121 }
type() const122 int MathFunction::type() const {
123 return TYPE_FUNCTION;
124 }
subtype() const125 int MathFunction::subtype() const {
126 return SUBTYPE_FUNCTION;
127 }
id() const128 int MathFunction::id() const {
129 return 0;
130 }
131
example(bool raw_format,string name_string) const132 string MathFunction::example(bool raw_format, string name_string) const {
133 // example text
134 if(raw_format) return sexample;
135 string str = sexample;
136 // $name is replaced function name (or provided string)
137 gsub("$name", name_string.empty() ? name() : name_string, str);
138 // adjust decimal and group separators
139 return CALCULATOR->localizeExpression(str);
140 }
setExample(string new_example)141 void MathFunction::setExample(string new_example) {
142 sexample = new_example;
143 }
144
145 /*int MathFunction::countArgOccurence(size_t arg_) {
146 if((int) arg_ > argc && max_argc < 0) {
147 arg_ = argc + 1;
148 }
149 if(argoccs.find(arg_) != argoccs.end()) {
150 return argoccs[arg_];
151 }
152 return 1;
153 }*/
args() const154 int MathFunction::args() const {
155 return max_argc;
156 }
minargs() const157 int MathFunction::minargs() const {
158 return argc;
159 }
maxargs() const160 int MathFunction::maxargs() const {
161 return max_argc;
162 }
condition() const163 string MathFunction::condition() const {
164 return scondition;
165 }
setCondition(string expression)166 void MathFunction::setCondition(string expression) {
167 scondition = expression;
168 remove_blank_ends(scondition);
169 }
testCondition(const MathStructure & vargs)170 bool MathFunction::testCondition(const MathStructure &vargs) {
171 // test condition for arguments
172 if(scondition.empty()) {
173 return true;
174 }
175 // create a temporary function from the condition expression (for handling av arguments)
176 UserFunction test_function("", "CONDITION_TEST_FUNCTION", scondition, false, argc, "", "", max_argc);
177 MathStructure vargs2(vargs);
178 MathStructure mstruct(test_function.MathFunction::calculate(vargs2));
179 EvaluationOptions eo;
180 eo.approximation = APPROXIMATION_APPROXIMATE;
181 mstruct.eval(eo);
182 // check if result is true
183 if(!mstruct.isNumber() || !mstruct.number().getBoolean()) {
184 if(CALCULATOR->showArgumentErrors() && !CALCULATOR->aborted()) {
185 CALCULATOR->error(true, _("%s() requires that %s"), name().c_str(), printCondition().c_str(), NULL);
186 }
187 return false;
188 }
189 return true;
190 }
printCondition()191 string MathFunction::printCondition() {
192 if(scondition.empty()) return scondition;
193 // replace arguments (represented by \x, \y, \z, \a, etc.) with argument definition names
194 string str = scondition;
195 string svar, argstr;
196 Argument *arg;
197 int i_args = maxargs();
198 if(i_args < 0) {
199 i_args = minargs() + 2;
200 }
201 for(int i = 0; i < i_args; i++) {
202 svar = '\\';
203 if(maxargs() < 0 && i >= minargs()) {
204 svar += (char) ('v' + i - minargs());
205 } else {
206 if('x' + i > 'z') {
207 svar += (char) ('a' + i - 3);
208 } else {
209 svar += 'x' + i;
210 }
211 }
212 size_t i2 = 0;
213 while(true) {
214 if((i2 = str.find(svar, i2)) != string::npos) {
215 if(maxargs() < 0 && i > minargs()) {
216 arg = getArgumentDefinition(i);
217 } else {
218 arg = getArgumentDefinition(i + 1);
219 }
220 argstr = "\"";
221 if(!arg || arg->name().empty()) {
222 argstr += _("argument");
223 argstr += " ";
224 if(maxargs() < 0 && i > minargs()) {
225 argstr += i2s(i);
226 } else {
227 argstr += i2s(i + 1);
228 }
229 } else {
230 argstr += arg->name();
231 }
232 argstr += "\"";
233 str.replace(i2, 2, argstr);
234 } else {
235 break;
236 }
237 }
238 }
239 return str;
240 }
args(const string & argstr,MathStructure & vargs,const ParseOptions & parseoptions)241 int MathFunction::args(const string &argstr, MathStructure &vargs, const ParseOptions &parseoptions) {
242 // read arguments from expression (e.g. "52, 2" from expression "sin(52, 2)"); used in Calculator::parse()
243 ParseOptions po = parseoptions;
244 MathStructure *unended_function = po.unended_function;
245 po.unended_function = NULL;
246 vargs.clearVector();
247 int start_pos = 0;
248 bool in_cit1 = false, in_cit2 = false;
249 int pars = 0;
250 int itmp = 0;
251 string str = argstr, stmp;
252 remove_blank_ends(str);
253 Argument *arg;
254 bool last_is_vctr = false, vctr_started = false;
255 if(maxargs() > 0) {
256 arg = getArgumentDefinition(maxargs());
257 // if last argument is vector or maximum number of arguments is 1 and the only argument allows vector
258 last_is_vctr = arg && ((arg->type() == ARGUMENT_TYPE_VECTOR) || (maxargs() == 1 && arg->handlesVector()));
259 }
260 for(size_t str_index = 0; str_index < str.length(); str_index++) {
261 switch(str[str_index]) {
262 // argument does not end within parentheses, brackets or quotes
263 case LEFT_VECTOR_WRAP_CH: {}
264 case LEFT_PARENTHESIS_CH: {
265 if(!in_cit1 && !in_cit2) {
266 pars++;
267 }
268 break;
269 }
270 case RIGHT_VECTOR_WRAP_CH: {}
271 case RIGHT_PARENTHESIS_CH: {
272 if(!in_cit1 && !in_cit2 && pars > 0) {
273 pars--;
274 }
275 break;
276 }
277 case '\"': {
278 if(in_cit1) {
279 in_cit1 = false;
280 } else if(!in_cit2) {
281 in_cit1 = true;
282 }
283 break;
284 }
285 case '\'': {
286 if(in_cit2) {
287 in_cit2 = false;
288 } else if(!in_cit1) {
289 in_cit1 = true;
290 }
291 break;
292 }
293 // argument separator
294 case COMMA_CH: {
295 if(pars == 0 && !in_cit1 && !in_cit2) {
296 itmp++;
297 // read one argument
298 if(itmp <= maxargs() || args() < 0) {
299 // index is <= max number of arguments
300 stmp = str.substr(start_pos, str_index - start_pos);
301 remove_blank_ends(stmp);
302 arg = getArgumentDefinition(itmp);
303 // index is greater than minimum number of arguments,
304 // and maximimum number of arguments is unlimited, use the last argument definition
305 if(!arg && itmp > argc && args() < 0 && itmp > (int) last_argdef_index && (int) last_argdef_index > argc) {
306 arg = priv->argdefs[last_argdef_index];
307 }
308 if(stmp.empty()) {
309 if(arg) {
310 // if index has argument definition, use for parsing
311 MathStructure *mstruct = new MathStructure();
312 arg->parse(mstruct, getDefaultValue(itmp), po);
313 vargs.addChild_nocopy(mstruct);
314 } else {
315 MathStructure *mstruct = new MathStructure();
316 CALCULATOR->parse(mstruct, getDefaultValue(itmp));
317 vargs.addChild_nocopy(mstruct);
318 }
319 } else {
320 if(arg) {
321 MathStructure *mstruct = new MathStructure();
322 arg->parse(mstruct, stmp, po);
323 vargs.addChild_nocopy(mstruct);
324 } else {
325 MathStructure *mstruct = new MathStructure();
326 CALCULATOR->parse(mstruct, stmp, po);
327 vargs.addChild_nocopy(mstruct);
328 }
329 }
330 } else if(last_is_vctr) {
331 // if last argument is a vector, use additional arguments to fill the vector
332 if(!vctr_started) {
333 if(!vargs[vargs.size() - 1].isVector() || vargs[vargs.size() - 1].size() != 1) {
334 vargs[vargs.size() - 1].transform(STRUCT_VECTOR);
335 }
336 vctr_started = true;
337 }
338 stmp = str.substr(start_pos, str_index - start_pos);
339 remove_blank_ends(stmp);
340 if(stmp.empty()) {
341 MathStructure *mstruct = new MathStructure();
342 getArgumentDefinition(maxargs())->parse(mstruct, getDefaultValue(itmp));
343 vargs[vargs.size() - 1].addChild_nocopy(mstruct);
344 } else {
345 MathStructure *mstruct = new MathStructure();
346 getArgumentDefinition(maxargs())->parse(mstruct, stmp, po);
347 vargs[vargs.size() - 1].addChild_nocopy(mstruct);
348 }
349 vargs.childUpdated(vargs.size());
350 } else {
351 CALCULATOR->error(false, _("Additional arguments for function %s() was ignored. Function can only use %s argument(s)."), name().c_str(), i2s(maxargs()).c_str(), NULL);
352 }
353 start_pos = str_index + 1;
354 }
355 break;
356 }
357 }
358 }
359 // generate unended function information
360 // used from Calculator::parse() for display of continuous parsing info
361 // handling is incomplete if used separately
362 if(!str.empty()) {
363 itmp++;
364 po.unended_function = unended_function;
365 if(itmp <= maxargs() || args() < 0) {
366 stmp = str.substr(start_pos, str.length() - start_pos);
367 remove_blank_ends(stmp);
368 arg = getArgumentDefinition(itmp);
369 if(!arg && itmp > argc && args() < 0 && itmp > (int) last_argdef_index && (int) last_argdef_index > argc) {
370 arg = priv->argdefs[last_argdef_index];
371 }
372 if(stmp.empty()) {
373 if(arg) {
374 MathStructure *mstruct = new MathStructure();
375 arg->parse(mstruct, getDefaultValue(itmp));
376 vargs.addChild_nocopy(mstruct);
377 } else {
378 MathStructure *mstruct = new MathStructure();
379 CALCULATOR->parse(mstruct, getDefaultValue(itmp));
380 vargs.addChild_nocopy(mstruct);
381 }
382 } else {
383 if(arg) {
384 MathStructure *mstruct = new MathStructure();
385 arg->parse(mstruct, stmp, po);
386 vargs.addChild_nocopy(mstruct);
387 } else {
388 MathStructure *mstruct = new MathStructure();
389 CALCULATOR->parse(mstruct, stmp, po);
390 vargs.addChild_nocopy(mstruct);
391 }
392 }
393 } else if(last_is_vctr) {
394 if(!vctr_started) {
395 if(!vargs[vargs.size() - 1].isVector() || vargs[vargs.size() - 1].size() != 1) {
396 vargs[vargs.size() - 1].transform(STRUCT_VECTOR);
397 }
398 vctr_started = true;
399 }
400 stmp = str.substr(start_pos, str.length() - start_pos);
401 remove_blank_ends(stmp);
402 if(stmp.empty()) {
403 MathStructure *mstruct = new MathStructure();
404 getArgumentDefinition(maxargs())->parse(mstruct, getDefaultValue(itmp));
405 vargs[vargs.size() - 1].addChild_nocopy(mstruct);
406 } else {
407 MathStructure *mstruct = new MathStructure();
408 getArgumentDefinition(maxargs())->parse(mstruct, stmp, po);
409 vargs[vargs.size() - 1].addChild_nocopy(mstruct);
410 }
411 vargs.childUpdated(vargs.size());
412 } else {
413 CALCULATOR->error(false, _("Additional arguments for function %s() was ignored. Function can only use %s argument(s)."), name().c_str(), i2s(maxargs()).c_str(), NULL);
414 }
415 }
416 if(unended_function && !unended_function->isFunction()) {
417 unended_function->set(vargs);
418 unended_function->setType(STRUCT_FUNCTION);
419 unended_function->setFunction(this);
420 while((int) unended_function->size() < itmp) {
421 unended_function->addChild(m_undefined);
422 }
423 }
424 // append default values
425 if(itmp < maxargs() && itmp >= minargs()) {
426 int itmp2 = itmp;
427 while(itmp2 < maxargs()) {
428 arg = getArgumentDefinition(itmp2 + 1);
429 if(arg) {
430 MathStructure *mstruct = new MathStructure();
431 arg->parse(mstruct, default_values[itmp2 - minargs()]);
432 vargs.addChild_nocopy(mstruct);
433 } else {
434 MathStructure *mstruct = new MathStructure();
435 CALCULATOR->parse(mstruct, default_values[itmp2 - minargs()]);
436 vargs.addChild_nocopy(mstruct);
437 }
438 itmp2++;
439 }
440 }
441 return itmp;
442 }
lastArgumentDefinitionIndex() const443 size_t MathFunction::lastArgumentDefinitionIndex() const {
444 return last_argdef_index;
445 }
getArgumentDefinition(size_t index)446 Argument *MathFunction::getArgumentDefinition(size_t index) {
447 if(priv->argdefs.find(index) != priv->argdefs.end()) {
448 return priv->argdefs[index];
449 }
450 return NULL;
451 }
clearArgumentDefinitions()452 void MathFunction::clearArgumentDefinitions() {
453 for(unordered_map<size_t, Argument*>::iterator it = priv->argdefs.begin(); it != priv->argdefs.end(); ++it) {
454 delete it->second;
455 }
456 priv->argdefs.clear();
457 last_argdef_index = 0;
458 setChanged(true);
459 }
setArgumentDefinition(size_t index,Argument * argdef)460 void MathFunction::setArgumentDefinition(size_t index, Argument *argdef) {
461 if(priv->argdefs.find(index) != priv->argdefs.end()) {
462 delete priv->argdefs[index];
463 }
464 priv->argdefs[index] = argdef;
465 if(index > last_argdef_index) {
466 last_argdef_index = index;
467 }
468 argdef->setIsLastArgument((int) index == maxargs());
469 setChanged(true);
470 }
testArgumentCount(int itmp)471 bool MathFunction::testArgumentCount(int itmp) {
472 if(itmp >= minargs()) {
473 if(itmp > maxargs() && maxargs() >= 0 && (maxargs() > 1 || !getArgumentDefinition(1) || !getArgumentDefinition(1)->handlesVector())) {
474 CALCULATOR->error(false, _("Additional arguments for function %s() was ignored. Function can only use %s argument(s)."), name().c_str(), i2s(maxargs()).c_str(), NULL);
475 }
476 return true;
477 }
478 string str;
479 Argument *arg;
480 bool b = false;
481 for(int i = 1; i <= minargs(); i++) {
482 arg = getArgumentDefinition(i);
483 if(i > 1) {
484 str += CALCULATOR->getComma();
485 str += " ";
486 }
487 if(arg && !arg->name().empty()) {
488 str += arg->name();
489 b = true;
490 } else {
491 str += "?";
492 }
493 }
494 if(b) {
495 CALCULATOR->error(true, _("You need at least %s argument(s) (%s) in function %s()."), i2s(minargs()).c_str(), str.c_str(), name().c_str(), NULL);
496 } else {
497 CALCULATOR->error(true, _("You need at least %s argument(s) in function %s()."), i2s(minargs()).c_str(), name().c_str(), NULL);
498 }
499 return false;
500 }
createFunctionMathStructureFromVArgs(const MathStructure & vargs)501 MathStructure MathFunction::createFunctionMathStructureFromVArgs(const MathStructure &vargs) {
502 MathStructure mstruct(this, NULL);
503 for(size_t i = 0; i < vargs.size(); i++) {
504 mstruct.addChild(vargs[i]);
505 }
506 return mstruct;
507 }
createFunctionMathStructureFromSVArgs(vector<string> & svargs)508 MathStructure MathFunction::createFunctionMathStructureFromSVArgs(vector<string> &svargs) {
509 MathStructure mstruct(this, NULL);
510 for(size_t i = 0; i < svargs.size(); i++) {
511 mstruct.addChild(svargs[i]);
512 }
513 return mstruct;
514 }
calculate(const string & argv,const EvaluationOptions & eo)515 MathStructure MathFunction::calculate(const string &argv, const EvaluationOptions &eo) {
516 /* MathStructure vargs;
517 args(argv, vargs, eo.parse_options);
518 return calculate(vargs, eo);*/
519 MathStructure fmstruct(parse(argv, eo.parse_options));
520 fmstruct.calculateFunctions(eo);
521 return fmstruct;
522 }
parse(const string & argv,const ParseOptions & po)523 MathStructure MathFunction::parse(const string &argv, const ParseOptions &po) {
524 MathStructure vargs;
525 args(argv, vargs, po);
526 vargs.setType(STRUCT_FUNCTION);
527 vargs.setFunction(this);
528 return vargs;
529 //return createFunctionMathStructureFromVArgs(vargs);
530 }
parse(MathStructure & mstruct,const string & argv,const ParseOptions & po)531 int MathFunction::parse(MathStructure &mstruct, const string &argv, const ParseOptions &po) {
532 int n = args(argv, mstruct, po);
533 mstruct.setType(STRUCT_FUNCTION);
534 mstruct.setFunction(this);
535 return n;
536 }
testArguments(MathStructure & vargs)537 bool MathFunction::testArguments(MathStructure &vargs) {
538 size_t last = 0;
539 for(unordered_map<size_t, Argument*>::iterator it = priv->argdefs.begin(); it != priv->argdefs.end(); ++it) {
540 if(it->first > last) {
541 last = it->first;
542 }
543 if(it->second && it->first > 0 && it->first <= vargs.size()) {
544 // for symbols arguments with zero or undefined value, search the first argument for a symbol
545 if(it->second->type() == ARGUMENT_TYPE_SYMBOLIC && (vargs[it->first - 1].isZero() || vargs[it->first - 1].isUndefined())) {
546 vargs[it->first - 1] = vargs[0].find_x_var();
547 if(vargs[it->first - 1].isUndefined() && vargs[0].isVariable() && vargs[0].variable()->isKnown()) vargs[it->first - 1] = ((KnownVariable*) vargs[0].variable())->get().find_x_var();
548 if(vargs[it->first - 1].isUndefined()) {
549 CALCULATOR->beginTemporaryStopMessages();
550 MathStructure mtest(vargs[0]);
551 mtest.eval();
552 vargs[it->first - 1] = mtest.find_x_var();
553 CALCULATOR->endTemporaryStopMessages();
554 }
555 if(vargs[it->first - 1].isUndefined()) {
556 vargs[it->first - 1].set(CALCULATOR->getVariableById(VARIABLE_ID_X), true);
557 CALCULATOR->error(false, _("No unknown variable/symbol was found."), NULL);
558 }
559 }
560 if(!it->second->test(vargs[it->first - 1], it->first, this)) return false;
561 }
562 }
563 if(max_argc < 0 && (int) last > argc && priv->argdefs.find(last) != priv->argdefs.end()) {
564 for(size_t i = last + 1; i <= vargs.size(); i++) {
565 if(!priv->argdefs[last]->test(vargs[i - 1], i, this)) {
566 return false;
567 }
568 }
569 }
570 return testCondition(vargs);
571 }
calculate(MathStructure & vargs,const EvaluationOptions & eo)572 MathStructure MathFunction::calculate(MathStructure &vargs, const EvaluationOptions &eo) {
573 int itmp = vargs.size();
574 if(testArgumentCount(itmp)) {
575 appendDefaultValues(vargs);
576 MathStructure mstruct;
577 int ret = 0;
578 if(!testArguments(vargs) || (ret = calculate(mstruct, vargs, eo)) < 1) {
579 if(ret < 0) {
580 ret = -ret;
581 if(maxargs() > 0 && ret > maxargs()) {
582 if(mstruct.isVector()) {
583 for(size_t arg_i = 0; arg_i < vargs.size() && arg_i < mstruct.size(); arg_i++) {
584 vargs.setChild(mstruct[arg_i], arg_i + 1);
585 }
586 }
587 } else if(ret <= (int) vargs.size()) {
588 vargs.setChild(mstruct, ret);
589 }
590 }
591 return createFunctionMathStructureFromVArgs(vargs);
592 }
593 if(precision() >= 0 && (precision() < mstruct.precision() || mstruct.precision() < 1)) mstruct.setPrecision(precision(), true);
594 if(isApproximate()) mstruct.setApproximate(true, true);
595 return mstruct;
596 } else {
597 return createFunctionMathStructureFromVArgs(vargs);
598 }
599 }
calculate(MathStructure &,const MathStructure &,const EvaluationOptions &)600 int MathFunction::calculate(MathStructure&, const MathStructure&, const EvaluationOptions&) {
601 //mstruct = createFunctionMathStructureFromVArgs(vargs);
602 return 0;
603 }
setDefaultValue(size_t arg_,string value_)604 void MathFunction::setDefaultValue(size_t arg_, string value_) {
605 if((int) arg_ > argc && (int) arg_ <= max_argc && (int) default_values.size() >= (int) arg_ - argc) {
606 default_values[arg_ - argc - 1] = value_;
607 }
608 }
getDefaultValue(size_t arg_) const609 const string &MathFunction::getDefaultValue(size_t arg_) const {
610 if((int) arg_ > argc && (int) arg_ <= max_argc && (int) default_values.size() >= (int) arg_ - argc) {
611 return default_values[arg_ - argc - 1];
612 }
613 return empty_string;
614 }
appendDefaultValues(MathStructure & vargs)615 void MathFunction::appendDefaultValues(MathStructure &vargs) {
616 if((int) vargs.size() < minargs()) return;
617 while((int) vargs.size() < maxargs()) {
618 Argument *arg = getArgumentDefinition(vargs.size() + 1);
619 if(arg) {
620 MathStructure *mstruct = new MathStructure();
621 arg->parse(mstruct, default_values[vargs.size() - minargs()]);
622 vargs.addChild_nocopy(mstruct);
623 } else {
624 MathStructure *mstruct = new MathStructure();
625 CALCULATOR->parse(mstruct, default_values[vargs.size() - minargs()]);
626 vargs.addChild_nocopy(mstruct);
627 }
628 }
629 }
stringArgs(const string & argstr,vector<string> & svargs)630 int MathFunction::stringArgs(const string &argstr, vector<string> &svargs) {
631 svargs.clear();
632 int start_pos = 0;
633 bool in_cit1 = false, in_cit2 = false;
634 int pars = 0;
635 int itmp = 0;
636 string str = argstr, stmp;
637 remove_blank_ends(str);
638 for(size_t str_index = 0; str_index < str.length(); str_index++) {
639 switch(str[str_index]) {
640 case LEFT_PARENTHESIS_CH: {
641 if(!in_cit1 && !in_cit2) {
642 pars++;
643 }
644 break;
645 }
646 case RIGHT_PARENTHESIS_CH: {
647 if(!in_cit1 && !in_cit2 && pars > 0) {
648 pars--;
649 }
650 break;
651 }
652 case '\"': {
653 if(in_cit1) {
654 in_cit1 = false;
655 } else if(!in_cit2) {
656 in_cit1 = true;
657 }
658 break;
659 }
660 case '\'': {
661 if(in_cit2) {
662 in_cit2 = false;
663 } else if(!in_cit1) {
664 in_cit1 = true;
665 }
666 break;
667 }
668 case COMMA_CH: {
669 if(pars == 0 && !in_cit1 && !in_cit2) {
670 itmp++;
671 if(itmp <= maxargs() || args() < 0) {
672 stmp = str.substr(start_pos, str_index - start_pos);
673 remove_blank_ends(stmp);
674 remove_parenthesis(stmp);
675 remove_blank_ends(stmp);
676 if(stmp.empty()) {
677 stmp = getDefaultValue(itmp);
678 }
679 svargs.push_back(stmp);
680 }
681 start_pos = str_index + 1;
682 }
683 break;
684 }
685 }
686 }
687 if(!str.empty()) {
688 itmp++;
689 if(itmp <= maxargs() || args() < 0) {
690 stmp = str.substr(start_pos, str.length() - start_pos);
691 remove_blank_ends(stmp);
692 remove_parenthesis(stmp);
693 remove_blank_ends(stmp);
694 if(stmp.empty()) {
695 stmp = getDefaultValue(itmp);
696 }
697 svargs.push_back(stmp);
698 }
699 }
700 if(itmp < maxargs() && itmp >= minargs()) {
701 int itmp2 = itmp;
702 while(itmp2 < maxargs()) {
703 svargs.push_back(default_values[itmp2 - minargs()]);
704 itmp2++;
705 }
706 }
707 return itmp;
708 }
709
produceVector(const MathStructure & vargs,int begin,int end)710 MathStructure MathFunction::produceVector(const MathStructure &vargs, int begin, int end) {
711 if(begin < 1) {
712 begin = minargs() + 1;
713 if(begin < 1) begin = 1;
714 }
715 if(end < 1 || end >= (int) vargs.size()) {
716 end = vargs.size();
717 }
718 if(begin == 1 && vargs.size() == 1) {
719 if(vargs[0].isVector()) {
720 return vargs[0];
721 } else {
722 return vargs;
723 }
724 }
725 MathStructure mstruct;
726 vargs.getRange(begin, end, mstruct);
727 MathStructure mstruct2;
728 return mstruct.flattenVector(mstruct2);
729 }
produceArgumentsVector(const MathStructure & vargs,int begin,int end)730 MathStructure MathFunction::produceArgumentsVector(const MathStructure &vargs, int begin, int end) {
731 if(begin < 1) {
732 begin = minargs() + 1;
733 if(begin < 1) begin = 1;
734 }
735 if(end < 1 || end >= (int) vargs.size()) {
736 end = vargs.size();
737 }
738 if(begin == 1 && vargs.size() == 1) {
739 return vargs;
740 }
741 MathStructure mstruct;
742 return vargs.getRange(begin, end, mstruct);
743 }
representsPositive(const MathStructure &,bool) const744 bool MathFunction::representsPositive(const MathStructure&, bool) const {return false;}
representsNegative(const MathStructure &,bool) const745 bool MathFunction::representsNegative(const MathStructure&, bool) const {return false;}
representsNonNegative(const MathStructure & vargs,bool allow_units) const746 bool MathFunction::representsNonNegative(const MathStructure &vargs, bool allow_units) const {return representsPositive(vargs, allow_units);}
representsNonPositive(const MathStructure & vargs,bool allow_units) const747 bool MathFunction::representsNonPositive(const MathStructure &vargs, bool allow_units) const {return representsNegative(vargs, allow_units);}
representsInteger(const MathStructure & vargs,bool allow_units) const748 bool MathFunction::representsInteger(const MathStructure &vargs, bool allow_units) const {return representsBoolean(vargs) || representsEven(vargs, allow_units) || representsOdd(vargs, allow_units);}
representsNumber(const MathStructure & vargs,bool allow_units) const749 bool MathFunction::representsNumber(const MathStructure &vargs, bool allow_units) const {return representsReal(vargs, allow_units) || representsComplex(vargs, allow_units);}
representsRational(const MathStructure & vargs,bool allow_units) const750 bool MathFunction::representsRational(const MathStructure &vargs, bool allow_units) const {return representsInteger(vargs, allow_units);}
representsNonComplex(const MathStructure & vargs,bool allow_units) const751 bool MathFunction::representsNonComplex(const MathStructure &vargs, bool allow_units) const {return representsReal(vargs, allow_units);}
representsReal(const MathStructure & vargs,bool allow_units) const752 bool MathFunction::representsReal(const MathStructure &vargs, bool allow_units) const {return representsRational(vargs, allow_units);}
representsComplex(const MathStructure &,bool) const753 bool MathFunction::representsComplex(const MathStructure&, bool) const {return false;}
representsNonZero(const MathStructure & vargs,bool allow_units) const754 bool MathFunction::representsNonZero(const MathStructure &vargs, bool allow_units) const {return representsPositive(vargs, allow_units) || representsNegative(vargs, allow_units);}
representsEven(const MathStructure &,bool) const755 bool MathFunction::representsEven(const MathStructure&, bool) const {return false;}
representsOdd(const MathStructure &,bool) const756 bool MathFunction::representsOdd(const MathStructure&, bool) const {return false;}
representsUndefined(const MathStructure &) const757 bool MathFunction::representsUndefined(const MathStructure&) const {return false;}
representsBoolean(const MathStructure &) const758 bool MathFunction::representsBoolean(const MathStructure&) const {return false;}
representsNonMatrix(const MathStructure & vargs) const759 bool MathFunction::representsNonMatrix(const MathStructure &vargs) const {
760 return representsNumber(vargs, true);
761 }
representsScalar(const MathStructure & vargs) const762 bool MathFunction::representsScalar(const MathStructure &vargs) const {
763 return representsNonMatrix(vargs);
764 }
765
UserFunction(string cat_,string name_,string formula_,bool is_local,int argc_,string title_,string descr_,int max_argc_,bool is_active)766 UserFunction::UserFunction(string cat_, string name_, string formula_, bool is_local, int argc_, string title_, string descr_, int max_argc_, bool is_active) : MathFunction(name_, argc_, max_argc_, cat_, title_, descr_, is_active) {
767 b_local = is_local;
768 b_builtin = false;
769 setFormula(formula_, argc_, max_argc_);
770 setChanged(false);
771 }
UserFunction(const UserFunction * function)772 UserFunction::UserFunction(const UserFunction *function) {
773 set(function);
774 }
formula() const775 string UserFunction::formula() const {
776 return sformula;
777 }
internalFormula() const778 string UserFunction::internalFormula() const {
779 return sformula_calc;
780 }
copy() const781 ExpressionItem *UserFunction::copy() const {
782 return new UserFunction(this);
783 }
set(const ExpressionItem * item)784 void UserFunction::set(const ExpressionItem *item) {
785 if(item->type() == TYPE_FUNCTION && item->subtype() == SUBTYPE_USER_FUNCTION) {
786 sformula = ((UserFunction*) item)->formula();
787 sformula_calc = ((UserFunction*) item)->internalFormula();
788 v_subs.clear();
789 v_precalculate.clear();
790 for(size_t i = 1; i <= ((UserFunction*) item)->countSubfunctions(); i++) {
791 v_subs.push_back(((UserFunction*) item)->getSubfunction(i));
792 v_precalculate.push_back(((UserFunction*) item)->subfunctionPrecalculated(i));
793 }
794 }
795 MathFunction::set(item);
796 }
subtype() const797 int UserFunction::subtype() const {
798 return SUBTYPE_USER_FUNCTION;
799 }
800 extern string format_and_print(const MathStructure &mstruct);
replace_intervals_f(MathStructure & mstruct)801 bool replace_intervals_f(MathStructure &mstruct) {
802 // replace intervals with temporary variables
803 if(mstruct.isNumber() && (mstruct.number().isInterval(false) || (CALCULATOR->usesIntervalArithmetic() && mstruct.number().precision() >= 0))) {
804 Variable *v = new KnownVariable("", format_and_print(mstruct), mstruct);
805 v->setTitle("\b");
806 mstruct.set(v, true);
807 v->destroy();
808 return true;
809 }
810 bool b = false;
811 for(size_t i = 0; i < mstruct.size(); i++) {
812 if(replace_intervals_f(mstruct[i])) {
813 mstruct.childUpdated(i + 1);
814 b = true;
815 }
816 }
817 return b;
818 }
replace_f_interval(MathStructure & mstruct,const EvaluationOptions & eo)819 bool replace_f_interval(MathStructure &mstruct, const EvaluationOptions &eo) {
820 // replace interval() and uncertainty() with numbers with intervals, if possible
821 if(mstruct.isFunction() && mstruct.function()->id() == FUNCTION_ID_INTERVAL && mstruct.size() == 2) {
822 if(mstruct[0].isNumber() && mstruct[1].isNumber()) {
823 Number nr;
824 if(nr.setInterval(mstruct[0].number(), mstruct[1].number())) {
825 mstruct.set(nr, true);
826 return true;
827 }
828 } else {
829 MathStructure m1(mstruct[0]);
830 MathStructure m2(mstruct[1]);
831 if(create_interval(mstruct, m1, m2)) return true;
832 m1.eval(eo);
833 m2.eval(eo);
834 if(create_interval(mstruct, m1, m2)) return true;
835 }
836 return false;
837 } else if(eo.interval_calculation != INTERVAL_CALCULATION_NONE && mstruct.isFunction() && mstruct.function()->id() == FUNCTION_ID_UNCERTAINTY && mstruct.size() == 3) {
838 if(mstruct[0].isNumber() && mstruct[1].isNumber()) {
839 Number nr(mstruct[0].number());
840 if(mstruct[2].number().getBoolean()) {
841 nr.setRelativeUncertainty(mstruct[1].number(), false);
842 } else {
843 nr.setUncertainty(mstruct[1].number(), false);
844 }
845 mstruct.set(nr, true);
846 return true;
847 } else {
848 MathStructure m1(mstruct[0]);
849 MathStructure m2(mstruct[1]);
850 if(mstruct[2].number().getBoolean()) {
851 m1.eval(eo);
852 m2.eval(eo);
853 if(m1.isNumber() && m2.isNumber()) {
854 Number nr(m1.number());
855 nr.setRelativeUncertainty(m2.number(), false);
856 mstruct.set(nr, true);
857 return true;
858 }
859 m1 = mstruct[0];
860 m2 = mstruct[1];
861 mstruct.setToChild(1, true);
862 mstruct *= m_one;
863 mstruct.last() -= m2;
864 mstruct.transformById(FUNCTION_ID_INTERVAL);
865 m1 *= m_one;
866 m1.last() += m2;
867 mstruct.addChild(m1);
868 return 1;
869 } else {
870 if(set_uncertainty(m1, m2, eo, false)) return true;
871 m1.eval(eo);
872 m2.eval(eo);
873 if(set_uncertainty(m1, m2, eo, true)) return true;
874 m1 = mstruct[0];
875 m2 = mstruct[1];
876 mstruct.setToChild(1);
877 mstruct -= m2;
878 mstruct.transformById(FUNCTION_ID_INTERVAL);
879 m1 += m2;
880 mstruct.addChild(m1);
881 }
882 replace_f_interval(mstruct, eo);
883 return true;
884
885 }
886 return false;
887 }
888 bool b = false;
889 for(size_t i = 0; i < mstruct.size(); i++) {
890 if(replace_f_interval(mstruct[i], eo)) {
891 mstruct.childUpdated(i + 1);
892 b = true;
893 }
894 }
895 return b;
896 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)897 int UserFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
898 ParseOptions po;
899 if(b_local) po.angle_unit = eo.parse_options.angle_unit;
900 if(args() != 0) {
901 string stmp = sformula_calc;
902 string svar;
903 string v_str, w_str;
904 vector<string> v_strs;
905 vector<size_t> v_id;
906 size_t i2 = 0;
907 int i_args = maxargs();
908 if(i_args < 0) {
909 i_args = minargs();
910 }
911
912 for(int i = 0; i < i_args; i++) {
913 MathStructure *mv = new MathStructure(vargs[i]);
914 Argument *arg = getArgumentDefinition(i + 1);
915 if((!arg || !arg->tests() || arg->type() == ARGUMENT_TYPE_FREE) && mv->containsInterval(true, false, false, 0, true)) {
916 size_t count = 0;
917 for(size_t i3 = 0; i3 < 1 || (maxargs() < 0 && i3 < 3); i3++) {
918 svar = '\\';
919 if(i3 == 1) {
920 svar += 'v';
921 } else if(i3 == 2) {
922 svar += 'w';
923 } else if('x' + i > 'z') {
924 svar += (char) ('a' + i - 3);
925 } else {
926 svar += 'x' + i;
927 }
928 size_t pos = 0;
929 while((pos = sformula_calc.find(svar, pos)) != string::npos) {
930 pos += svar.length();
931 count++;
932 }
933 for(size_t i2 = 0; i2 < v_subs.size(); i2++) {
934 pos = 0;
935 size_t c2 = 0;
936 while((pos = v_subs[i2].find(svar, pos)) != string::npos) {
937 pos += svar.length();
938 c2++;
939 }
940 string svar2 = "\\";
941 svar2 += i2s(i2 + 1);
942 pos = 0;
943 size_t c_sub = 0;
944 while((pos = sformula_calc.find(svar2, pos)) != string::npos) {
945 pos += svar2.length();
946 c_sub++;
947 }
948 count += c2 * c_sub;
949 }
950 }
951 if(count > 1) {
952 replace_f_interval(*mv, eo);
953 replace_intervals_f(*mv);
954 }
955 }
956 v_id.push_back(CALCULATOR->addId(mv, true));
957 v_strs.push_back(LEFT_PARENTHESIS ID_WRAP_LEFT);
958 v_strs[i] += i2s(v_id[i]);
959 v_strs[i] += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
960 }
961 if(maxargs() < 0) {
962 if(stmp.find("\\v") != string::npos) {
963 v_id.push_back(CALCULATOR->addId(new MathStructure(produceVector(vargs)), true));
964 v_str = LEFT_PARENTHESIS ID_WRAP_LEFT;
965 v_str += i2s(v_id[v_id.size() - 1]);
966 v_str += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
967 }
968 if(stmp.find("\\w") != string::npos) {
969 v_id.push_back(CALCULATOR->addId(new MathStructure(produceArgumentsVector(vargs)), true));
970 w_str = LEFT_PARENTHESIS ID_WRAP_LEFT;
971 w_str += i2s(v_id[v_id.size() - 1]);
972 w_str += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
973 }
974 }
975
976 for(size_t i = 0; i < v_subs.size(); i++) {
977 if(subfunctionPrecalculated(i + 1)) {
978 string str = v_subs[i];
979 for(int i3 = 0; i3 < i_args; i3++) {
980 svar = '\\';
981 if('x' + i3 > 'z') {
982 svar += (char) ('a' + i3 - 3);
983 } else {
984 svar += 'x' + i3;
985 }
986 i2 = 0;
987 while(true) {
988 if((i2 = str.find(svar, i2)) != string::npos) {
989 if(i2 != 0 && str[i2 - 1] == '\\') {
990 i2 += 2;
991 } else {
992 str.replace(i2, 2, v_strs[i3]);
993 }
994 } else {
995 break;
996 }
997 }
998 }
999 if(maxargs() < 0) {
1000 i2 = 0;
1001 while(true) {
1002 if((i2 = str.find("\\v")) != string::npos) {
1003 if(i2 != 0 && str[i2 - 1] == '\\') {
1004 i2 += 2;
1005 } else {
1006 str.replace(i2, 2, v_str);
1007 }
1008 } else {
1009 break;
1010 }
1011 }
1012 i2 = 0;
1013 while(true) {
1014 if((i2 = str.find("\\w")) != string::npos) {
1015 if(i2 != 0 && str[i2 - 1] == '\\') {
1016 i2 += 2;
1017 } else {
1018 str.replace(i2, 2, w_str);
1019 }
1020 } else {
1021 break;
1022 }
1023 }
1024 }
1025 MathStructure *v_mstruct = new MathStructure();
1026 CALCULATOR->parse(v_mstruct, str, po);
1027 v_mstruct->eval(eo);
1028 v_id.push_back(CALCULATOR->addId(v_mstruct, true));
1029 str = LEFT_PARENTHESIS ID_WRAP_LEFT;
1030 str += i2s(v_id[v_id.size() - 1]);
1031 str += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
1032 i2 = 0;
1033 svar = '\\';
1034 svar += i2s(i + 1);
1035 while(true) {
1036 if((i2 = stmp.find(svar, i2)) != string::npos) {
1037 if(i2 != 0 && stmp[i2 - 1] == '\\') {
1038 i2 += 2;
1039 } else {
1040 stmp.replace(i2, 2, str);
1041 }
1042 } else {
1043 break;
1044 }
1045 }
1046 } else {
1047 i2 = 0;
1048 svar = '\\';
1049 svar += i2s(i + 1);
1050 while(true) {
1051 if((i2 = stmp.find(svar, i2)) != string::npos) {
1052 if(i2 != 0 && stmp[i2 - 1] == '\\') {
1053 i2 += svar.size();
1054 } else {
1055 stmp.replace(i2, svar.size(), string("(") + v_subs[i] + ")");
1056 }
1057 } else {
1058 break;
1059 }
1060 }
1061 }
1062 }
1063 for(int i = 0; i < i_args; i++) {
1064 svar = '\\';
1065 if('x' + i > 'z') {
1066 svar += (char) ('a' + i - 3);
1067 } else {
1068 svar += 'x' + i;
1069 }
1070 i2 = 0;
1071 while(true) {
1072 if((i2 = stmp.find(svar, i2)) != string::npos) {
1073 if(i2 != 0 && stmp[i2 - 1] == '\\') {
1074 i2 += 2;
1075 } else {
1076 stmp.replace(i2, 2, v_strs[i]);
1077 }
1078 } else {
1079 break;
1080 }
1081 }
1082 }
1083 if(maxargs() < 0) {
1084 i2 = 0;
1085 while(true) {
1086 if((i2 = stmp.find("\\v")) != string::npos) {
1087 if(i2 != 0 && stmp[i2 - 1] == '\\') {
1088 i2 += 2;
1089 } else {
1090 stmp.replace(i2, 2, v_str);
1091 }
1092 } else {
1093 break;
1094 }
1095 }
1096 i2 = 0;
1097 while(true) {
1098 if((i2 = stmp.find("\\w")) != string::npos) {
1099 if(i2 != 0 && stmp[i2 - 1] == '\\') {
1100 i2 += 2;
1101 } else {
1102 stmp.replace(i2, 2, w_str);
1103 }
1104 } else {
1105 break;
1106 }
1107 }
1108 }
1109 while(true) {
1110 if((i2 = stmp.find("\\\\")) != string::npos) {
1111 stmp.replace(i2, 2, "\\");
1112 } else {
1113 break;
1114 }
1115 }
1116 CALCULATOR->parse(&mstruct, stmp, po);
1117 for(size_t i = 0; i < v_id.size(); i++) {
1118 CALCULATOR->delId(v_id[i]);
1119 }
1120 if(precision() >= 0) mstruct.setPrecision(precision(), true);
1121 if(isApproximate()) mstruct.setApproximate(true, true);
1122 } else {
1123 CALCULATOR->parse(&mstruct, sformula_calc, po);
1124 if(precision() >= 0) mstruct.setPrecision(precision(), true);
1125 if(isApproximate()) mstruct.setApproximate(true, true);
1126 }
1127 return 1;
1128 }
setFormula(string new_formula,int argc_,int max_argc_)1129 void UserFunction::setFormula(string new_formula, int argc_, int max_argc_) {
1130 setChanged(true);
1131 sformula = new_formula;
1132 default_values.clear();
1133 if(sformula.empty() && v_subs.empty()) {
1134 sformula_calc = new_formula;
1135 argc = 0;
1136 max_argc = 0;
1137 return;
1138 }
1139 if(argc_ < 0) {
1140 argc_ = 0, max_argc_ = 0;
1141 string svar, svar_o, svar_v;
1142 bool optionals = false, b;
1143 size_t i3 = 0, i4 = 0, i5 = 0;
1144 size_t i2 = 0;
1145 for(int i = 0; i < 26; i++) {
1146 begin_loop_in_set_formula:
1147 i4 = 0; i5 = 0;
1148 svar = '\\';
1149 svar_o = '\\';
1150 if('x' + i > 'z')
1151 svar += (char) ('a' + i - 3);
1152 else
1153 svar += 'x' + i;
1154 if('X' + i > 'Z')
1155 svar_o += (char) ('A' + i - 3);
1156 else
1157 svar_o += 'X' + i;
1158
1159 before_find_in_set_formula:
1160 if(i < 24 && (i2 = new_formula.find(svar_o, i4)) != string::npos) {
1161 if(i2 > 0 && new_formula[i2 - 1] == '\\') {
1162 i4 = i2 + 2;
1163 goto before_find_in_set_formula;
1164 }
1165 i3 = 0;
1166 if(new_formula.length() > i2 + 2 && new_formula[i2 + 2] == ID_WRAP_LEFT_CH) {
1167 if((i3 = new_formula.find(ID_WRAP_RIGHT_CH, i2 + 2)) != string::npos) {
1168 svar_v = new_formula.substr(i2 + 3, i3 - (i2 + 3));
1169 i3 -= i2 + 1;
1170 } else i3 = 0;
1171 }
1172 if(i3) {
1173 default_values.push_back(svar_v);
1174 } else {
1175 default_values.push_back("0");
1176 }
1177 new_formula.replace(i2, 2 + i3, svar);
1178 while((i2 = new_formula.find(svar_o, i2 + 1)) != string::npos) {
1179 if(i2 > 0 && new_formula[i2 - 1] == '\\') {
1180 i2++;
1181 } else {
1182 new_formula.replace(i2, 2, svar);
1183 }
1184 }
1185 for(size_t sub_i = 0; sub_i < v_subs.size(); sub_i++) {
1186 i2 = 0;
1187 while((i2 = v_subs[sub_i].find(svar_o, i2 + 1)) != string::npos) {
1188 if(i2 > 0 && v_subs[sub_i][i2 - 1] == '\\') {
1189 i2++;
1190 } else {
1191 v_subs[sub_i].replace(i2, 2, svar);
1192 }
1193 }
1194 }
1195 optionals = true;
1196 } else if((i2 = new_formula.find(svar, i5)) != string::npos) {
1197 if(i2 > 0 && new_formula[i2 - 1] == '\\') {
1198 i5 = i2 + 2;
1199 goto before_find_in_set_formula;
1200 }
1201 } else {
1202 b = false;
1203 for(size_t sub_i = 0; sub_i < v_subs.size(); sub_i++) {
1204 before_find_in_vsubs_set_formula:
1205 if(i < 24 && (i2 = v_subs[sub_i].find(svar_o, i4)) != string::npos) {
1206 if(i2 > 0 && v_subs[sub_i][i2 - 1] == '\\') {
1207 i4 = i2 + 2;
1208 goto before_find_in_vsubs_set_formula;
1209 }
1210 i3 = 0;
1211 if(v_subs[sub_i].length() > i2 + 2 && v_subs[sub_i][i2 + 2] == ID_WRAP_LEFT_CH) {
1212 if((i3 = v_subs[sub_i].find(ID_WRAP_RIGHT_CH, i2 + 2)) != string::npos) {
1213 svar_v = v_subs[sub_i].substr(i2 + 3, i3 - (i2 + 3));
1214 i3 -= i2 + 1;
1215 } else i3 = 0;
1216 }
1217 if(i3) {
1218 default_values.push_back(svar_v);
1219 } else {
1220 default_values.push_back("0");
1221 }
1222 v_subs[sub_i].replace(i2, 2 + i3, svar);
1223 while((i2 = v_subs[sub_i].find(svar_o, i2 + 1)) != string::npos) {
1224 if(i2 > 0 && v_subs[sub_i][i2 - 1] == '\\') {
1225 i2++;
1226 } else {
1227 v_subs[sub_i].replace(i2, 2, svar);
1228 }
1229 }
1230 optionals = true;
1231 b = true;
1232 } else if((i2 = v_subs[sub_i].find(svar, i5)) != string::npos) {
1233 if(i2 > 0 && v_subs[sub_i][i2 - 1] == '\\') {
1234 i5 = i2 + 2;
1235 goto before_find_in_vsubs_set_formula;
1236 }
1237 b = true;
1238 }
1239 }
1240 if(!b) {
1241 if(i < 24 && !optionals) {
1242 i = 24;
1243 goto begin_loop_in_set_formula;
1244 }
1245 break;
1246 }
1247 }
1248 if(i >= 24) {
1249 max_argc_ = -1;
1250 } else {
1251 if(optionals) {
1252 max_argc_++;
1253 } else {
1254 max_argc_++;
1255 argc_++;
1256 }
1257 }
1258 }
1259 }
1260 if(argc_ > 24) {
1261 argc_ = 24;
1262 }
1263 if(max_argc_ > 24) {
1264 max_argc_ = 24;
1265 }
1266 if(max_argc_ < 0 || argc_ < 0) {
1267 max_argc_ = -1;
1268 if(argc_ < 0) argc_ = 0;
1269 } else if(max_argc_ < argc_) {
1270 max_argc_ = argc_;
1271 }
1272
1273 while((int) default_values.size() < max_argc_ - argc_) {
1274 default_values.push_back("0");
1275 }
1276 if(max_argc_ > 0) default_values.resize(max_argc_ - argc_);
1277 sformula_calc = new_formula;
1278 argc = argc_;
1279 max_argc = max_argc_;
1280 }
addSubfunction(string subfunction,bool precalculate)1281 void UserFunction::addSubfunction(string subfunction, bool precalculate) {
1282 setChanged(true);
1283 v_subs.push_back(subfunction);
1284 v_precalculate.push_back(precalculate);
1285 }
setSubfunction(size_t index,string subfunction)1286 void UserFunction::setSubfunction(size_t index, string subfunction) {
1287 if(index > 0 && index <= v_subs.size()) {
1288 setChanged(true);
1289 v_subs[index - 1] = subfunction;
1290 }
1291 }
delSubfunction(size_t index)1292 void UserFunction::delSubfunction(size_t index) {
1293 if(index > 0 && index <= v_subs.size()) {
1294 setChanged(true);
1295 v_subs.erase(v_subs.begin() + (index - 1));
1296 }
1297 if(index > 0 && index <= v_precalculate.size()) {
1298 setChanged(true);
1299 v_precalculate.erase(v_precalculate.begin() + (index - 1));
1300 }
1301 }
clearSubfunctions()1302 void UserFunction::clearSubfunctions() {
1303 setChanged(true);
1304 v_subs.clear();
1305 v_precalculate.clear();
1306 }
setSubfunctionPrecalculated(size_t index,bool precalculate)1307 void UserFunction::setSubfunctionPrecalculated(size_t index, bool precalculate) {
1308 if(index > 0 && index <= v_precalculate.size()) {
1309 setChanged(true);
1310 v_precalculate[index - 1] = precalculate;
1311 }
1312 }
countSubfunctions() const1313 size_t UserFunction::countSubfunctions() const {
1314 return v_subs.size();
1315 }
getSubfunction(size_t index) const1316 const string &UserFunction::getSubfunction(size_t index) const {
1317 if(index > 0 && index <= v_subs.size()) {
1318 return v_subs[index - 1];
1319 }
1320 return empty_string;
1321 }
subfunctionPrecalculated(size_t index) const1322 bool UserFunction::subfunctionPrecalculated(size_t index) const {
1323 if(index > 0 && index <= v_precalculate.size()) {
1324 return v_precalculate[index - 1];
1325 }
1326 return false;
1327 }
1328
Argument(string name_,bool does_test,bool does_error)1329 Argument::Argument(string name_, bool does_test, bool does_error) {
1330 sname = name_;
1331 remove_blank_ends(sname);
1332 scondition = "";
1333 b_zero = true;
1334 b_test = does_test;
1335 b_matrix = false;
1336 b_text = false;
1337 b_error = does_error;
1338 b_rational = false;
1339 b_last = false;
1340 b_handle_vector = false;
1341 }
Argument(const Argument * arg)1342 Argument::Argument(const Argument *arg) {
1343 b_text = false;
1344 set(arg);
1345 }
~Argument()1346 Argument::~Argument() {}
copy() const1347 Argument *Argument::copy() const {
1348 return new Argument(this);
1349 }
print() const1350 string Argument::print() const {return "";}
subprintlong() const1351 string Argument::subprintlong() const {return _("a free value");}
printlong() const1352 string Argument::printlong() const {
1353 string str = subprintlong();
1354 if(!b_zero) {
1355 str += " ";
1356 str += _("that is nonzero");
1357 }
1358 if(b_rational) {
1359 if(!b_zero) {
1360 str += " ";
1361 str += _("and");
1362 }
1363 str += " ";
1364 str += _("that is rational (polynomial)");
1365 }
1366 if(!scondition.empty()) {
1367 if(!b_zero || b_rational) {
1368 str += " ";
1369 str += _("and");
1370 }
1371 str += " ";
1372 str += _("that fulfills the condition:");
1373 str += " \"";
1374 string str2 = scondition;
1375 if(name().empty()) gsub("\\x", _("argument"), str2);
1376 else gsub("\\x", name(), str2);
1377 str += str2;
1378 str += "\"";
1379 }
1380 return str;
1381 }
set(const Argument * arg)1382 void Argument::set(const Argument *arg) {
1383 sname = arg->name();
1384 scondition = arg->getCustomCondition();
1385 b_zero = !arg->zeroForbidden();
1386 b_test = arg->tests();
1387 b_matrix = arg->matrixAllowed();
1388 b_rational = arg->rationalPolynomial();
1389 b_last = arg->isLastArgument();
1390 b_handle_vector = arg->handlesVector();
1391 }
test(MathStructure & value,int index,MathFunction * f,const EvaluationOptions & eo) const1392 bool Argument::test(MathStructure &value, int index, MathFunction *f, const EvaluationOptions &eo) const {
1393 if(!b_test) {
1394 return true;
1395 }
1396 bool evaled = false;
1397 bool b = subtest(value, eo);
1398 if(b && !b_zero) {
1399 if(!value.isNumber() && !value.representsNonZero()) {
1400 value.eval(eo);
1401 evaled = true;
1402 }
1403 b = value.representsNonZero();
1404 }
1405 if(b && b_rational) {
1406 if(!evaled) {
1407 value.eval(eo);
1408 evaled = true;
1409 }
1410 b = value.isRationalPolynomial();
1411 }
1412 if(!b && b_matrix) {
1413 if(!evaled && !value.isMatrix()) {
1414 value.eval(eo);
1415 evaled = true;
1416 }
1417 b = value.isMatrix();
1418 }
1419 if(b && !scondition.empty()) {
1420 string expression = scondition;
1421 int id = CALCULATOR->addId(new MathStructure(value), true);
1422 string ids = LEFT_PARENTHESIS ID_WRAP_LEFT;
1423 ids += i2s(id);
1424 ids += ID_WRAP_RIGHT RIGHT_PARENTHESIS;
1425 gsub("\\x", ids, expression);
1426 b = CALCULATOR->testCondition(expression);
1427 CALCULATOR->delId(id);
1428 }
1429 if(!b && b_handle_vector) {
1430 if(!evaled && !value.isVector()) {
1431 value.eval(eo);
1432 evaled = true;
1433 }
1434 if(value.isVector()) return false;
1435 }
1436 if(!b) {
1437 if(b_error && (type() != ARGUMENT_TYPE_SYMBOLIC || !value.isUndefined())) {
1438 if(sname.empty()) {
1439 CALCULATOR->error(true, _("Argument %s in %s() must be %s."), i2s(index).c_str(), f->name().c_str(), printlong().c_str(), NULL);
1440 } else {
1441 CALCULATOR->error(true, _("Argument %s, %s, in %s() must be %s."), i2s(index).c_str(), sname.c_str(), f->name().c_str(), printlong().c_str(), NULL);
1442 }
1443 }
1444 return false;
1445 }
1446 return true;
1447 }
parse(const string & str,const ParseOptions & po) const1448 MathStructure Argument::parse(const string &str, const ParseOptions &po) const {
1449 MathStructure mstruct;
1450 parse(&mstruct, str, po);
1451 return mstruct;
1452 }
parse(MathStructure * mstruct,const string & str,const ParseOptions & po) const1453 void Argument::parse(MathStructure *mstruct, const string &str, const ParseOptions &po) const {
1454 if(b_text) {
1455 size_t pars = 0;
1456 while(true) {
1457 size_t pars2 = 1;
1458 size_t i = pars;
1459 if(str.length() >= 2 + pars * 2 && str[pars] == LEFT_PARENTHESIS_CH && str[str.length() - 1 - pars] == RIGHT_PARENTHESIS_CH) {
1460 while(true) {
1461 i = str.find_first_of(LEFT_PARENTHESIS RIGHT_PARENTHESIS, i + 1);
1462 if(i == string::npos || i >= str.length() - 1 - pars) {
1463 break;
1464 } else if(str[i] == LEFT_PARENTHESIS_CH) {
1465 pars2++;
1466 } else if(str[i] == RIGHT_PARENTHESIS_CH) {
1467 pars2--;
1468 if(pars2 == 0) {
1469 break;
1470 }
1471 }
1472 }
1473 if(pars2 > 0) {
1474 pars++;
1475 }
1476 } else {
1477 break;
1478 }
1479 if(pars2 == 0) break;
1480 }
1481 if(str.length() >= 2 + pars * 2) {
1482 if(str[pars] == ID_WRAP_LEFT_CH && str[str.length() - 1 - pars] == ID_WRAP_RIGHT_CH && str.find(ID_WRAP_RIGHT, pars + 1) == str.length() - 1 - pars) {
1483 CALCULATOR->parse(mstruct, str.substr(pars, str.length() - pars * 2), po);
1484 if(mstruct->isDateTime() && !mstruct->datetime()->parsed_string.empty()) mstruct->set(mstruct->datetime()->parsed_string, false, true);
1485 return;
1486 }
1487 if(str[pars] == '\\' && str[str.length() - 1 - pars] == '\\') {
1488 CALCULATOR->parse(mstruct, str.substr(1 + pars, str.length() - 2 - pars * 2), po);
1489 if(mstruct->isDateTime() && !mstruct->datetime()->parsed_string.empty()) mstruct->set(mstruct->datetime()->parsed_string, false, true);
1490 return;
1491 }
1492 if((str[pars] == '\"' && str[str.length() - 1 - pars] == '\"') || (str[pars] == '\'' && str[str.length() - 1 - pars] == '\'')) {
1493 size_t i = pars + 1, cits = 0;
1494 while(i < str.length() - 1 - pars) {
1495 i = str.find(str[pars], i);
1496 if(i >= str.length() - 1 - pars) {
1497 break;
1498 }
1499 cits++;
1500 i++;
1501 }
1502 if((cits / 2) % 2 == 0) {
1503 i = str.find(ID_WRAP_LEFT, 1 + pars);
1504 if(i == string::npos || i >= str.length() - (1 + pars)) {
1505 mstruct->set(str.substr(1 + pars, str.length() - 2 - pars * 2));
1506 return;
1507 }
1508 string str2 = str.substr(1 + pars, str.length() - 2 - pars * 2);
1509 string str3;
1510 i = 0;
1511 size_t i2 = 0; int id = 0;
1512 while((i = str2.find(ID_WRAP_LEFT, i)) != string::npos) {
1513 i2 = str2.find(ID_WRAP_RIGHT, i + 1);
1514 if(i2 == string::npos) break;
1515 id = s2i(str2.substr(i + 1, i2 - (i + 1)));
1516 MathStructure *m_temp = CALCULATOR->getId((size_t) id);
1517 str3 = "(";
1518 if(!m_temp) {
1519 CALCULATOR->error(true, _("Internal id %s does not exist."), i2s(id).c_str(), NULL);
1520 str3 += CALCULATOR->getVariableById(VARIABLE_ID_UNDEFINED)->preferredInputName(true, false, false, true).name;
1521 } else {
1522 str3 += m_temp->print(CALCULATOR->save_printoptions).c_str();
1523 m_temp->unref();
1524 }
1525 str3 += ")";
1526 str2.replace(i, i2 - i + 1, str3);
1527 i += str3.length();
1528 }
1529 mstruct->set(str2, false, true);
1530 return;
1531 }
1532 }
1533 }
1534 size_t i = str.find(ID_WRAP_LEFT, pars);
1535 if(i == string::npos || i >= str.length() - pars) {
1536 mstruct->set(str.substr(pars, str.length() - pars * 2), false, true);
1537 return;
1538 }
1539 string str2 = str.substr(pars, str.length() - pars * 2);
1540 string str3;
1541 i = 0;
1542 size_t i2 = 0; int id = 0;
1543 while((i = str2.find(ID_WRAP_LEFT, i)) != string::npos) {
1544 i2 = str2.find(ID_WRAP_RIGHT, i + 1);
1545 if(i2 == string::npos) break;
1546 id = s2i(str2.substr(i + 1, i2 - (i + 1)));
1547 MathStructure *m_temp = CALCULATOR->getId((size_t) id);
1548 str3 = "(";
1549 if(!m_temp) {
1550 CALCULATOR->error(true, _("Internal id %s does not exist."), i2s(id).c_str(), NULL);
1551 str3 += CALCULATOR->getVariableById(VARIABLE_ID_UNDEFINED)->preferredInputName(true, false, false, true).name;
1552 } else {
1553 str3 += m_temp->print(CALCULATOR->save_printoptions).c_str();
1554 m_temp->unref();
1555 }
1556 str3 += ")";
1557 str2.replace(i, i2 - i + 1, str3);
1558 i += str3.length();
1559 }
1560 mstruct->set(str2, false, true);
1561 return;
1562 } else {
1563 CALCULATOR->parse(mstruct, str, po);
1564 }
1565 }
1566
subtest(MathStructure &,const EvaluationOptions &) const1567 bool Argument::subtest(MathStructure&, const EvaluationOptions&) const {
1568 return true;
1569 }
name() const1570 string Argument::name() const {
1571 return sname;
1572 }
setName(string name_)1573 void Argument::setName(string name_) {
1574 sname = name_;
1575 remove_blank_ends(sname);
1576 }
setCustomCondition(string condition)1577 void Argument::setCustomCondition(string condition) {
1578 scondition = condition;
1579 remove_blank_ends(scondition);
1580 }
getCustomCondition() const1581 string Argument::getCustomCondition() const {
1582 return scondition;
1583 }
1584
zeroForbidden() const1585 bool Argument::zeroForbidden() const {
1586 return !b_zero;
1587 }
setZeroForbidden(bool forbid_zero)1588 void Argument::setZeroForbidden(bool forbid_zero) {
1589 b_zero = !forbid_zero;
1590 }
1591
tests() const1592 bool Argument::tests() const {
1593 return b_test;
1594 }
setTests(bool does_test)1595 void Argument::setTests(bool does_test) {
1596 b_test = does_test;
1597 }
1598
alerts() const1599 bool Argument::alerts() const {
1600 return b_error;
1601 }
setAlerts(bool does_error)1602 void Argument::setAlerts(bool does_error) {
1603 b_error = does_error;
1604 }
suggestsQuotes() const1605 bool Argument::suggestsQuotes() const {return false;}
type() const1606 int Argument::type() const {
1607 return ARGUMENT_TYPE_FREE;
1608 }
matrixAllowed() const1609 bool Argument::matrixAllowed() const {return b_matrix;}
setMatrixAllowed(bool allow_matrix)1610 void Argument::setMatrixAllowed(bool allow_matrix) {b_matrix = allow_matrix;}
handlesVector() const1611 bool Argument::handlesVector() const {return b_handle_vector;}
setHandleVector(bool handle_vector)1612 void Argument::setHandleVector(bool handle_vector) {b_handle_vector = handle_vector;}
isLastArgument() const1613 bool Argument::isLastArgument() const {return b_last;}
setIsLastArgument(bool is_last)1614 void Argument::setIsLastArgument(bool is_last) {b_last = is_last;}
rationalPolynomial() const1615 bool Argument::rationalPolynomial() const {return b_rational;}
setRationalPolynomial(bool rational_polynomial)1616 void Argument::setRationalPolynomial(bool rational_polynomial) {b_rational = rational_polynomial;}
1617
NumberArgument(string name_,ArgumentMinMaxPreDefinition minmax,bool does_test,bool does_error)1618 NumberArgument::NumberArgument(string name_, ArgumentMinMaxPreDefinition minmax, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {
1619 fmin = NULL;
1620 fmax = NULL;
1621 b_incl_min = true;
1622 b_incl_max = true;
1623 b_complex = true;
1624 b_rational_number = false;
1625 switch(minmax) {
1626 case ARGUMENT_MIN_MAX_POSITIVE: {
1627 fmin = new Number();
1628 b_incl_min = false;
1629 break;
1630 }
1631 case ARGUMENT_MIN_MAX_NEGATIVE: {
1632 fmax = new Number();
1633 b_incl_max = false;
1634 break;
1635 }
1636 case ARGUMENT_MIN_MAX_NONNEGATIVE: {
1637 fmin = new Number();
1638 break;
1639 }
1640 case ARGUMENT_MIN_MAX_NONZERO: {
1641 setZeroForbidden(true);
1642 break;
1643 }
1644 default: {}
1645 }
1646 b_handle_vector = does_test;
1647 }
NumberArgument(const NumberArgument * arg)1648 NumberArgument::NumberArgument(const NumberArgument *arg) {
1649 fmin = NULL;
1650 fmax = NULL;
1651 set(arg);
1652 }
~NumberArgument()1653 NumberArgument::~NumberArgument() {
1654 if(fmin) {
1655 delete fmin;
1656 }
1657 if(fmax) {
1658 delete fmax;
1659 }
1660 }
1661
setMin(const Number * nmin)1662 void NumberArgument::setMin(const Number *nmin) {
1663 if(!nmin) {
1664 if(fmin) {
1665 delete fmin;
1666 }
1667 return;
1668 }
1669 if(!fmin) {
1670 fmin = new Number(*nmin);
1671 } else {
1672 fmin->set(*nmin);
1673 }
1674 }
setIncludeEqualsMin(bool include_equals)1675 void NumberArgument::setIncludeEqualsMin(bool include_equals) {
1676 b_incl_min = include_equals;
1677 }
includeEqualsMin() const1678 bool NumberArgument::includeEqualsMin() const {
1679 return b_incl_min;
1680 }
min() const1681 const Number *NumberArgument::min() const {
1682 return fmin;
1683 }
setMax(const Number * nmax)1684 void NumberArgument::setMax(const Number *nmax) {
1685 if(!nmax) {
1686 if(fmax) {
1687 delete fmax;
1688 }
1689 return;
1690 }
1691 if(!fmax) {
1692 fmax = new Number(*nmax);
1693 } else {
1694 fmax->set(*nmax);
1695 }
1696 }
setIncludeEqualsMax(bool include_equals)1697 void NumberArgument::setIncludeEqualsMax(bool include_equals) {
1698 b_incl_max = include_equals;
1699 }
includeEqualsMax() const1700 bool NumberArgument::includeEqualsMax() const {
1701 return b_incl_max;
1702 }
max() const1703 const Number *NumberArgument::max() const {
1704 return fmax;
1705 }
complexAllowed() const1706 bool NumberArgument::complexAllowed() const {
1707 return b_complex;
1708 }
setComplexAllowed(bool allow_complex)1709 void NumberArgument::setComplexAllowed(bool allow_complex) {
1710 b_complex = allow_complex;
1711 }
rationalNumber() const1712 bool NumberArgument::rationalNumber() const {
1713 return b_rational_number;
1714 }
setRationalNumber(bool rational_number)1715 void NumberArgument::setRationalNumber(bool rational_number) {
1716 b_rational_number = rational_number;
1717 }
subtest(MathStructure & value,const EvaluationOptions & eo) const1718 bool NumberArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
1719 if(!value.isNumber()) {
1720 value.eval(eo);
1721 }
1722 /*if(value.isMultiplication() && value.size() == 2 && value[0].isNumber() && value[1].isUnit() && value[1].unit()->baseUnit() == CALCULATOR->getRadUnit()->baseUnit()) {
1723 value /= CALCULATOR->getRadUnit();
1724 value.eval(eo);
1725 }*/
1726 if(!value.isNumber() || (b_rational_number && !value.number().isRational())) {
1727 return false;
1728 }
1729 if(!b_complex && value.number().hasImaginaryPart()) {
1730 if(!value.number().imaginaryPartIsNonZero()) value.number().clearImaginary();
1731 else return false;
1732 }
1733 if(fmin) {
1734 ComparisonResult cmpr = fmin->compare(value.number());
1735 if(!(cmpr == COMPARISON_RESULT_GREATER || (b_incl_min && COMPARISON_IS_EQUAL_OR_GREATER(cmpr)))) {
1736 return false;
1737 }
1738 }
1739 if(fmax) {
1740 ComparisonResult cmpr = fmax->compare(value.number());
1741 if(!(cmpr == COMPARISON_RESULT_LESS || (b_incl_max && COMPARISON_IS_EQUAL_OR_LESS(cmpr)))) {
1742 return false;
1743 }
1744 }
1745 return true;
1746 }
type() const1747 int NumberArgument::type() const {
1748 return ARGUMENT_TYPE_NUMBER;
1749 }
copy() const1750 Argument *NumberArgument::copy() const {
1751 return new NumberArgument(this);
1752 }
set(const Argument * arg)1753 void NumberArgument::set(const Argument *arg) {
1754 if(arg->type() == ARGUMENT_TYPE_NUMBER) {
1755 const NumberArgument *farg = (const NumberArgument*) arg;
1756 b_incl_min = farg->includeEqualsMin();
1757 b_incl_max = farg->includeEqualsMax();
1758 b_complex = farg->complexAllowed();
1759 b_rational_number = farg->rationalNumber();
1760 if(fmin) {
1761 delete fmin;
1762 fmin = NULL;
1763 }
1764 if(fmax) {
1765 delete fmax;
1766 fmax = NULL;
1767 }
1768 if(farg->min()) {
1769 fmin = new Number(*farg->min());
1770 }
1771 if(farg->max()) {
1772 fmax = new Number(*farg->max());
1773 }
1774 }
1775 Argument::set(arg);
1776 }
print() const1777 string NumberArgument::print() const {
1778 return _("number");
1779 }
subprintlong() const1780 string NumberArgument::subprintlong() const {
1781 string str;
1782 if(b_rational_number) {
1783 str += _("a rational number");
1784 } else if(b_complex) {
1785 str += _("a number");
1786 } else {
1787 str += _("a real number");
1788 }
1789 if(fmin) {
1790 str += " ";
1791 if(b_incl_min) {
1792 str += _(">=");
1793 } else {
1794 str += _(">");
1795 }
1796 str += " ";
1797 str += fmin->print();
1798 }
1799 if(fmax) {
1800 if(fmin) {
1801 str += " ";
1802 str += _("and");
1803 }
1804 str += " ";
1805 if(b_incl_max) {
1806 str += _("<=");
1807 } else {
1808 str += _("<");
1809 }
1810 str += " ";
1811 str += fmax->print();
1812 }
1813 return str;
1814 }
1815
IntegerArgument(string name_,ArgumentMinMaxPreDefinition minmax,bool does_test,bool does_error,IntegerType integer_type)1816 IntegerArgument::IntegerArgument(string name_, ArgumentMinMaxPreDefinition minmax, bool does_test, bool does_error, IntegerType integer_type) : Argument(name_, does_test, does_error) {
1817 imin = NULL;
1818 imax = NULL;
1819 i_inttype = integer_type;
1820 switch(minmax) {
1821 case ARGUMENT_MIN_MAX_POSITIVE: {
1822 imin = new Number(1, 1);
1823 break;
1824 }
1825 case ARGUMENT_MIN_MAX_NEGATIVE: {
1826 imax = new Number(-1, 1);
1827 break;
1828 }
1829 case ARGUMENT_MIN_MAX_NONNEGATIVE: {
1830 imin = new Number();
1831 break;
1832 }
1833 case ARGUMENT_MIN_MAX_NONZERO: {
1834 setZeroForbidden(true);
1835 break;
1836 }
1837 default: {}
1838 }
1839 b_handle_vector = does_test;
1840 }
IntegerArgument(const IntegerArgument * arg)1841 IntegerArgument::IntegerArgument(const IntegerArgument *arg) {
1842 imin = NULL;
1843 imax = NULL;
1844 i_inttype = INTEGER_TYPE_NONE;
1845 set(arg);
1846 }
~IntegerArgument()1847 IntegerArgument::~IntegerArgument() {
1848 if(imin) {
1849 delete imin;
1850 }
1851 if(imax) {
1852 delete imax;
1853 }
1854 }
1855
integerType() const1856 IntegerType IntegerArgument::integerType() const {return i_inttype;}
setIntegerType(IntegerType integer_type)1857 void IntegerArgument::setIntegerType(IntegerType integer_type) {i_inttype = integer_type;}
setMin(const Number * nmin)1858 void IntegerArgument::setMin(const Number *nmin) {
1859 if(!nmin) {
1860 if(imin) {
1861 delete imin;
1862 }
1863 return;
1864 }
1865 if(!imin) {
1866 imin = new Number(*nmin);
1867 } else {
1868 imin->set(*nmin);
1869 }
1870 }
min() const1871 const Number *IntegerArgument::min() const {
1872 return imin;
1873 }
setMax(const Number * nmax)1874 void IntegerArgument::setMax(const Number *nmax) {
1875 if(!nmax) {
1876 if(imax) {
1877 delete imax;
1878 }
1879 return;
1880 }
1881 if(!imax) {
1882 imax = new Number(*nmax);
1883 } else {
1884 imax->set(*nmax);
1885 }
1886 }
max() const1887 const Number *IntegerArgument::max() const {
1888 return imax;
1889 }
subtest(MathStructure & value,const EvaluationOptions & eo) const1890 bool IntegerArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
1891 if(!value.isNumber()) {
1892 value.eval(eo);
1893 }
1894 if(!value.isNumber() || !value.number().isInteger(i_inttype)) {
1895 return false;
1896 }
1897 if(imin) {
1898 ComparisonResult cmpr = imin->compare(value.number());
1899 if(!(COMPARISON_IS_EQUAL_OR_GREATER(cmpr))) {
1900 return false;
1901 }
1902 }
1903 if(imax) {
1904 ComparisonResult cmpr = imax->compare(value.number());
1905 if(!(COMPARISON_IS_EQUAL_OR_LESS(cmpr))) {
1906 return false;
1907 }
1908 }
1909 return true;
1910 }
type() const1911 int IntegerArgument::type() const {
1912 return ARGUMENT_TYPE_INTEGER;
1913 }
copy() const1914 Argument *IntegerArgument::copy() const {
1915 return new IntegerArgument(this);
1916 }
set(const Argument * arg)1917 void IntegerArgument::set(const Argument *arg) {
1918 if(arg->type() == ARGUMENT_TYPE_INTEGER) {
1919 const IntegerArgument *iarg = (const IntegerArgument*) arg;
1920 if(imin) {
1921 delete imin;
1922 imin = NULL;
1923 }
1924 if(imax) {
1925 delete imax;
1926 imax = NULL;
1927 }
1928 if(iarg->min()) {
1929 imin = new Number(*iarg->min());
1930 }
1931 if(iarg->max()) {
1932 imax = new Number(*iarg->max());
1933 }
1934 i_inttype = iarg->integerType();
1935 }
1936 Argument::set(arg);
1937 }
print() const1938 string IntegerArgument::print() const {
1939 return _("integer");
1940 }
subprintlong() const1941 string IntegerArgument::subprintlong() const {
1942 string str = _("an integer");
1943 if(imin) {
1944 str += " ";
1945 str += _(">=");
1946 str += " ";
1947 str += imin->print();
1948 } else if(i_inttype != INTEGER_TYPE_NONE) {
1949 str += " ";
1950 str += _(">=");
1951 str += " ";
1952 switch(i_inttype) {
1953 case INTEGER_TYPE_SIZE: {}
1954 case INTEGER_TYPE_UINT: {str += "0"; break;}
1955 case INTEGER_TYPE_SINT: {str += i2s(INT_MIN); break;}
1956 case INTEGER_TYPE_ULONG: {str += "0"; break;}
1957 case INTEGER_TYPE_SLONG: {str += i2s(LONG_MIN); break;}
1958 default: {}
1959 }
1960 }
1961 if(imax) {
1962 if(imin || i_inttype != INTEGER_TYPE_NONE) {
1963 str += " ";
1964 str += _("and");
1965 }
1966 str += " ";
1967 str += _("<=");
1968 str += " ";
1969 str += imax->print();
1970 } else if(i_inttype != INTEGER_TYPE_NONE) {
1971 str += " ";
1972 str += _("and");
1973 str += " ";
1974 str += _("<=");
1975 str += " ";
1976 switch(i_inttype) {
1977 case INTEGER_TYPE_SIZE: {}
1978 case INTEGER_TYPE_UINT: {str += u2s(UINT_MAX); break;}
1979 case INTEGER_TYPE_SINT: {str += i2s(INT_MAX); break;}
1980 case INTEGER_TYPE_ULONG: {str += u2s(ULONG_MAX); break;}
1981 case INTEGER_TYPE_SLONG: {str += i2s(LONG_MAX); break;}
1982 default: {}
1983 }
1984 }
1985 return str;
1986 }
1987
SymbolicArgument(string name_,bool does_test,bool does_error)1988 SymbolicArgument::SymbolicArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {}
SymbolicArgument(const SymbolicArgument * arg)1989 SymbolicArgument::SymbolicArgument(const SymbolicArgument *arg) {set(arg);}
~SymbolicArgument()1990 SymbolicArgument::~SymbolicArgument() {}
subtest(MathStructure & value,const EvaluationOptions & eo) const1991 bool SymbolicArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
1992 if(!value.isSymbolic() && (!value.isVariable() || value.variable()->isKnown())) {
1993 value.eval(eo);
1994 }
1995 return value.isSymbolic() || (value.isVariable() && !value.variable()->isKnown());
1996 }
type() const1997 int SymbolicArgument::type() const {return ARGUMENT_TYPE_SYMBOLIC;}
copy() const1998 Argument *SymbolicArgument::copy() const {return new SymbolicArgument(this);}
print() const1999 string SymbolicArgument::print() const {return _("symbol");}
subprintlong() const2000 string SymbolicArgument::subprintlong() const {return _("an unknown variable/symbol");}
2001
TextArgument(string name_,bool does_test,bool does_error)2002 TextArgument::TextArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {b_text = true;}
TextArgument(const TextArgument * arg)2003 TextArgument::TextArgument(const TextArgument *arg) {set(arg); b_text = true;}
~TextArgument()2004 TextArgument::~TextArgument() {}
subtest(MathStructure & value,const EvaluationOptions & eo) const2005 bool TextArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2006 if(!value.isSymbolic()) {
2007 value.eval(eo);
2008 }
2009 return value.isSymbolic();
2010 }
type() const2011 int TextArgument::type() const {return ARGUMENT_TYPE_TEXT;}
copy() const2012 Argument *TextArgument::copy() const {return new TextArgument(this);}
print() const2013 string TextArgument::print() const {return _("text");}
subprintlong() const2014 string TextArgument::subprintlong() const {return _("a text string");}
suggestsQuotes() const2015 bool TextArgument::suggestsQuotes() const {return false;}
2016
DateArgument(string name_,bool does_test,bool does_error)2017 DateArgument::DateArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {}
DateArgument(const DateArgument * arg)2018 DateArgument::DateArgument(const DateArgument *arg) {set(arg);}
~DateArgument()2019 DateArgument::~DateArgument() {}
parse(MathStructure * mstruct,const string & str,const ParseOptions & po) const2020 void DateArgument::parse(MathStructure *mstruct, const string &str, const ParseOptions &po) const {
2021 QalculateDateTime dt_test;
2022 if(dt_test.set(str)) {
2023 mstruct->set(dt_test);
2024 } else {
2025 Argument::parse(mstruct, str, po);
2026 }
2027 }
subtest(MathStructure & value,const EvaluationOptions & eo) const2028 bool DateArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2029 if(!value.isDateTime()) {
2030 value.eval(eo);
2031 }
2032 return value.isDateTime();
2033 }
type() const2034 int DateArgument::type() const {return ARGUMENT_TYPE_DATE;}
copy() const2035 Argument *DateArgument::copy() const {return new DateArgument(this);}
print() const2036 string DateArgument::print() const {return string(_("date")) + " (Y-M-D)";}
subprintlong() const2037 string DateArgument::subprintlong() const {return string(_("a date")) + " (Y-M-D)";}
2038
VectorArgument(string name_,bool does_test,bool allow_matrix,bool does_error)2039 VectorArgument::VectorArgument(string name_, bool does_test, bool allow_matrix, bool does_error) : Argument(name_, does_test, does_error) {
2040 setMatrixAllowed(allow_matrix);
2041 b_argloop = true;
2042 }
VectorArgument(const VectorArgument * arg)2043 VectorArgument::VectorArgument(const VectorArgument *arg) {
2044 set(arg);
2045 b_argloop = arg->reoccuringArguments();
2046 size_t i = 1;
2047 while(true) {
2048 if(!arg->getArgument(i)) break;
2049 subargs.push_back(arg->getArgument(i)->copy());
2050 i++;
2051 }
2052 }
~VectorArgument()2053 VectorArgument::~VectorArgument() {
2054 for(size_t i = 0; i < subargs.size(); i++) {
2055 delete subargs[i];
2056 }
2057 }
subtest(MathStructure & value,const EvaluationOptions & eo) const2058 bool VectorArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2059 //if(!value.isVector()) {
2060 value.eval(eo);
2061 //}
2062 if(!value.isVector()) {
2063 if(isLastArgument()) value.transform(STRUCT_VECTOR);
2064 else return false;
2065 }
2066 if(b_argloop && subargs.size() > 0) {
2067 for(size_t i = 0; i < value.countChildren(); i++) {
2068 if(!subargs[i % subargs.size()]->test(value[i], 1, NULL, eo)) {
2069 return false;
2070 }
2071 }
2072 } else {
2073 for(size_t i = 0; i < subargs.size() && i < value.countChildren(); i++) {
2074 if(!subargs[i]->test(value[i], 1, NULL, eo)) {
2075 return false;
2076 }
2077 }
2078 }
2079 return true;
2080 }
type() const2081 int VectorArgument::type() const {return ARGUMENT_TYPE_VECTOR;}
copy() const2082 Argument *VectorArgument::copy() const {return new VectorArgument(this);}
print() const2083 string VectorArgument::print() const {return _("vector");}
subprintlong() const2084 string VectorArgument::subprintlong() const {
2085 if(subargs.size() > 0) {
2086 string str = _("a vector with ");
2087 for(size_t i = 0; i < subargs.size(); i++) {
2088 if(i > 0) {
2089 str += ", ";
2090 }
2091 str += subargs[i]->printlong();
2092 }
2093 if(b_argloop) {
2094 str += ", ...";
2095 }
2096 return str;
2097 } else {
2098 return _("a vector");
2099 }
2100 }
reoccuringArguments() const2101 bool VectorArgument::reoccuringArguments() const {
2102 return b_argloop;
2103 }
setReoccuringArguments(bool reocc)2104 void VectorArgument::setReoccuringArguments(bool reocc) {
2105 b_argloop = reocc;
2106 }
addArgument(Argument * arg)2107 void VectorArgument::addArgument(Argument *arg) {
2108 arg->setAlerts(false);
2109 subargs.push_back(arg);
2110 }
delArgument(size_t index)2111 void VectorArgument::delArgument(size_t index) {
2112 if(index > 0 && index <= subargs.size()) {
2113 subargs.erase(subargs.begin() + (index - 1));
2114 }
2115 }
countArguments() const2116 size_t VectorArgument::countArguments() const {
2117 return subargs.size();
2118 }
getArgument(size_t index) const2119 Argument *VectorArgument::getArgument(size_t index) const {
2120 if(index > 0 && index <= subargs.size()) {
2121 return subargs[index - 1];
2122 }
2123 return NULL;
2124 }
2125
MatrixArgument(string name_,bool does_test,bool does_error)2126 MatrixArgument::MatrixArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {
2127 b_square = false;
2128 }
MatrixArgument(const MatrixArgument * arg)2129 MatrixArgument::MatrixArgument(const MatrixArgument *arg) {
2130 set(arg);
2131 b_square = arg->squareDemanded();
2132 }
~MatrixArgument()2133 MatrixArgument::~MatrixArgument() {}
subtest(MathStructure & value,const EvaluationOptions & eo) const2134 bool MatrixArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2135 value.eval(eo);
2136 if(!b_square && !value.isMatrix() && value.isVector() && value.size() > 0 && !value[0].isVector()) {
2137 for(size_t i = 0; i < value.size(); i++) {
2138 value[i].transform(STRUCT_VECTOR);
2139 }
2140 }
2141 return value.isMatrix() && (!b_square || value.matrixIsSquare());
2142 }
squareDemanded() const2143 bool MatrixArgument::squareDemanded() const {return b_square;}
setSquareDemanded(bool square)2144 void MatrixArgument::setSquareDemanded(bool square) {b_square = square;}
type() const2145 int MatrixArgument::type() const {return ARGUMENT_TYPE_MATRIX;}
copy() const2146 Argument *MatrixArgument::copy() const {return new MatrixArgument(this);}
print() const2147 string MatrixArgument::print() const {return _("matrix");}
subprintlong() const2148 string MatrixArgument::subprintlong() const {
2149 if(b_square) {
2150 return _("a square matrix");
2151 } else {
2152 return _("a matrix");
2153 }
2154 }
2155
ExpressionItemArgument(string name_,bool does_test,bool does_error)2156 ExpressionItemArgument::ExpressionItemArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {b_text = true;}
ExpressionItemArgument(const ExpressionItemArgument * arg)2157 ExpressionItemArgument::ExpressionItemArgument(const ExpressionItemArgument *arg) {set(arg); b_text = true;}
~ExpressionItemArgument()2158 ExpressionItemArgument::~ExpressionItemArgument() {}
subtest(MathStructure & value,const EvaluationOptions & eo) const2159 bool ExpressionItemArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2160 if(!value.isSymbolic()) {
2161 value.eval(eo);
2162 }
2163 return value.isSymbolic() && CALCULATOR->getExpressionItem(value.symbol());
2164 }
type() const2165 int ExpressionItemArgument::type() const {return ARGUMENT_TYPE_EXPRESSION_ITEM;}
copy() const2166 Argument *ExpressionItemArgument::copy() const {return new ExpressionItemArgument(this);}
print() const2167 string ExpressionItemArgument::print() const {return _("object");}
subprintlong() const2168 string ExpressionItemArgument::subprintlong() const {return _("a valid function, unit or variable name");}
2169
FunctionArgument(string name_,bool does_test,bool does_error)2170 FunctionArgument::FunctionArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {b_text = true;}
FunctionArgument(const FunctionArgument * arg)2171 FunctionArgument::FunctionArgument(const FunctionArgument *arg) {set(arg); b_text = true;}
~FunctionArgument()2172 FunctionArgument::~FunctionArgument() {}
subtest(MathStructure & value,const EvaluationOptions & eo) const2173 bool FunctionArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2174 if(!value.isSymbolic()) {
2175 value.eval(eo);
2176 }
2177 return value.isSymbolic() && CALCULATOR->getActiveFunction(value.symbol());
2178 }
type() const2179 int FunctionArgument::type() const {return ARGUMENT_TYPE_FUNCTION;}
copy() const2180 Argument *FunctionArgument::copy() const {return new FunctionArgument(this);}
print() const2181 string FunctionArgument::print() const {return _("function");}
subprintlong() const2182 string FunctionArgument::subprintlong() const {return _("a valid function name");}
2183
UnitArgument(string name_,bool does_test,bool does_error)2184 UnitArgument::UnitArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {b_text = true;}
UnitArgument(const UnitArgument * arg)2185 UnitArgument::UnitArgument(const UnitArgument *arg) {set(arg); b_text = true;}
~UnitArgument()2186 UnitArgument::~UnitArgument() {}
subtest(MathStructure & value,const EvaluationOptions & eo) const2187 bool UnitArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2188 if(!value.isSymbolic()) {
2189 value.eval(eo);
2190 }
2191 return value.isSymbolic() && CALCULATOR->getActiveUnit(value.symbol());
2192 }
type() const2193 int UnitArgument::type() const {return ARGUMENT_TYPE_UNIT;}
copy() const2194 Argument *UnitArgument::copy() const {return new UnitArgument(this);}
print() const2195 string UnitArgument::print() const {return _("unit");}
subprintlong() const2196 string UnitArgument::subprintlong() const {return _("a valid unit name");}
2197
VariableArgument(string name_,bool does_test,bool does_error)2198 VariableArgument::VariableArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {b_text = true;}
VariableArgument(const VariableArgument * arg)2199 VariableArgument::VariableArgument(const VariableArgument *arg) {set(arg); b_text = true;}
~VariableArgument()2200 VariableArgument::~VariableArgument() {}
subtest(MathStructure & value,const EvaluationOptions & eo) const2201 bool VariableArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2202 if(!value.isSymbolic()) {
2203 value.eval(eo);
2204 }
2205 return value.isSymbolic() && CALCULATOR->getActiveVariable(value.symbol());
2206 }
type() const2207 int VariableArgument::type() const {return ARGUMENT_TYPE_VARIABLE;}
copy() const2208 Argument *VariableArgument::copy() const {return new VariableArgument(this);}
print() const2209 string VariableArgument::print() const {return _("variable");}
subprintlong() const2210 string VariableArgument::subprintlong() const {return _("a valid variable name");}
2211
FileArgument(string name_,bool does_test,bool does_error)2212 FileArgument::FileArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {b_text = true;}
FileArgument(const FileArgument * arg)2213 FileArgument::FileArgument(const FileArgument *arg) {set(arg); b_text = true;}
~FileArgument()2214 FileArgument::~FileArgument() {}
subtest(MathStructure & value,const EvaluationOptions & eo) const2215 bool FileArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2216 if(!value.isSymbolic()) {
2217 value.eval(eo);
2218 }
2219 return value.isSymbolic();
2220 }
type() const2221 int FileArgument::type() const {return ARGUMENT_TYPE_FILE;}
copy() const2222 Argument *FileArgument::copy() const {return new FileArgument(this);}
print() const2223 string FileArgument::print() const {return _("file");}
subprintlong() const2224 string FileArgument::subprintlong() const {return _("a valid file name");}
2225
BooleanArgument(string name_,bool does_test,bool does_error)2226 BooleanArgument::BooleanArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {}
BooleanArgument(const BooleanArgument * arg)2227 BooleanArgument::BooleanArgument(const BooleanArgument *arg) {set(arg);}
~BooleanArgument()2228 BooleanArgument::~BooleanArgument() {}
subtest(MathStructure & value,const EvaluationOptions & eo) const2229 bool BooleanArgument::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2230 if(!value.isNumber()) {
2231 value.eval(eo);
2232 }
2233 return value.isZero() || value.isOne();
2234 }
type() const2235 int BooleanArgument::type() const {return ARGUMENT_TYPE_BOOLEAN;}
copy() const2236 Argument *BooleanArgument::copy() const {return new BooleanArgument(this);}
print() const2237 string BooleanArgument::print() const {return _("boolean");}
subprintlong() const2238 string BooleanArgument::subprintlong() const {return _("a boolean (0 or 1)");}
2239
AngleArgument(string name_,bool does_test,bool does_error)2240 AngleArgument::AngleArgument(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {}
AngleArgument(const AngleArgument * arg)2241 AngleArgument::AngleArgument(const AngleArgument *arg) {set(arg);}
~AngleArgument()2242 AngleArgument::~AngleArgument() {}
subtest(MathStructure &,const EvaluationOptions &) const2243 bool AngleArgument::subtest(MathStructure&, const EvaluationOptions&) const {
2244 return true;
2245 }
type() const2246 int AngleArgument::type() const {return ARGUMENT_TYPE_ANGLE;}
copy() const2247 Argument *AngleArgument::copy() const {return new AngleArgument(this);}
print() const2248 string AngleArgument::print() const {return _("angle");}
subprintlong() const2249 string AngleArgument::subprintlong() const {return _("an angle or a number (using the default angle unit)");}
parse(MathStructure * mstruct,const string & str,const ParseOptions & po) const2250 void AngleArgument::parse(MathStructure *mstruct, const string &str, const ParseOptions &po) const {
2251 CALCULATOR->parse(mstruct, str, po);
2252 if(po.angle_unit != ANGLE_UNIT_NONE) {
2253 if(mstruct->contains(CALCULATOR->getRadUnit(), false, true, true) > 0) return;
2254 if(mstruct->contains(CALCULATOR->getDegUnit(), false, true, true) > 0) return;
2255 if(mstruct->contains(CALCULATOR->getGraUnit(), false, true, true) > 0) return;
2256 if(contains_angle_unit(*mstruct, po)) return;
2257 }
2258 switch(po.angle_unit) {
2259 case ANGLE_UNIT_DEGREES: {
2260 mstruct->multiply(CALCULATOR->getDegUnit());
2261 break;
2262 }
2263 case ANGLE_UNIT_GRADIANS: {
2264 mstruct->multiply(CALCULATOR->getGraUnit());
2265 break;
2266 }
2267 case ANGLE_UNIT_RADIANS: {
2268 mstruct->multiply(CALCULATOR->getRadUnit());
2269 break;
2270 }
2271 default: {}
2272 }
2273 }
2274
ArgumentSet(string name_,bool does_test,bool does_error)2275 ArgumentSet::ArgumentSet(string name_, bool does_test, bool does_error) : Argument(name_, does_test, does_error) {
2276 }
ArgumentSet(const ArgumentSet * arg)2277 ArgumentSet::ArgumentSet(const ArgumentSet *arg) {
2278 set(arg);
2279 size_t i = 1;
2280 while(true) {
2281 if(!arg->getArgument(i)) break;
2282 subargs.push_back(arg->getArgument(i)->copy());
2283 i++;
2284 }
2285 }
~ArgumentSet()2286 ArgumentSet::~ArgumentSet() {
2287 for(size_t i = 0; i < subargs.size(); i++) {
2288 delete subargs[i];
2289 }
2290 }
subtest(MathStructure & value,const EvaluationOptions & eo) const2291 bool ArgumentSet::subtest(MathStructure &value, const EvaluationOptions &eo) const {
2292 for(size_t i = 0; i < subargs.size(); i++) {
2293 if(subargs[i]->test(value, 1, NULL, eo)) {
2294 return true;
2295 }
2296 }
2297 return false;
2298 }
type() const2299 int ArgumentSet::type() const {return ARGUMENT_TYPE_SET;}
copy() const2300 Argument *ArgumentSet::copy() const {return new ArgumentSet(this);}
print() const2301 string ArgumentSet::print() const {
2302 string str = "";
2303 for(size_t i = 0; i < subargs.size(); i++) {
2304 if(i > 0) {
2305 if(i == subargs.size() - 1) {
2306 str += " ";
2307 str += _("or");
2308 str += " ";
2309 } else {
2310 str += ", ";
2311 }
2312 }
2313 str += subargs[i]->print();
2314 }
2315 return str;
2316 }
subprintlong() const2317 string ArgumentSet::subprintlong() const {
2318 string str = "";
2319 for(size_t i = 0; i < subargs.size(); i++) {
2320 if(i > 0) {
2321 if(i == subargs.size() - 1) {
2322 str += " ";
2323 str += _("or");
2324 str += " ";
2325 } else {
2326 str += ", ";
2327 }
2328 }
2329 str += subargs[i]->printlong();
2330 }
2331 return str;
2332 }
addArgument(Argument * arg)2333 void ArgumentSet::addArgument(Argument *arg) {
2334 arg->setAlerts(false);
2335 subargs.push_back(arg);
2336 }
delArgument(size_t index)2337 void ArgumentSet::delArgument(size_t index) {
2338 if(index > 0 && index <= subargs.size()) {
2339 subargs.erase(subargs.begin() + (index - 1));
2340 }
2341 }
countArguments() const2342 size_t ArgumentSet::countArguments() const {
2343 return subargs.size();
2344 }
getArgument(size_t index) const2345 Argument *ArgumentSet::getArgument(size_t index) const {
2346 if(index > 0 && index <= subargs.size()) {
2347 return subargs[index - 1];
2348 }
2349 return NULL;
2350 }
2351