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