1 #include <ail/string.hpp>
2 #include <frith/variable.hpp>
9 std::string
const zero_division_error_message
= "Zero division error";
12 unary_argument::unary_argument(variable
& output
, std::string
& error_message
):
14 error_message(error_message
)
18 binary_argument::binary_argument(variable
const & other
, variable
& output
, std::string
& error_message
):
21 error_message(error_message
)
26 type(variable_type_identifier::undefined
)
30 variable::variable(variable
const & other
):
35 case variable_type_identifier::boolean
:
36 boolean
= other
.boolean
;
39 case variable_type_identifier::signed_integer
:
40 signed_integer
= other
.signed_integer
;
43 case variable_type_identifier::unsigned_integer
:
44 unsigned_integer
= other
.unsigned_integer
;
47 case variable_type_identifier::floating_point_value
:
48 floating_point_value
= other
.floating_point_value
;
51 case variable_type_identifier::string
:
52 string
= new std::string(*other
.string
);
55 case variable_type_identifier::array
:
56 array
= new types::vector(*other
.array
);
59 case variable_type_identifier::map
:
60 map
= new types::map(*other
.map
);
69 case variable_type_identifier::string
:
73 case variable_type_identifier::array
:
77 case variable_type_identifier::map
:
83 variable_type
variable::get_type() const
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
)
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
)
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);
169 bool variable::perform_string_conversion(std::string
& output
, bool & error
) const
171 if(!get_string_representation(output
))
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
;
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
);
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); \
213 argument.output.new_signed_integer(signed_integer operator argument.other.signed_integer); \
217 argument.error_message = get_binary_argument_type_error(name_of_operation, type, argument.other.type); \
222 bool variable::addition(binary_argument
& argument
) const
224 std::string
const name_of_operation
= "Addition";
226 if(array_addition(argument
))
230 if(string_addition(argument
, string_error
))
235 argument
.error_message
= get_binary_argument_type_error(name_of_operation
, type
, argument
.other
.type
);
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
;
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
;
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
);
278 argument
.output
.new_signed_integer(signed_integer
% argument
.other
.signed_integer
);
282 argument
.error_message
= get_binary_argument_type_error(name_of_operation
, type
, argument
.other
.type
);
287 bool variable::negative(unary_argument
& argument
) const
289 argument
.output
.type
= type
;
292 case variable_type_identifier::signed_integer
:
293 argument
.output
.signed_integer
= - signed_integer
;
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
);
301 case variable_type_identifier::floating_point_value
:
302 argument
.output
.floating_point_value
= - floating_point_value
;
306 argument
.error_message
= "Cannot use unary minus on type " + get_type_string(type
);
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); \
321 argument.output.new_boolean(signed_integer operator argument.other.signed_integer); \
325 argument.error_message = get_binary_argument_type_error(name_of_operation, type, argument.other.type); \
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
));
360 bool variable::equal(binary_argument
& argument
) const
362 argument
.output
.new_boolean(operator==(argument
.other
));
366 bool variable::logical_not(unary_argument
& argument
) const
369 if(get_boolean_value(value
))
371 argument
.output
.new_boolean(!value
);
376 argument
.error_message
= get_unary_argument_type_error("Logical not", type
);
381 #define LOGICAL_OPERATOR(name, operator) \
385 if(get_boolean_value(left_value) && argument.other.get_boolean_value(right_value)) \
387 argument.output.new_boolean(left_value operator right_value); \
392 argument.error_message = get_unary_argument_type_error(name, type); \
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); \
414 argument.error_message = get_binary_argument_type_error(name, type, argument.other.type); \
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
);
452 argument
.error_message
= get_unary_argument_type_error("Binary not", type
);
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
465 type
== variable_type_identifier::signed_integer
||
466 type
== variable_type_identifier::unsigned_integer
;
469 bool variable::is_numeric_type() const
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
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
498 case variable_type_identifier::boolean
:
499 output
= ail::bool_to_string(boolean
);
502 case variable_type_identifier::signed_integer
:
503 output
= ail::number_to_string
<types::signed_integer
>(signed_integer
);
506 case variable_type_identifier::unsigned_integer
:
507 output
= ail::number_to_string
<types::unsigned_integer
>(unsigned_integer
);
510 case variable_type_identifier::floating_point_value
:
511 output
= ail::number_to_string
<types::floating_point_value
>(floating_point_value
);
521 bool variable::get_boolean_value(bool & output
) const
525 case variable_type_identifier::boolean
:
529 case variable_type_identifier::signed_integer
:
530 output
= signed_integer
!= 0;
533 case variable_type_identifier::unsigned_integer
:
534 output
= unsigned_integer
!= 0;
544 bool variable::is_zero() const
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
565 & other_vector
= *other
.array
;
567 std::size_t size
= vector
.size();
568 if(size
!= vector
.size())
571 for(std::size_t i
= 0; i
< size
; i
++)
573 if(vector
[i
] != other_vector
[i
])
580 bool variable::map_equality(variable
const & other
) const
584 & other_map
= *other
.map
;
586 if(this_map
.size() != other_map
.size())
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())
595 if(i
->second
!= iterator
->second
)
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();
609 return unsigned_integer
== other
.unsigned_integer
;
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
:
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();
659 type
== variable_type_identifier::unsigned_integer
&&
660 other
.type
== variable_type_identifier::unsigned_integer
662 return unsigned_integer
< other
.unsigned_integer
;
664 return signed_integer
< other
.signed_integer
;
666 else if(type
!= other
.type
)
667 return static_cast<word
>(type
) < static_cast<word
>(other
.type
);
670 if(type
== variable_type_identifier::string
)
671 return *string
< *other
.string
;
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
);
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
);
698 uword
variable::hash(uword previous_hash
) const
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
)
741 case variable_type_identifier::undefined
:
744 case variable_type_identifier::nil
:
747 case variable_type_identifier::boolean
:
750 case variable_type_identifier::signed_integer
:
753 case variable_type_identifier::unsigned_integer
:
754 return "unsigned-integer";
756 case variable_type_identifier::floating_point_value
:
759 case variable_type_identifier::string
:
762 case variable_type_identifier::array
:
765 case variable_type_identifier::map
:
768 case variable_type_identifier::function
:
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
);