1 /*
2    Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3    Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY.
11 
12    See the COPYING file for more details.
13 */
14 
15 #include "formula/formula.hpp"
16 
17 #include "formula/callable.hpp"
18 #include "formula/function.hpp"
19 #include "formula/string_utils.hpp"
20 #include "random.hpp"
21 #include "serialization/string_utils.hpp"
22 #include "log.hpp"
23 
24 #include <cassert>
25 #include <set>
26 #include <sstream>
27 
28 // This is here only for the below initialization code.
29 // If other logging is required in this file, it should use a different logdomain
30 // (probably "scripting/formula" or something)
31 static lg::log_domain log_engine("engine");
32 #define ERR_NG LOG_STREAM(err, log_engine)
33 
34 namespace utils {
35 	namespace detail {
36 		std::string evaluate_formula_impl(const std::string&);
37 
evaluate_formula_impl(const std::string & formula)38 		std::string evaluate_formula_impl(const std::string& formula) {
39 			try {
40 				const wfl::formula form(formula);
41 				return form.evaluate().string_cast();
42 			} catch(const wfl::formula_error& e) {
43 				ERR_NG << "Formula in WML string cannot be evaluated due to "
44 					<< e.type << "\n\t--> \"";
45 				return "";
46 			}
47 		}
48 
49 		struct formula_initer {
formula_initerutils::detail::formula_initer50 			formula_initer() {
51 				evaluate_formula = &evaluate_formula_impl;
52 			}
53 		} init;
54 	}
55 }
56 
57 namespace wfl
58 {
59 using expr_table           = std::map<std::string, expression_ptr>;
60 using expr_table_evaluated = std::map<std::string, variant>;
61 using expr_table_ptr       = std::shared_ptr<expr_table>;
62 
63 // Function used when creating error reports.
64 // Parses all tokens passed to parse_expression, thus there are no EOL or whitespaces
tokens_to_string(const tk::token * i1,const tk::token * i2)65 static std::string tokens_to_string(const tk::token* i1, const tk::token* i2)
66 {
67 	std::ostringstream expr;
68 	while(i1 != i2) {
69 		expr << std::string(i1->begin, i1->end) << " ";
70 		++i1;
71 	}
72 
73 	return expr.str();
74 }
75 
76 class null_expression : public formula_expression
77 {
78 public:
null_expression()79 	null_expression() {}
80 
str() const81 	std::string str() const
82 	{
83 		return "";
84 	}
85 
86 private:
execute(const formula_callable &,formula_debugger *) const87 	variant execute(const formula_callable& /*variables*/, formula_debugger* /*fdb*/) const
88 	{
89 		return variant();
90 	}
91 };
92 
93 // Implemented further down
94 expression_ptr parse_expression(const tk::token* i1, const tk::token* i2, function_symbol_table* symbols);
95 
96 
97 const char* const formula::id_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
98 
formula(const std::string & text,function_symbol_table * symbols)99 formula::formula(const std::string& text, function_symbol_table* symbols)
100 	: expr_()
101 	, str_(text)
102 	, managed_symbols_(symbols ? nullptr : new function_symbol_table)
103 	, symbols_(symbols ? symbols : managed_symbols_.get())
104 {
105 	std::vector<tk::token> tokens;
106 	std::string::const_iterator i1 = text.begin(), i2 = text.end();
107 
108 	// Set true when 'fai' keyword is found
109 	bool fai_keyword = false;
110 
111 	// Set true when 'wfl' keyword is found
112 	bool wfl_keyword = false;
113 
114 	// Used to locally keep the track of which file we parse actually and in which line we are
115 	std::vector<std::pair<std::string, int>> files;
116 
117 	// Used as a source of strings - we point to these strings from tokens
118 	std::set<std::string> filenames;
119 
120 	files.emplace_back("formula", 1);
121 	filenames.insert("formula");
122 
123 	std::set<std::string>::iterator filenames_it = filenames.begin();
124 
125 	while(i1 != i2) {
126 		try {
127 			tokens.push_back(tk::get_token(i1,i2));
128 
129 			tk::TOKEN_TYPE current_type = tokens.back().type;
130 
131 			if(current_type == tk::TOKEN_WHITESPACE)  {
132 				tokens.pop_back();
133 			} else if(current_type == tk::TOKEN_COMMENT) {
134 				// Since we can have multiline comments, let's see how many EOL are within it
135 				int counter = 0;
136 
137 				std::string comment = std::string(tokens.back().begin, tokens.back().end);
138 				for(const auto& str_it : comment) {
139 					if(str_it == '\n') {
140 						counter++;
141 					}
142 				}
143 
144 				files.back().second += counter;
145 				tokens.pop_back();
146 			} else if(current_type == tk::TOKEN_EOL) {
147 				files.back().second++;
148 				tokens.pop_back();
149 			} else if((current_type == tk::TOKEN_KEYWORD) && (std::string(tokens.back().begin, tokens.back().end) == "fai")) {
150 				fai_keyword = true;
151 				tokens.pop_back();
152 			} else if((current_type == tk::TOKEN_KEYWORD) && (std::string(tokens.back().begin, tokens.back().end) == "wfl")) {
153 				wfl_keyword = true;
154 				tokens.pop_back();
155 			} else if((current_type == tk::TOKEN_KEYWORD) && (std::string(tokens.back().begin, tokens.back().end) == "faiend")) {
156 				if(files.size() > 1) {
157 					files.pop_back();
158 					filenames_it = filenames.find(files.back().first);
159 
160 					tokens.pop_back();
161 				} else {
162 					throw formula_error("Unexpected 'faiend' found", "", "", 0);
163 				}
164 			} else if((current_type == tk::TOKEN_KEYWORD) && (std::string(tokens.back().begin, tokens.back().end) == "wflend")) {
165 				if(files.size() > 1) {
166 					files.pop_back();
167 					filenames_it = filenames.find(files.back().first);
168 
169 					tokens.pop_back();
170 				} else {
171 					throw formula_error("Unexpected 'wflend' found", "", "", 0);
172 				}
173 			} else if(fai_keyword || wfl_keyword) {
174 				if(current_type == tk::TOKEN_STRING_LITERAL) {
175 					std::string str = std::string(tokens.back().begin, tokens.back().end);
176 					files.emplace_back(str , 1);
177 
178 					std::set<std::string>::iterator pos;
179 					bool success;
180 
181 					std::tie(pos, success) = filenames.insert(str);
182 
183 					if(success) {
184 						filenames_it = pos;
185 					} else {
186 						if(fai_keyword) {
187 							throw formula_error("Faifile already included", "fai" + str, "", 0);
188 						} else {
189 							throw formula_error("Wflfile already included", "wfl" + str, "", 0);
190 						}
191 					}
192 
193 					tokens.pop_back();
194 					fai_keyword = false;
195 					wfl_keyword = false;
196 				} else {
197 					if(fai_keyword) {
198 						throw formula_error("Expected string after the 'fai'", "fai", "", 0);
199 					} else {
200 						throw formula_error("Expected string after the 'wfl'", "wfl", "", 0);
201 					}
202 				}
203 			} else {
204 				// In every token not specified above, store line number and name of file it came from
205 				tokens.back().filename = &(*filenames_it);
206 				tokens.back().line_number = files.back().second;
207 			}
208 		} catch(const tk::token_error& e) {
209 			// When we catch token error, we should write whole line in which error occurred,
210 			// so we merge info from token and everything we had in the line so far
211 			std::string str = "";
212 			if(!tokens.empty()) {
213 				tk::token* tok_it = &tokens[0] + tokens.size()-1;
214 				while(( tok_it != &tokens[0] ) && (tok_it->line_number == tokens.back().line_number)) {
215 					--tok_it;
216 				}
217 
218 				if(tok_it != &tokens[0] && tok_it != &tokens[0] + tokens.size() -1) {
219 					++tok_it;
220 				}
221 
222 				str = tokens_to_string(tok_it, &tokens[0] + tokens.size());
223 			}
224 
225 			throw formula_error(e.description_, str + e.formula_, *filenames_it, files.back().second);
226 		}
227 	}
228 
229 	if(files.size() > 1) {
230 		throw formula_error("Missing 'wflend', make sure each .wfl file ends with it", "", "", 0);
231 	}
232 
233 	if(!tokens.empty()) {
234 		expr_ = parse_expression(&tokens[0], &tokens[0] + tokens.size(), symbols_);
235 	} else {
236 		expr_ = std::make_shared<null_expression>();
237 	}
238 }
239 
formula(const tk::token * i1,const tk::token * i2,function_symbol_table * symbols)240 formula::formula(const tk::token* i1, const tk::token* i2, function_symbol_table* symbols)
241 	: expr_()
242 	, str_()
243 	, managed_symbols_(symbols ? nullptr : new function_symbol_table)
244 	, symbols_(symbols ? symbols : managed_symbols_.get())
245 {
246 	if(i1 != i2) {
247 		expr_ = parse_expression(i1, i2, symbols);
248 	} else {
249 		expr_ = std::make_shared<null_expression>();
250 	}
251 }
252 
create_optional_formula(const std::string & str,function_symbol_table * symbols)253 formula_ptr formula::create_optional_formula(const std::string& str, function_symbol_table* symbols)
254 {
255 	if(str.empty()) {
256 		return formula_ptr();
257 	}
258 
259 	return formula_ptr(new formula(str, symbols));
260 }
261 
execute(const formula_callable & variables,formula_debugger * fdb) const262 variant formula::execute(const formula_callable& variables, formula_debugger*fdb) const
263 {
264 	try {
265 		return expr_->evaluate(variables, fdb);
266 	} catch(const type_error& e) {
267 		std::cerr << "formula type error: " << e.message << "\n";
268 		return variant();
269 	}
270 }
271 
execute(formula_debugger * fdb) const272 variant formula::execute(formula_debugger*fdb) const
273 {
274 	static map_formula_callable null_callable;
275 	return execute(null_callable,fdb);
276 }
277 
278 
formula_error(const std::string & type,const std::string & formula,const std::string & file,int line)279 formula_error::formula_error(const std::string& type, const std::string& formula,
280 		const std::string& file, int line)
281 	: error()
282 	, type(type)
283 	, formula(formula)
284 	, filename(file)
285 	, line(line)
286 {
287 	std::stringstream ss;
288 	ss << "Formula error in " << filename << ":" << line
289 	   << "\nIn formula " << formula
290 	   << "\nError: " << type;
291 	message = ss.str();
292 }
293 
294 
295 /**
296  * Classes that encapsulate and handle the various formula functions.
297  */
298 class function_list_expression : public formula_expression
299 {
300 public:
function_list_expression(function_symbol_table * symbols)301 	explicit function_list_expression(function_symbol_table* symbols)
302 		: symbols_(symbols)
303 	{}
304 
str() const305 	virtual std::string str() const
306 	{
307 		return "{function_list_expression()}";
308 	}
309 
310 private:
execute(const formula_callable &,formula_debugger *) const311 	variant execute(const formula_callable& /*variables*/, formula_debugger* /*fdb*/) const
312 	{
313 		std::vector<variant> res;
314 		for(const std::string& fcn_name : symbols_->get_function_names()) {
315 			res.emplace_back(fcn_name);
316 		}
317 
318 		return variant(res);
319 	}
320 
321 	function_symbol_table* symbols_;
322 };
323 
324 class list_expression : public formula_expression
325 {
326 public:
list_expression(const std::vector<expression_ptr> & items)327 	explicit list_expression(const std::vector<expression_ptr>& items)
328 		: items_(items)
329 	{}
330 
331 private:
execute(const formula_callable & variables,formula_debugger * fdb) const332 	variant execute(const formula_callable& variables, formula_debugger*fdb) const
333 	{
334 		std::vector<variant> res;
335 		res.reserve(items_.size());
336 		for(const auto& i : items_) {
337 			res.push_back(i->evaluate(variables, add_debug_info(fdb, 0, "[list element]")));
338 		}
339 
340 		return variant(res);
341 	}
342 
343 	std::vector<expression_ptr> items_;
344 
str() const345 	std::string str() const
346 	{
347 		std::stringstream s;
348 		s << '[';
349 		bool first_item = true;
350 		for(expression_ptr a : items_) {
351 			if(!first_item) {
352 				s << ',';
353 			} else {
354 				first_item = false;
355 			}
356 			s << a->str();
357 		}
358 		s << ']';
359 		return s.str();
360 	}
361 };
362 
363 class map_expression : public formula_expression
364 {
365 public:
map_expression(const std::vector<expression_ptr> & items)366 	explicit map_expression(const std::vector<expression_ptr>& items)
367 		: items_(items)
368 	{}
369 
str() const370 	virtual std::string str() const
371 	{
372 		std::stringstream s;
373 		s << " [";
374 		for(std::vector<expression_ptr>::const_iterator i = items_.begin(); (i != items_.end()) && (i + 1 != items_.end()) ; i += 2) {
375 			if(i != items_.begin()) {
376 				s << ", ";
377 			}
378 			s << (*i)->str();
379 			s << " -> ";
380 			s << (*(i+1))->str();
381 		}
382 		if(items_.empty()) {
383 			s << "->";
384 		}
385 		s << " ]";
386 		return s.str();
387 	}
388 
389 private:
execute(const formula_callable & variables,formula_debugger * fdb) const390 	variant execute(const formula_callable& variables, formula_debugger*fdb) const
391 	{
392 		std::map<variant,variant> res;
393 		for(std::vector<expression_ptr>::const_iterator i = items_.begin(); (i != items_.end()) && (i + 1 != items_.end()) ; i += 2) {
394 			variant key = (*i)->evaluate(variables, add_debug_info(fdb, 0, "key ->"));
395 			variant value = (*(i+1))->evaluate(variables, add_debug_info(fdb, 1, "-> value"));
396 			res[key] = value;
397 		}
398 
399 		return variant(res);
400 	}
401 
402 	std::vector<expression_ptr> items_;
403 };
404 
405 class unary_operator_expression : public formula_expression
406 {
407 public:
unary_operator_expression(const std::string & op,expression_ptr arg)408 	unary_operator_expression(const std::string& op, expression_ptr arg)
409 		: op_(),op_str_(op)
410 		, operand_(arg)
411 	{
412 		if(op == "not") {
413 			op_ = NOT;
414 		} else if(op == "-") {
415 			op_ = SUB;
416 		} else {
417 			throw formula_error("Illegal unary operator: '" + op + "'" , "", "", 0);
418 		}
419 	}
420 
str() const421 	virtual std::string str() const
422 	{
423 		std::stringstream s;
424 		s << op_str_ << '('<< operand_->str() << ')';
425 		return s.str();
426 	}
427 
428 private:
execute(const formula_callable & variables,formula_debugger * fdb) const429 	variant execute(const formula_callable& variables, formula_debugger*fdb) const
430 	{
431 		const variant res = operand_->evaluate(variables, add_debug_info(fdb, 0, op_str_ + " unary"));
432 		switch(op_) {
433 		case NOT:
434 			return res.as_bool() ? variant(0) : variant(1);
435 		case SUB:
436 		default:
437 			return -res;
438 		}
439 	}
440 
441 	enum OP { NOT, SUB };
442 	OP op_;
443 	std::string op_str_;
444 	expression_ptr operand_;
445 };
446 
447 class string_callable : public formula_callable
448 {
449 public:
string_callable(const variant & string)450 	explicit string_callable(const variant& string) : string_(string) {}
451 
get_inputs(formula_input_vector & inputs) const452 	void get_inputs(formula_input_vector& inputs) const
453 	{
454 		add_input(inputs, "size");
455 		add_input(inputs, "empty");
456 		add_input(inputs, "char");
457 		add_input(inputs, "word");
458 		add_input(inputs, "item");
459 	}
460 
get_value(const std::string & key) const461 	variant get_value(const std::string& key) const
462 	{
463 		if(key == "size") {
464 			return variant(string_.as_string().length());
465 		} else if(key == "empty") {
466 			return variant(string_.as_string().empty());
467 		} else if(key == "char" || key == "chars") {
468 			std::vector<variant> chars;
469 			for(char c : string_.as_string()) {
470 				chars.emplace_back(std::string(1, c));
471 			}
472 
473 			return variant(chars);
474 		} else if(key == "word" || key == "words") {
475 			std::vector<variant> words;
476 			const std::string& str = string_.as_string();
477 			size_t next_space = 0;
478 			do {
479 				size_t last_space = next_space;
480 				next_space = str.find_first_of(" \t", next_space);
481 				words.emplace_back(str.substr(last_space, next_space - last_space));
482 				next_space = str.find_first_not_of(" \t", next_space);
483 			} while(next_space != std::string::npos);
484 
485 			return variant(words);
486 		} else if(key == "item" || key == "items") {
487 			std::vector<std::string> split = utils::parenthetical_split(string_.as_string(), ',');
488 			std::vector<variant> items;
489 			items.reserve(split.size());
490 			for(const std::string s : split) {
491 				items.emplace_back(s);
492 			}
493 
494 			return variant(items);
495 		}
496 
497 		return variant();
498 	}
499 
500 private:
501 	variant string_;
502 };
503 
504 class list_callable : public formula_callable
505 {
506 public:
list_callable(const variant & list)507 	explicit list_callable(const variant& list) : list_(list) {}
508 
get_inputs(formula_input_vector & inputs) const509 	void get_inputs(formula_input_vector& inputs) const
510 	{
511 		add_input(inputs, "size", FORMULA_READ_WRITE);
512 		add_input(inputs, "empty", FORMULA_READ_WRITE);
513 		add_input(inputs, "first", FORMULA_READ_WRITE);
514 		add_input(inputs, "last", FORMULA_READ_WRITE);
515 	}
516 
get_value(const std::string & key) const517 	variant get_value(const std::string& key) const
518 	{
519 		if(key == "size") {
520 			return variant(list_.num_elements());
521 		} else if(key == "empty") {
522 			return variant(list_.num_elements() == 0);
523 		} else if(key == "first") {
524 			if(list_.num_elements() > 0) {
525 				return list_[0];
526 			}
527 
528 			return variant();
529 		} else if(key == "last") {
530 			if(list_.num_elements() > 0) {
531 				return list_[list_.num_elements()-1];
532 			}
533 
534 			return variant();
535 		}
536 
537 		return variant();
538 	}
539 
540 private:
541 	variant list_;
542 };
543 
544 class map_callable : public formula_callable
545 {
546 public:
map_callable(const variant & map)547 	explicit map_callable(const variant& map) : map_(map) {}
548 
get_inputs(formula_input_vector & inputs) const549 	void get_inputs(formula_input_vector& inputs) const
550 	{
551 		add_input(inputs, "size", FORMULA_READ_WRITE);
552 		add_input(inputs, "empty", FORMULA_READ_WRITE);
553 
554 		for(const auto& v : map_) {
555 			// variant_iterator does not implement operator->,
556 			// and to do so is notrivial since it returns temporaries for maps.
557 			const variant& key_variant = v.get_member("key");
558 			if(!key_variant.is_string()) {
559 				continue;
560 			}
561 
562 			std::string key = key_variant.as_string();
563 			bool valid = true;
564 			for(char c : key) {
565 				if(!isalpha(c) && c != '_') {
566 					valid = false;
567 					break;
568 				}
569 			}
570 
571 			if(valid) {
572 				add_input(inputs, key);
573 			}
574 		}
575 	}
576 
get_value(const std::string & key) const577 	variant get_value(const std::string& key) const
578 	{
579 		const variant key_variant(key);
580 		if(map_.as_map().find(key_variant) != map_.as_map().end()) {
581 			return map_[key_variant];
582 		} else if(key == "size") {
583 			return variant(map_.num_elements());
584 		} else if(key == "empty") {
585 			return variant(map_.num_elements() == 0);
586 		}
587 
588 		return variant();
589 	}
590 
591 private:
592 	variant map_;
593 };
594 
595 class dot_callable : public formula_callable
596 {
597 public:
dot_callable(const formula_callable & global,const formula_callable & local)598 	dot_callable(const formula_callable &global, const formula_callable& local)
599 		: global_(global), local_(local)
600 	{}
601 
602 private:
603 	const formula_callable& global_, &local_;
604 
get_inputs(formula_input_vector & inputs) const605 	void get_inputs(formula_input_vector& inputs) const
606 	{
607 		return local_.get_inputs(inputs);
608 	}
609 
get_value(const std::string & key) const610 	variant get_value(const std::string& key) const
611 	{
612 		variant v = local_.query_value(key);
613 
614 		if( v == variant() )
615 			return global_.query_value(key);
616 		else
617 			return v;
618 	}
619 };
620 
621 class dot_expression : public formula_expression
622 {
623 public:
dot_expression(expression_ptr left,expression_ptr right)624 	dot_expression(expression_ptr left, expression_ptr right)
625 		: left_(left), right_(right)
626 	{}
627 
str() const628 	std::string str() const
629 	{
630 		std::stringstream s;
631 		s << left_->str() << "." << right_->str();
632 		return s.str();
633 	}
634 
635 private:
execute(const formula_callable & variables,formula_debugger * fdb) const636 	variant execute(const formula_callable& variables, formula_debugger*fdb) const
637 	{
638 		const variant left = left_->evaluate(variables, add_debug_info(fdb,0,"left ."));
639 		if(!left.is_callable()) {
640 			if(left.is_list()) {
641 				list_callable list_call(left);
642 				dot_callable callable(variables, list_call);
643 				return right_->evaluate(callable,fdb);
644 			}
645 
646 			if(left.is_map()) {
647 				map_callable map_call(left);
648 				dot_callable callable(variables, map_call);
649 				return right_->evaluate(callable,fdb);
650 			}
651 
652 			if(left.is_string()) {
653 				string_callable string_call(left);
654 				dot_callable callable(variables, string_call);
655 				return right_->evaluate(callable,fdb);
656 			}
657 
658 			return left;
659 		}
660 
661 		dot_callable callable(variables, *left.as_callable());
662 		return right_->evaluate(callable, add_debug_info(fdb,1,". right"));
663 	}
664 
665 	expression_ptr left_, right_;
666 };
667 
668 class square_bracket_expression : public formula_expression
669 {
670 public:
square_bracket_expression(expression_ptr left,expression_ptr key)671 	square_bracket_expression(expression_ptr left, expression_ptr key)
672 		: left_(left), key_(key)
673 	{}
674 
str() const675 	std::string str() const
676 	{
677 		std::stringstream s;
678 		s << left_->str() << '[' << key_->str() << ']';
679 		return s.str();
680 	}
681 
682 private:
execute(const formula_callable & variables,formula_debugger * fdb) const683 	variant execute(const formula_callable& variables, formula_debugger*fdb) const
684 	{
685 		const variant left = left_->evaluate(variables, add_debug_info(fdb,0,"base[]"));
686 		const variant key = key_->evaluate(variables, add_debug_info(fdb,1,"[index]"));
687 		if(left.is_list() || left.is_map()) {
688 			return left[key];
689 		}
690 
691 		return variant();
692 	}
693 
694 	expression_ptr left_, key_;
695 };
696 
697 class operator_expression : public formula_expression
698 {
699 public:
operator_expression(const std::string & op,expression_ptr left,expression_ptr right)700 	operator_expression(const std::string& op, expression_ptr left, expression_ptr right)
701 		: op_(OP(op[0])), op_str_(op), left_(left), right_(right)
702 	{
703 		if(op == ">=") {
704 			op_ = GTE;
705 		} else if(op == "<=") {
706 			op_ = LTE;
707 		} else if(op == "!=") {
708 			op_ = NEQ;
709 		} else if(op == "and") {
710 			op_ = AND;
711 		} else if(op == "or") {
712 			op_ = OR;
713 		} else if(op == ".+") {
714 			op_ = ADDL;
715 		} else if(op == ".-") {
716 			op_ = SUBL;
717 		} else if(op == ".*") {
718 			op_ = MULL;
719 		} else if(op == "./") {
720 			op_ = DIVL;
721 		} else if(op == "..") {
722 			op_ = OP_CAT;
723 		} else if(op == "in") {
724 			op_ = OP_IN;
725 		}
726 	}
727 
str() const728 	std::string str() const
729 	{
730 		std::stringstream s;
731 		s << '(' << left_->str() << op_str_ << right_->str() << ')';
732 		return s.str();
733 	}
734 
735 private:
execute(const formula_callable & variables,formula_debugger * fdb) const736 	variant execute(const formula_callable& variables, formula_debugger*fdb) const
737 	{
738 		const variant left = left_->evaluate(variables, add_debug_info(fdb, 0, "left " + op_str_));
739 		const variant right = right_->evaluate(variables, add_debug_info(fdb, 1, op_str_ + " right"));
740 
741 		switch(op_) {
742 		case AND:
743 			return left.as_bool() == false ? left : right;
744 		case OR:
745 			return left.as_bool() ? left : right;
746 		case ADD:
747 			return left + right;
748 		case SUB:
749 			return left - right;
750 		case MUL:
751 			return left * right;
752 		case DIV:
753 			return left / right;
754 		case POW:
755 			return left ^ right;
756 		case ADDL:
757 			return left.list_elements_add(right);
758 		case SUBL:
759 			return left.list_elements_sub(right);
760 		case MULL:
761 			return left.list_elements_mul(right);
762 		case DIVL:
763 			return left.list_elements_div(right);
764 		case OP_IN:
765 			return variant(right.contains(left));
766 		case OP_CAT:
767 			return left.concatenate(right);
768 		case EQ:
769 			return left == right ? variant(1) : variant(0);
770 		case NEQ:
771 			return left != right ? variant(1) : variant(0);
772 		case LTE:
773 			return left <= right ? variant(1) : variant(0);
774 		case GTE:
775 			return left >= right ? variant(1) : variant(0);
776 		case LT:
777 			return left < right ? variant(1) : variant(0);
778 		case GT:
779 			return left > right ? variant(1) : variant(0);
780 		case MOD:
781 			return left % right;
782 		case RAN:
783 			return left.build_range(right);
784 		case DICE:
785 			return variant(dice_roll(left.as_int(), right.as_int()));
786 		default:
787 			std::cerr << "ERROR: Unimplemented operator!" << std::endl;
788 			return variant();
789 		}
790 	}
791 
dice_roll(int num_rolls,int faces)792 	static int dice_roll(int num_rolls, int faces)
793 	{
794 		int res = 0;
795 		while(faces > 0 && num_rolls-- > 0) {
796 			res += randomness::generator->get_random_int(1, faces);
797 		}
798 
799 		return res;
800 	}
801 
802 	//In some cases a IN  or CAT macros are defined.
803 	enum OP { AND, OR, NEQ, LTE, GTE, OP_CAT, OP_IN, GT='>', LT='<', EQ='=', RAN='~',
804 	          ADD='+', SUB='-', MUL='*', DIV='/', ADDL, SUBL, MULL, DIVL, DICE='d', POW='^', MOD='%' };
805 
806 	OP op_;
807 	std::string op_str_;
808 	expression_ptr left_, right_;
809 };
810 
811 class where_variables: public formula_callable
812 {
813 public:
where_variables(const formula_callable & base,expr_table_ptr table,formula_debugger * fdb)814 	where_variables(const formula_callable &base, expr_table_ptr table, formula_debugger* fdb)
815 		: formula_callable(false)
816 		, base_(base)
817 		, table_(table)
818 		, evaluated_table_()
819 		, debugger_(fdb)
820 	{
821 	}
822 
823 private:
824 	const formula_callable& base_;
825 	expr_table_ptr table_;
826 	mutable expr_table_evaluated evaluated_table_;
827 	formula_debugger* debugger_;
828 
get_inputs(formula_input_vector & inputs) const829 	void get_inputs(formula_input_vector& inputs) const
830 	{
831 		for(expr_table::const_iterator i = table_->begin(); i != table_->end(); ++i) {
832 			add_input(inputs, i->first);
833 		}
834 	}
835 
get_value(const std::string & key) const836 	variant get_value(const std::string& key) const
837 	{
838 		expr_table::iterator i = table_->find(key);
839 		if(i != table_->end()) {
840 			expr_table_evaluated::const_iterator ev = evaluated_table_.find(key);
841 			if(ev != evaluated_table_.end()) {
842 				return ev->second;
843 			}
844 
845 			variant v = i->second->evaluate(base_, add_debug_info(debugger_, 0, "where[" + key + "]"));
846 			evaluated_table_[key] = v;
847 			return v;
848 		}
849 
850 		return base_.query_value(key);
851 	}
852 };
853 
854 class where_expression: public formula_expression
855 {
856 public:
where_expression(expression_ptr body,expr_table_ptr clauses)857 	where_expression(expression_ptr body, expr_table_ptr clauses)
858 		: body_(body), clauses_(clauses)
859 	{}
860 
str() const861 	std::string str() const
862 	{
863 		std::stringstream s;
864 		s << "{where:(";
865 		s << body_->str();
866 		for(const expr_table::value_type &a : *clauses_) {
867 			s << ", [" << a.first << "] -> ["<< a.second->str()<<"]";
868 		}
869 		s << ")}";
870 		return s.str();
871 	}
872 
873 private:
874 	expression_ptr body_;
875 	expr_table_ptr clauses_;
876 
execute(const formula_callable & variables,formula_debugger * fdb) const877 	variant execute(const formula_callable& variables,formula_debugger*fdb) const
878 	{
879 		where_variables wrapped_variables(variables, clauses_, fdb);
880 		return body_->evaluate(wrapped_variables, add_debug_info(fdb, 0, "... where"));
881 	}
882 };
883 
884 
885 class identifier_expression : public formula_expression
886 {
887 public:
identifier_expression(const std::string & id)888 	explicit identifier_expression(const std::string& id) : id_(id) {}
889 
str() const890 	std::string str() const
891 	{
892 		return id_;
893 	}
894 
895 private:
execute(const formula_callable & variables,formula_debugger *) const896 	variant execute(const formula_callable& variables, formula_debugger* /*fdb*/) const
897 	{
898 		return variables.query_value(id_);
899 	}
900 
901 	std::string id_;
902 };
903 
904 class integer_expression : public formula_expression
905 {
906 public:
integer_expression(int i)907 	explicit integer_expression(int i) : i_(i) {}
908 
str() const909 	std::string str() const
910 	{
911 		std::stringstream s;
912 		s << i_;
913 		return s.str();
914 	}
915 
916 private:
execute(const formula_callable &,formula_debugger *) const917 	variant execute(const formula_callable& /*variables*/, formula_debugger* /*fdb*/) const
918 	{
919 		return variant(i_);
920 	}
921 
922 	int i_;
923 };
924 
925 class decimal_expression : public formula_expression
926 {
927 public:
decimal_expression(int i,int f)928 	decimal_expression(int i, int f) : i_(i), f_(f) {}
929 
str() const930 	std::string str() const
931 	{
932 		std::stringstream s;
933 		s << i_ << '.';
934 		s.width(3);
935 		s.fill('0');
936 		s << f_;
937 		return s.str();
938 	}
939 
940 private:
execute(const formula_callable &,formula_debugger *) const941 	variant execute(const formula_callable& /*variables*/, formula_debugger* /*fdb*/) const
942 	{
943 		return variant(i_ * 1000 + f_, variant::DECIMAL_VARIANT );
944 	}
945 
946 	int i_, f_;
947 };
948 
949 class string_expression : public formula_expression
950 {
951 public:
string_expression(std::string str)952 	explicit string_expression(std::string str)
953 		: str_()
954 		, subs_()
955 	{
956 		std::string::iterator i = str.begin();
957 		while((i = std::find(i, str.end(), '[')) != str.end()) {
958 			int bracket_depth = 0;
959 			std::string::iterator j = i + 1;
960 			while(j != str.end() && (bracket_depth > 0 || *j != ']')) {
961 				if(*j == '[') {
962 					bracket_depth++;
963 				} else if(*j == ']' && bracket_depth > 0) {
964 					bracket_depth--;
965 				}
966 				++j;
967 			}
968 
969 			if(j == str.end()) {
970 				break;
971 			}
972 
973 			const std::string formula_str(i+1, j);
974 			const int pos = std::distance(str.begin(), i);
975 			if(j - i == 2 && (i[1] == '(' || i[1] == '\'' || i[1] == ')')) {
976 				// Bracket contained nothing but a quote or parenthesis.
977 				// This means it was intended as a literal quote or square bracket.
978 				i = str.erase(i);
979 				if(*i == '(') {
980 					*i = '[';
981 				} else if(*i == ')') {
982 					*i = ']';
983 				}
984 
985 				i = str.erase(i + 1);
986 				continue;
987 			} else {
988 				i = str.erase(i, j+1);
989 			}
990 
991 			substitution sub;
992 			sub.pos = pos;
993 			try {
994 				sub.calculation.reset(new formula(formula_str));
995 			} catch(formula_error& e) {
996 				e.filename += " - string substitution";
997 				throw;
998 			}
999 
1000 			subs_.push_back(sub);
1001 		}
1002 
1003 		std::reverse(subs_.begin(), subs_.end());
1004 
1005 		str_ = variant(str);
1006 	}
1007 
str() const1008 	std::string str() const
1009 	{
1010 		std::string res = str_.as_string();
1011 		int j = res.size() - 1;
1012 
1013 		for(const auto& sub : subs_) {
1014 			for(; j >= sub.pos && j >= 0; j--) {
1015 				if(res[j] == '\'') {
1016 					res.replace(j, 1, "[']");
1017 				} else if(res[j] == '[') {
1018 					res.replace(j, 1, "[(]");
1019 				} else if(res[j] == ']') {
1020 					res.replace(j, 1, "[)]");
1021 				}
1022 			}
1023 
1024 			const std::string str = "[" + sub.calculation->str() + "]";
1025 			res.insert(sub.pos, str);
1026 		}
1027 
1028 		for(; j >= 0; j--) {
1029 			if(res[j] == '\'') {
1030 				res.replace(j, 1, "[']");
1031 			} else if(res[j] == '[') {
1032 				res.replace(j, 1, "[(]");
1033 			} else if(res[j] == ']') {
1034 				res.replace(j, 1, "[)]");
1035 			}
1036 		}
1037 
1038 		return "'" + res + "'";
1039 	}
1040 
1041 private:
execute(const formula_callable & variables,formula_debugger * fdb) const1042 	variant execute(const formula_callable& variables, formula_debugger*fdb) const
1043 	{
1044 		if(subs_.empty()) {
1045 			return str_;
1046 		}
1047 
1048 		std::string res = str_.as_string();
1049 		for(size_t i = 0; i < subs_.size(); ++i) {
1050 			const int j = subs_.size() - i - 1;
1051 			const substitution& sub = subs_[i];
1052 			add_debug_info(fdb, j, "[string subst]");
1053 			const std::string str = sub.calculation->evaluate(variables,fdb).string_cast();
1054 			res.insert(sub.pos, str);
1055 		}
1056 
1057 		return variant(res);
1058 	}
1059 
1060 	struct substitution
1061 	{
substitutionwfl::string_expression::substitution1062 		substitution() : pos(0) , calculation() {}
1063 
1064 		int pos;
1065 		const_formula_ptr calculation;
1066 	};
1067 
1068 	variant str_;
1069 	std::vector<substitution> subs_;
1070 };
1071 
1072 
1073 /**
1074  * Functions to handle the actual parsing of WFL.
1075  */
operator_precedence(const tk::token & t)1076 static int operator_precedence(const tk::token& t)
1077 {
1078 	static std::map<std::string,int> precedence_map;
1079 	if(precedence_map.empty()) {
1080 		int n = 0;
1081 		precedence_map["not"]   = ++n;
1082 		precedence_map["where"] = ++n;
1083 		precedence_map["or"]    = ++n;
1084 		precedence_map["and"]   = ++n;
1085 		precedence_map["="]     = ++n;
1086 		precedence_map["!="]    = n;
1087 		precedence_map["<"]     = n;
1088 		precedence_map[">"]     = n;
1089 		precedence_map["<="]    = n;
1090 		precedence_map[">="]    = n;
1091 		precedence_map["in"]    = n;
1092 		precedence_map["~"]     = ++n;
1093 		precedence_map["+"]     = ++n;
1094 		precedence_map["-"]     = n;
1095 		precedence_map[".."]    = n;
1096 		precedence_map["*"]     = ++n;
1097 		precedence_map["/"]     = n;
1098 		precedence_map["%"]     = ++n;
1099 		precedence_map["^"]     = ++n;
1100 		precedence_map["d"]     = ++n;
1101 		precedence_map["."]     = ++n;
1102 	}
1103 
1104 	assert(precedence_map.count(std::string(t.begin, t.end)));
1105 	return precedence_map[std::string(t.begin, t.end)];
1106 }
1107 
parse_function_args(const tk::token * & i1,const tk::token * i2,std::vector<std::string> * res)1108 static void parse_function_args(const tk::token* &i1, const tk::token* i2, std::vector<std::string>* res)
1109 {
1110 	const tk::token* begin = i1, *end = i2;	// These are used for error reporting
1111 
1112 	if(i1->type == tk::TOKEN_LPARENS) {
1113 		++i1;
1114 	} else {
1115 		throw formula_error("Invalid function definition", tokens_to_string(begin,end - 1), *i1->filename, i1->line_number);
1116 	}
1117 
1118 	while((i1-> type != tk::TOKEN_RPARENS) && (i1 != i2)) {
1119 		if(i1->type == tk::TOKEN_IDENTIFIER) {
1120 			if(std::string((i1+1)->begin, (i1+1)->end) == "*") {
1121 				res->push_back(std::string(i1->begin, i1->end) + std::string("*"));
1122 				++i1;
1123 			} else {
1124 				res->push_back(std::string(i1->begin, i1->end));
1125 			}
1126 		} else if(i1->type == tk::TOKEN_COMMA) {
1127 			//do nothing
1128 		} else {
1129 			throw formula_error("Invalid function definition", tokens_to_string(begin,end - 1), *i1->filename, i1->line_number);
1130 		}
1131 
1132 		++i1;
1133 	}
1134 
1135 	if(i1->type != tk::TOKEN_RPARENS) {
1136 		throw formula_error("Invalid function definition", tokens_to_string(begin,end - 1), *i1->filename, i1->line_number);
1137 	}
1138 
1139 	++i1;
1140 }
1141 
parse_args(const tk::token * i1,const tk::token * i2,std::vector<expression_ptr> * res,function_symbol_table * symbols)1142 static void parse_args(const tk::token* i1, const tk::token* i2,
1143                 std::vector<expression_ptr>* res,
1144 				function_symbol_table* symbols)
1145 {
1146 	int parens = 0;
1147 	const tk::token* beg = i1;
1148 	while(i1 != i2) {
1149 		if(i1->type == tk::TOKEN_LPARENS || i1->type == tk::TOKEN_LSQUARE ) {
1150 			++parens;
1151 		} else if(i1->type == tk::TOKEN_RPARENS || i1->type == tk::TOKEN_RSQUARE ) {
1152 			--parens;
1153 		} else if(i1->type == tk::TOKEN_COMMA && !parens) {
1154 			res->push_back(parse_expression(beg, i1, symbols));
1155 			beg = i1+1;
1156 		}
1157 
1158 		++i1;
1159 	}
1160 
1161 	if(beg != i1) {
1162 		res->push_back(parse_expression(beg, i1, symbols));
1163 	}
1164 }
1165 
parse_set_args(const tk::token * i1,const tk::token * i2,std::vector<expression_ptr> * res,function_symbol_table * symbols)1166 static void parse_set_args(const tk::token* i1, const tk::token* i2,
1167                 std::vector<expression_ptr>* res,
1168 				function_symbol_table* symbols)
1169 {
1170 	int parens = 0;
1171 	bool check_pointer = false;
1172 	const tk::token* beg = i1;
1173 	const tk::token* begin = i1, *end = i2;	// These are used for error reporting
1174 	while(i1 != i2) {
1175 		if(i1->type == tk::TOKEN_LPARENS || i1->type == tk::TOKEN_LSQUARE) {
1176 			++parens;
1177 		} else if(i1->type == tk::TOKEN_RPARENS || i1->type == tk::TOKEN_RSQUARE) {
1178 			--parens;
1179 		} else if(i1->type == tk::TOKEN_POINTER && !parens ) {
1180 			if(!check_pointer) {
1181 				check_pointer = true;
1182 				res->push_back(parse_expression(beg, i1, symbols));
1183 				beg = i1+1;
1184 			} else {
1185 				throw formula_error("Too many '->' operators found", tokens_to_string(begin,end - 1), *i1->filename, i1->line_number);
1186 			}
1187 		} else if(i1->type == tk::TOKEN_COMMA && !parens ) {
1188 			if(check_pointer)
1189 				check_pointer = false;
1190 			else {
1191 				throw formula_error("Expected comma, but '->' found", tokens_to_string(begin,end - 1), *i1->filename, i1->line_number);
1192 			}
1193 			res->push_back(parse_expression(beg, i1, symbols));
1194 			beg = i1+1;
1195 		}
1196 
1197 		++i1;
1198 	}
1199 
1200 	if(beg != i1) {
1201 		res->push_back(parse_expression(beg, i1, symbols));
1202 	}
1203 }
1204 
parse_where_clauses(const tk::token * i1,const tk::token * i2,expr_table_ptr res,function_symbol_table * symbols)1205 static void parse_where_clauses(const tk::token* i1, const tk::token* i2, expr_table_ptr res, function_symbol_table* symbols)
1206 {
1207 	int parens = 0;
1208 	const tk::token* original_i1_cached = i1;
1209 	const tk::token* beg = i1;
1210 	const tk::token* begin = i1, *end = i2;	// These are used for error reporting
1211 	std::string var_name;
1212 
1213 	while(i1 != i2) {
1214 		if(i1->type == tk::TOKEN_LPARENS || i1->type == tk::TOKEN_LSQUARE) {
1215 			++parens;
1216 		} else if(i1->type == tk::TOKEN_RPARENS || i1->type == tk::TOKEN_RSQUARE) {
1217 			--parens;
1218 		} else if(!parens) {
1219 			if(i1->type == tk::TOKEN_COMMA) {
1220 				if(var_name.empty()) {
1221 					throw formula_error("There is 'where <expression>' but 'where name=<expression>' was needed",
1222 						tokens_to_string(begin, end - 1), *i1->filename, i1->line_number);
1223 				}
1224 
1225 				(*res)[var_name] = parse_expression(beg, i1, symbols);
1226 				beg = i1+1;
1227 				var_name = "";
1228 			} else if(i1->type == tk::TOKEN_OPERATOR) {
1229 				std::string op_name(i1->begin, i1->end);
1230 
1231 				if(op_name == "=") {
1232 					if(beg->type != tk::TOKEN_IDENTIFIER) {
1233 						if(i1 == original_i1_cached) {
1234 							throw formula_error("There is 'where <expression>' but 'where name=<expression>' was needed",
1235 								tokens_to_string(begin, end - 1), *i1->filename, i1->line_number);
1236 						} else {
1237 							throw formula_error("There is 'where <expression>=<expression>' but 'where name=<expression>' was needed",
1238 								tokens_to_string(begin, end - 1), *i1->filename, i1->line_number);
1239 						}
1240 					} else if(beg+1 != i1) {
1241 						throw formula_error("There is 'where name <expression>=<expression>' but 'where name=<expression>' was needed",
1242 							tokens_to_string(begin, end - 1), *i1->filename, i1->line_number);
1243 					} else if(!var_name.empty()) {
1244 						throw formula_error("There is 'where name=name=<expression>' but 'where name=<expression>' was needed",
1245 							tokens_to_string(begin, end - 1), *i1->filename, i1->line_number);
1246 					}
1247 
1248 					var_name.insert(var_name.end(), beg->begin, beg->end);
1249 					beg = i1+1;
1250 				}
1251 			}
1252 		}
1253 		++i1;
1254 	}
1255 
1256 	if(beg != i1) {
1257 		if(var_name.empty()) {
1258 			throw formula_error("There is 'where <expression>' but 'where name=<expression>' was needed",
1259 				tokens_to_string(begin, end - 1), *i1->filename, i1->line_number);
1260 		}
1261 
1262 		(*res)[var_name] = parse_expression(beg, i1, symbols);
1263 	}
1264 }
1265 
parse_expression(const tk::token * i1,const tk::token * i2,function_symbol_table * symbols)1266 expression_ptr parse_expression(const tk::token* i1, const tk::token* i2, function_symbol_table* symbols)
1267 {
1268 	if(i1 == i2) {
1269 		throw formula_error("Empty expression", "", *i1->filename, i1->line_number);
1270 	}
1271 
1272 	std::unique_ptr<function_symbol_table> temp_functions;
1273 	if(!symbols) {
1274 		temp_functions.reset(new function_symbol_table(function_symbol_table::get_builtins()));
1275 		symbols = temp_functions.get();
1276 	}
1277 
1278 	const tk::token* begin = i1, *end = i2;	// These are used for error reporting
1279 
1280 	if(i1->type == tk::TOKEN_KEYWORD && (i1 + 1)->type == tk::TOKEN_IDENTIFIER) {
1281 		if(std::string(i1->begin, i1->end) == "def") {
1282 			++i1;
1283 			const std::string formula_name = std::string(i1->begin, i1->end);
1284 
1285 			std::vector<std::string> args;
1286 			parse_function_args(++i1, i2, &args);
1287 
1288 			const tk::token* beg = i1;
1289 			while((i1 != i2) && (i1->type != tk::TOKEN_SEMICOLON)) {
1290 				++i1;
1291 			}
1292 
1293 			const std::string precond = "";
1294 			if(symbols == nullptr) {
1295 				throw formula_error("Function symbol table required but not present", "",*i1->filename, i1->line_number);
1296 			}
1297 
1298 			symbols->add_function(formula_name,
1299 				std::make_shared<user_formula_function>(
1300 					formula_name, std::make_shared<const formula>(beg, i1, symbols),
1301 					formula::create_optional_formula(precond, symbols), args
1302 				)
1303 			);
1304 
1305 			if((i1 == i2) || (i1 == (i2-1))) {
1306 				return std::make_shared<function_list_expression>(symbols);
1307 			} else {
1308 				return parse_expression((i1+1), i2, symbols);
1309 			}
1310 		}
1311 	}
1312 
1313 	int parens = 0;
1314 	const tk::token* op = nullptr;
1315 	bool operator_group = false;
1316 
1317 	for(const tk::token* i = i1; i != i2; ++i) {
1318 		if(i->type == tk::TOKEN_LPARENS || i->type == tk::TOKEN_LSQUARE) {
1319 			++parens;
1320 		} else if(i->type == tk::TOKEN_RPARENS || i->type == tk::TOKEN_RSQUARE) {
1321 			--parens;
1322 		} else if(parens == 0 && i->type == tk::TOKEN_OPERATOR) {
1323 			if((!operator_group ) && (op == nullptr || operator_precedence(*op) >= operator_precedence(*i))) {
1324 				// Need special exception for exponentiation to be right-associative
1325 				if(*i->begin != '^' || op == nullptr || *op->begin != '^') {
1326 					op = i;
1327 				}
1328 			}
1329 			operator_group = true;
1330 		} else {
1331 			operator_group = false;
1332 		}
1333 	}
1334 
1335 	if(op == nullptr) {
1336 		if(i1->type == tk::TOKEN_LPARENS && (i2-1)->type == tk::TOKEN_RPARENS) {
1337 			return parse_expression(i1+1,i2-1,symbols);
1338 		} else if((i2-1)->type == tk::TOKEN_RSQUARE) { //check if there is [ ] : either a list/map definition, or a operator
1339 			// First, a special case for an empty map
1340 			if(i2 - i1 == 3 && i1->type == tk::TOKEN_LSQUARE && (i1+1)->type == tk::TOKEN_POINTER) {
1341 				return std::make_shared<map_expression>(std::vector<expression_ptr>());
1342 			}
1343 
1344 			const tk::token* tok = i2-2;
1345 			int square_parens = 0;
1346 			bool is_map = false;
1347 			while ((tok->type != tk::TOKEN_LSQUARE || square_parens) && tok != i1) {
1348 				if(tok->type == tk::TOKEN_RSQUARE) {
1349 					square_parens++;
1350 				} else if(tok->type == tk::TOKEN_LSQUARE) {
1351 					square_parens--;
1352 				} else if((tok->type == tk::TOKEN_POINTER) && !square_parens ) {
1353 					is_map = true;
1354 				}
1355 				--tok;
1356 			}
1357 
1358 			if(tok->type == tk::TOKEN_LSQUARE) {
1359 				if(tok == i1) {
1360 					// Create a list or a map
1361 					std::vector<expression_ptr> args;
1362 
1363 					if( is_map ) {
1364 						parse_set_args(i1+1, i2-1, &args, symbols);
1365 						return std::make_shared<map_expression>(args);
1366 					} else {
1367 						parse_args(i1+1,i2-1,&args,symbols);
1368 						return std::make_shared<list_expression>(args);
1369 					}
1370 				} else {
1371 					// Execute operator [ ]
1372 					try{
1373 						return std::make_shared<square_bracket_expression>(
1374 							parse_expression(i1,      tok,    symbols),
1375 							parse_expression(tok + 1, i2 - 1, symbols)
1376 						);
1377 					} catch (const formula_error& e){
1378 						throw formula_error( e.type, tokens_to_string(i1, i2-1), *i1->filename, i1->line_number );
1379 					}
1380 				}
1381 			}
1382 		} else if(i2 - i1 == 1) {
1383 			if(i1->type == tk::TOKEN_KEYWORD) {
1384 				if(std::string(i1->begin, i1->end) == "functions") {
1385 					return std::make_shared<function_list_expression>(symbols);
1386 				}
1387 			} else if(i1->type == tk::TOKEN_IDENTIFIER) {
1388 				return std::make_shared<identifier_expression>(std::string(i1->begin, i1->end));
1389 			} else if(i1->type == tk::TOKEN_INTEGER) {
1390 				int n = std::stoi(std::string(i1->begin, i1->end));
1391 				return std::make_shared<integer_expression>(n);
1392 			} else if(i1->type == tk::TOKEN_DECIMAL) {
1393 				tk::iterator dot = i1->begin;
1394 				while(*dot != '.') {
1395 					++dot;
1396 				}
1397 
1398 				int n = std::stoi(std::string(i1->begin,dot));
1399 
1400 				tk::iterator literal_end = i1->end;
1401 
1402 				if(literal_end - dot > 4) {
1403 				   literal_end = dot + 4;
1404 				}
1405 
1406 				++dot;
1407 
1408 				int f = 0;
1409 
1410 				int multiplicator = 100;
1411 				while(dot != literal_end) {
1412 					f += (*dot - 48) * multiplicator;
1413 					multiplicator /= 10;
1414 					++dot;
1415 				}
1416 
1417 				return std::make_shared<decimal_expression>(n, f);
1418 			} else if(i1->type == tk::TOKEN_STRING_LITERAL) {
1419 				return std::make_shared<string_expression>(std::string(i1->begin + 1, i1->end - 1));
1420 			}
1421 		} else if(i1->type == tk::TOKEN_IDENTIFIER &&
1422 		          (i1+1)->type == tk::TOKEN_LPARENS &&
1423 				  (i2-1)->type == tk::TOKEN_RPARENS)
1424 		{
1425 			const tk::token* function_call_begin = i1, *function_call_end = i2;	// These are used for error reporting
1426 			int nleft = 0, nright = 0;
1427 			for(const tk::token* i = i1; i != i2; ++i) {
1428 				if(i->type == tk::TOKEN_LPARENS) {
1429 					++nleft;
1430 				} else if(i->type == tk::TOKEN_RPARENS) {
1431 					++nright;
1432 				}
1433 			}
1434 
1435 			if(nleft == nright) {
1436 				std::vector<expression_ptr> args;
1437 				parse_args(i1+2,i2-1,&args,symbols);
1438 				try{
1439 					return symbols->create_function(std::string(i1->begin, i1->end),args);
1440 				}
1441 				catch(const formula_error& e) {
1442 					throw formula_error(e.type, tokens_to_string(function_call_begin, function_call_end), *i1->filename, i1->line_number);
1443 				}
1444 			}
1445 		}
1446 
1447 		throw formula_error("Could not parse expression", tokens_to_string(i1, i2), *i1->filename, i1->line_number);
1448 	}
1449 
1450 	if(op + 1 == end) {
1451 		throw formula_error("Expected another token", tokens_to_string(begin, end - 1), *op->filename, op->line_number);
1452 	}
1453 
1454 	if(op == i1) {
1455 		try{
1456 			return expression_ptr(
1457 				new unary_operator_expression(std::string(op->begin, op->end), parse_expression(op + 1, i2 ,symbols)));
1458 		} catch(const formula_error& e)	{
1459 			throw formula_error( e.type, tokens_to_string(begin,end - 1), *op->filename, op->line_number);
1460 		}
1461 	}
1462 
1463 	const std::string op_name(op->begin,op->end);
1464 
1465 	if(op_name == ".") {
1466 		return expression_ptr(
1467 			new dot_expression(
1468 				parse_expression(i1,    op, symbols),
1469 				parse_expression(op + 1,i2, symbols)
1470 			)
1471 		);
1472 	}
1473 
1474 	if(op_name == "where") {
1475 		expr_table_ptr table(new expr_table());
1476 		parse_where_clauses(op+1, i2, table, symbols);
1477 
1478 		return std::make_shared<where_expression>(parse_expression(i1, op, symbols), table);
1479 	}
1480 
1481 	return expression_ptr(
1482 		new operator_expression(op_name,
1483 			parse_expression(i1,     op, symbols),
1484 			parse_expression(op + 1, i2, symbols)
1485 		)
1486 	);
1487 }
1488 
1489 } // namespace wfl
1490