Will I ever finish this?
[fridhskrift.git] / frith / variable.cpp
blobd625a35431db214f31df0ec539807457c2ae5ac0
1 #include <ail/string.hpp>
2 #include <frith/variable.hpp>
3 #include <fnv.hpp>
5 namespace frith
7 namespace
9 std::string const zero_division_error_message = "Zero division error";
12 unary_argument::unary_argument(variable & output, std::string & error_message):
13 output(output),
14 error_message(error_message)
18 binary_argument::binary_argument(variable const & other, variable & output, std::string & error_message):
19 other(other),
20 output(output),
21 error_message(error_message)
25 variable::variable():
26 type(variable_type_identifier::undefined)
30 variable::variable(variable const & other):
31 type(other.type)
33 switch(type)
35 case variable_type_identifier::boolean:
36 boolean = other.boolean;
37 break;
39 case variable_type_identifier::signed_integer:
40 signed_integer = other.signed_integer;
41 break;
43 case variable_type_identifier::unsigned_integer:
44 unsigned_integer = other.unsigned_integer;
45 break;
47 case variable_type_identifier::floating_point_value:
48 floating_point_value = other.floating_point_value;
49 break;
51 case variable_type_identifier::string:
52 string = new std::string(*other.string);
53 break;
55 case variable_type_identifier::array:
56 array = new types::vector(*other.array);
57 break;
59 case variable_type_identifier::map:
60 map = new types::map(*other.map);
61 break;
65 variable::~variable()
67 switch(type)
69 case variable_type_identifier::string:
70 delete string;
71 break;
73 case variable_type_identifier::array:
74 delete array;
75 break;
77 case variable_type_identifier::map:
78 delete map;
79 break;
83 variable_type variable::get_type() const
85 return type;
88 void variable::nil()
90 type = variable_type_identifier::nil;
93 void variable::new_boolean(types::boolean new_boolean)
95 type = variable_type_identifier::boolean;
96 boolean = new_boolean;
99 void variable::new_signed_integer(types::signed_integer new_signed_integer)
101 type = variable_type_identifier::signed_integer;
102 signed_integer = new_signed_integer;
105 void variable::new_unsigned_integer(types::unsigned_integer new_unsigned_integer)
107 type = variable_type_identifier::unsigned_integer;
108 unsigned_integer = new_unsigned_integer;
111 void variable::new_floating_point_value(types::floating_point_value new_floating_point_value)
113 type = variable_type_identifier::floating_point_value;
114 floating_point_value = new_floating_point_value;
117 void variable::new_string(types::string const & new_string)
119 type = variable_type_identifier::string;
120 string = new std::string(new_string);
123 void variable::new_array()
125 type = variable_type_identifier::array;
126 array = new types::vector();
129 void variable::new_map()
131 type = variable_type_identifier::map;
132 map = new types::map();
135 bool variable::array_addition(binary_argument & argument) const
137 bool left_is_array = type == variable_type_identifier::array;
138 bool right_is_array = argument.other.type == variable_type_identifier::array;
140 if(left_is_array || right_is_array)
142 argument.output.type = variable_type_identifier::array;
143 argument.output.array = new types::vector;
144 types::vector & vector = *argument.output.array;
146 if(left_is_array && right_is_array)
148 vector = *array;
149 types::vector & right_vector = *argument.other.array;
150 vector.insert(vector.end(), right_vector.begin(), right_vector.end());
152 else if(left_is_array && !right_is_array)
154 vector = *array;
155 vector.push_back(argument.other);
157 else if(!left_is_array && right_is_array)
159 vector = *argument.other.array;
160 vector.push_back(*this);
163 else
164 return false;
166 return true;
169 bool variable::perform_string_conversion(std::string & output, bool & error) const
171 if(!get_string_representation(output))
173 error = true;
174 return false;
176 else
177 return true;
180 bool variable::string_addition(binary_argument & argument, bool & error) const
182 bool left_is_string = type == variable_type_identifier::string;
183 bool right_is_string = argument.other.type == variable_type_identifier::string;
185 error = false;
187 if(left_is_string || right_is_string)
189 argument.output.type = variable_type_identifier::string;
190 argument.output.string = new std::string;
191 std::string & output_string = *argument.output.string;
192 if(left_is_string && right_is_string)
193 output_string = *string + *argument.other.string;
194 else if(left_is_string && !right_is_string)
195 return argument.other.perform_string_conversion(output_string, error);
196 else if(!left_is_string && right_is_string)
197 return perform_string_conversion(output_string, error);
199 else
200 return false;
202 return true;
205 #define ARITHMETIC_OPERATION(operator) \
206 if(is_numeric_type() && argument.other.is_numeric_type()) \
208 if(is_floating_point_operation(argument)) \
209 argument.output.new_floating_point_value(get_floating_point_value() operator argument.other.get_floating_point_value()); \
210 else if(type == variable_type_identifier::unsigned_integer && argument.other.type == variable_type_identifier::unsigned_integer) \
211 argument.output.new_unsigned_integer(unsigned_integer operator argument.other.unsigned_integer); \
212 else \
213 argument.output.new_signed_integer(signed_integer operator argument.other.signed_integer); \
215 else \
217 argument.error_message = get_binary_argument_type_error(name_of_operation, type, argument.other.type); \
218 return false; \
220 return true;
222 bool variable::addition(binary_argument & argument) const
224 std::string const name_of_operation = "Addition";
226 if(array_addition(argument))
227 return true;
229 bool string_error;
230 if(string_addition(argument, string_error))
231 return true;
233 if(string_error)
235 argument.error_message = get_binary_argument_type_error(name_of_operation, type, argument.other.type);
236 return false;
239 ARITHMETIC_OPERATION(+)
242 bool variable::subtraction(binary_argument & argument) const
244 std::string const name_of_operation = "Subtraction";
245 ARITHMETIC_OPERATION(-)
248 bool variable::multiplication(binary_argument & argument) const
250 std::string const name_of_operation = "Multiplication";
251 ARITHMETIC_OPERATION(*)
254 bool variable::division(binary_argument & argument) const
256 std::string const name_of_operation = "Division";
257 if(argument.other.is_zero())
259 argument.error_message = zero_division_error_message;
260 return false;
262 ARITHMETIC_OPERATION(/)
265 bool variable::modulo(binary_argument & argument) const
267 std::string const name_of_operation = "Modulo";
268 if(argument.other.is_zero())
270 argument.error_message = zero_division_error_message;
271 return false;
273 else if(is_integer_type() && argument.other.is_integer_type())
275 if(type == variable_type_identifier::unsigned_integer && argument.other.type == variable_type_identifier::unsigned_integer)
276 argument.output.new_unsigned_integer(unsigned_integer % argument.other.unsigned_integer);
277 else
278 argument.output.new_signed_integer(signed_integer % argument.other.signed_integer);
280 else
282 argument.error_message = get_binary_argument_type_error(name_of_operation, type, argument.other.type);
283 return false;
287 bool variable::negative(unary_argument & argument) const
289 argument.output.type = type;
290 switch(type)
292 case variable_type_identifier::signed_integer:
293 argument.output.signed_integer = - signed_integer;
294 break;
296 case variable_type_identifier::unsigned_integer:
297 argument.output.type = variable_type_identifier::signed_integer;
298 argument.output.signed_integer = - static_cast<types::signed_integer>(unsigned_integer);
299 break;
301 case variable_type_identifier::floating_point_value:
302 argument.output.floating_point_value = - floating_point_value;
303 break;
305 default:
306 argument.error_message = "Cannot use unary minus on type " + get_type_string(type);
307 return false;
310 return true;
313 #define NUMERIC_COMPARISON(operator) \
314 if(is_numeric_type() && argument.other.is_numeric_type()) \
316 if(is_floating_point_operation(argument)) \
317 argument.output.new_boolean(get_floating_point_value() operator argument.other.get_floating_point_value()); \
318 else if(type == variable_type_identifier::unsigned_integer && argument.other.type == variable_type_identifier::signed_integer) \
319 argument.output.new_boolean(unsigned_integer operator argument.other.unsigned_integer); \
320 else \
321 argument.output.new_boolean(signed_integer operator argument.other.signed_integer); \
323 else \
325 argument.error_message = get_binary_argument_type_error(name_of_operation, type, argument.other.type); \
326 return false; \
328 return true;
330 bool variable::less_than(binary_argument & argument) const
332 std::string const name_of_operation = "Less than";
333 NUMERIC_COMPARISON(<=)
336 bool variable::less_than_or_equal(binary_argument & argument) const
338 std::string const name_of_operation = "Less than or equal";
339 NUMERIC_COMPARISON(<=)
342 bool variable::greater_than(binary_argument & argument) const
344 std::string const name_of_operation = "Greater than";
345 NUMERIC_COMPARISON(<=)
348 bool variable::greater_than_or_equal(binary_argument & argument) const
350 std::string const name_of_operation = "Greater than or equal";
351 NUMERIC_COMPARISON(<=)
354 bool variable::unequal(binary_argument & argument) const
356 argument.output.new_boolean(operator!=(argument.other));
357 return true;
360 bool variable::equal(binary_argument & argument) const
362 argument.output.new_boolean(operator==(argument.other));
363 return true;
366 bool variable::logical_not(unary_argument & argument) const
368 bool value;
369 if(get_boolean_value(value))
371 argument.output.new_boolean(!value);
372 return true;
374 else
376 argument.error_message = get_unary_argument_type_error("Logical not", type);
377 return false;
381 #define LOGICAL_OPERATOR(name, operator) \
382 bool \
383 left_value, \
384 right_value; \
385 if(get_boolean_value(left_value) && argument.other.get_boolean_value(right_value)) \
387 argument.output.new_boolean(left_value operator right_value); \
388 return true; \
390 else \
392 argument.error_message = get_unary_argument_type_error(name, type); \
393 return false; \
396 bool variable::logical_and(binary_argument & argument) const
398 LOGICAL_OPERATOR("Logical and", &&)
401 bool variable::logical_or(binary_argument & argument) const
403 LOGICAL_OPERATOR("Logical or", ||)
406 #define BINARY_OPERATOR(name, operator) \
407 if(is_integer_type() && argument.other.is_integer_type()) \
409 argument.output.new_unsigned_integer(unsigned_integer operator argument.other.unsigned_integer); \
410 return true; \
412 else \
414 argument.error_message = get_binary_argument_type_error(name, type, argument.other.type); \
415 return false; \
418 bool variable::shift_left(binary_argument & argument) const
420 BINARY_OPERATOR("Shift left", <<)
423 bool variable::shift_right(binary_argument & argument) const
425 BINARY_OPERATOR("Shift right", >>)
428 bool variable::binary_and(binary_argument & argument) const
430 BINARY_OPERATOR("Binary and", &)
433 bool variable::binary_or(binary_argument & argument) const
435 BINARY_OPERATOR("Binary or", |)
438 bool variable::binary_xor(binary_argument & argument) const
440 BINARY_OPERATOR("Binary exclusive or", ^)
443 bool variable::binary_not(unary_argument & argument) const
445 if(is_integer_type())
447 argument.output.new_unsigned_integer(~unsigned_integer);
448 return true;
450 else
452 argument.error_message = get_unary_argument_type_error("Binary not", type);
453 return false;
457 bool variable::is_floating_point_operation(binary_argument & argument) const
459 return type == variable_type_identifier::floating_point_value || argument.other.type == variable_type_identifier::floating_point_value;
462 bool variable::is_integer_type() const
464 return
465 type == variable_type_identifier::signed_integer ||
466 type == variable_type_identifier::unsigned_integer;
469 bool variable::is_numeric_type() const
471 return
472 type == variable_type_identifier::signed_integer ||
473 type == variable_type_identifier::unsigned_integer ||
474 type == variable_type_identifier::floating_point_value;
477 types::floating_point_value variable::get_floating_point_value() const
479 switch(type)
481 case variable_type_identifier::signed_integer:
482 return signed_integer;
484 case variable_type_identifier::unsigned_integer:
485 return unsigned_integer;
487 case variable_type_identifier::floating_point_value:
488 return floating_point_value;
491 throw ail::exception("Failed to retrieve floating point value");
494 bool variable::get_string_representation(std::string & output) const
496 switch(type)
498 case variable_type_identifier::boolean:
499 output = ail::bool_to_string(boolean);
500 break;
502 case variable_type_identifier::signed_integer:
503 output = ail::number_to_string<types::signed_integer>(signed_integer);
504 break;
506 case variable_type_identifier::unsigned_integer:
507 output = ail::number_to_string<types::unsigned_integer>(unsigned_integer);
508 break;
510 case variable_type_identifier::floating_point_value:
511 output = ail::number_to_string<types::floating_point_value>(floating_point_value);
512 break;
514 default:
515 return false;
518 return true;
521 bool variable::get_boolean_value(bool & output) const
523 switch(type)
525 case variable_type_identifier::boolean:
526 output = boolean;
527 break;
529 case variable_type_identifier::signed_integer:
530 output = signed_integer != 0;
531 break;
533 case variable_type_identifier::unsigned_integer:
534 output = unsigned_integer != 0;
535 break;
537 default:
538 return false;
541 return true;
544 bool variable::is_zero() const
546 switch(type)
548 case variable_type_identifier::signed_integer:
549 return signed_integer == 0;
551 case variable_type_identifier::unsigned_integer:
552 return unsigned_integer == 0;
554 case variable_type_identifier::floating_point_value:
555 return floating_point_value == 0.0;
558 throw ail::exception("Unable to check if variable is zero");
561 bool variable::array_equality(variable const & other) const
563 types::vector
564 & vector = *array,
565 & other_vector = *other.array;
567 std::size_t size = vector.size();
568 if(size != vector.size())
569 return false;
571 for(std::size_t i = 0; i < size; i++)
573 if(vector[i] != other_vector[i])
574 return false;
577 return true;
580 bool variable::map_equality(variable const & other) const
582 types::map
583 & this_map = *map,
584 & other_map = *other.map;
586 if(this_map.size() != other_map.size())
587 return false;
589 for(types::map::const_iterator i = this_map.begin(), end = this_map.end(); i != end; i++)
591 types::map::const_iterator iterator = other_map.find(i->first);
592 if(iterator == other_map.end())
593 return false;
595 if(i->second != iterator->second)
596 return false;
599 return true;
602 bool variable::operator==(variable const & other) const
604 if(is_numeric_type() && other.is_numeric_type())
606 if(type == variable_type_identifier::floating_point_value || other.type == variable_type_identifier::floating_point_value)
607 return get_floating_point_value() == other.get_floating_point_value();
608 else
609 return unsigned_integer == other.unsigned_integer;
611 else
613 switch(type)
615 case variable_type_identifier::nil:
616 return type == other.type;
618 case variable_type_identifier::boolean:
619 return type == other.type && boolean == other.boolean;
621 case variable_type_identifier::string:
622 return type == other.type && *string == *other.string;
624 case variable_type_identifier::array:
625 return array_equality(other);
627 case variable_type_identifier::map:
628 return map_equality(other);
630 case variable_type_identifier::function:
631 throw ail::exception("Comparison of functions has not been implemented yet");
633 case variable_type_identifier::signed_integer:
634 case variable_type_identifier::unsigned_integer:
635 case variable_type_identifier::floating_point_value:
636 default:
637 return false;
642 bool variable::operator!=(variable const & other) const
644 return !operator==(other);
647 bool variable::operator<(variable const & other) const
649 if(is_numeric_type() && other.is_numeric_type())
653 type == variable_type_identifier::floating_point_value ||
654 other.type == variable_type_identifier::floating_point_value
656 return get_floating_point_value() < other.get_floating_point_value();
657 else if
659 type == variable_type_identifier::unsigned_integer &&
660 other.type == variable_type_identifier::unsigned_integer
662 return unsigned_integer < other.unsigned_integer;
663 else
664 return signed_integer < other.signed_integer;
666 else if(type != other.type)
667 return static_cast<word>(type) < static_cast<word>(other.type);
668 else
670 if(type == variable_type_identifier::string)
671 return *string < *other.string;
672 else
679 uword variable::array_hash(uword previous_hash) const
681 uword hash = previous_hash;
682 for(types::vector::iterator i = array->begin(), end = array->end(); i != end; i++)
683 hash = i->hash(hash);
684 return hash;
687 uword variable::map_hash(uword previous_hash) const
689 uword hash = previous_hash;
690 for(types::map::iterator i = map->begin(), end = map->end(); i != end; i++)
692 hash = i->first.hash(hash);
693 hash = i->second.hash(hash);
695 return hash;
698 uword variable::hash(uword previous_hash) const
700 switch(type)
702 case variable_type_identifier::undefined:
703 throw ail::exception("Attempted to calculate the hash of an undefined variable");
705 case variable_type_identifier::nil:
707 std::string const value = "nil";
708 return fnv1a_hash(value.c_str(), value.size(), previous_hash);
711 case variable_type_identifier::boolean:
712 return fnv1a_hash(hash_pointer, sizeof(types::signed_integer), previous_hash);
714 case variable_type_identifier::signed_integer:
715 return fnv1a_hash(hash_pointer, sizeof(types::signed_integer), previous_hash);
717 case variable_type_identifier::unsigned_integer:
718 return fnv1a_hash(hash_pointer, sizeof(types::unsigned_integer), previous_hash);
720 case variable_type_identifier::floating_point_value:
721 return fnv1a_hash(hash_pointer, sizeof(types::floating_point_value), previous_hash);
723 case variable_type_identifier::string:
724 return fnv1a_hash(string->c_str(), string->size(), previous_hash);
726 case variable_type_identifier::array:
727 return array_hash(previous_hash);
729 case variable_type_identifier::map:
730 return map_hash(previous_hash);
732 case variable_type_identifier::function:
733 throw ail::exception("Hashing for functions has not been implemented yet");
737 std::string get_type_string(variable_type type)
739 switch(type)
741 case variable_type_identifier::undefined:
742 return "undefined";
744 case variable_type_identifier::nil:
745 return "nil";
747 case variable_type_identifier::boolean:
748 return "boolean";
750 case variable_type_identifier::signed_integer:
751 return "integer";
753 case variable_type_identifier::unsigned_integer:
754 return "unsigned-integer";
756 case variable_type_identifier::floating_point_value:
757 return "float";
759 case variable_type_identifier::string:
760 return "string";
762 case variable_type_identifier::array:
763 return "array";
765 case variable_type_identifier::map:
766 return "map";
768 case variable_type_identifier::function:
769 return "function";
772 return "unknown";
775 std::string get_unary_argument_type_error(std::string const & operation, variable_type type)
777 return operation + ": Invalid argument type \"" + get_type_string(type) + "\"";
780 std::string get_binary_argument_type_error(std::string const & operation, variable_type left, variable_type right)
782 return operation + ": Invalid argument types \"" + get_type_string(left) + "\", \"" + get_type_string(right);