/* G-Cows - scripting language for creation of web sites Copyright (C) 2002, 2003, 2004, 2005, 2006 Andrea Sozzi This file is part of G-Cows. G-Cows is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. G-Cows is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "variables.H" #include "error.H" #include "Xmalloc.H" void Gen_type::fix_list () { if (type == 'i') arr_value.push_back (int_value); else if (type == 'c') arr_value.push_back (str_value); type = 'a'; } string Gen_type::get_string () const { if (type != 'c') Msg::inst()->fatal ("Gen_type::get_string () -- Internal Error"); return str_value; } int Gen_type::get_int () const { if (type != 'i') Msg::inst()->fatal ("Gen_type::get_int () -- Internal Error"); return int_value; } const Gen_type_vector * Gen_type::get_array () const { if (type != 'a') Msg::inst()->fatal ("Gen_type::get_array () -- Internal Error"); return &arr_value; } const Gen_type_vector * Gen_type::get_list () const { if (type != 'l') Msg::inst()->fatal ("Gen_type::get_list () -- Internal Error"); return &arr_value; } void Gen_type::push_items (Gen_type value) { if (value.is_array () || value.is_list ()) arr_value.insert (arr_value.end (), value.arr_value.begin (), value.arr_value.end ()); else arr_value.push_back (value); } Gen_type::operator bool () const { switch (type) { case 'i': return int_value != 0; break; case 'c': return str_value != ""; break; case 'a': return arr_value.size () != 0; break; case 'u': return false; default: Msg::inst()->fatal ("Gen_type::bool () Internal error"); return Gen_type (-1); break; } } Gen_type Gen_type::operator>(const Gen_type& right_val) const { if (is_array () || right_val.is_array ()) { // At least one is an array Msg::inst()->error (">; can't compare arrays"); return Gen_type (0); } if (type != right_val.type) { Msg::inst()->error (">; can't compare operands of different types"); return Gen_type (0); } if (type == 'i') return Gen_type (int_value > right_val.int_value); if (type == 'c') return Gen_type (str_value > right_val.str_value); if (type == 'u') return Gen_type (false); Msg::inst()->fatal ("Gen_type::>: Internal error"); return Gen_type (0); } Gen_type Gen_type::operator<(const Gen_type& right_val) const { if (is_array () || right_val.is_array ()) { // At least one is an array Msg::inst()->error ("<: Can't compare arrays"); return Gen_type (0); } if (type != right_val.type) { Msg::inst()->error (">; can't compare operands of different types"); return Gen_type (0); } if (type == 'i') return Gen_type (int_value < right_val.int_value); if (type == 'c') return Gen_type (str_value < right_val.str_value); if (type == 'u') return Gen_type (false); Msg::inst()->fatal ("Gen_type::<: Internal error"); return Gen_type (0); } Gen_type Gen_type::operator>=(const Gen_type& right_val) const { if (is_array () || right_val.is_array ()) { // At least one is an array Msg::inst()->error (">=: Can't compare arrays"); return Gen_type (0); } if (type != right_val.type) { Msg::inst()->error (">=; can't compare operands of different types"); return Gen_type (0); } if (type == 'i') return Gen_type (int_value >= right_val.int_value); if (type == 'c') return Gen_type (str_value >= right_val.str_value); if (type == 'u') return Gen_type (true); Msg::inst()->fatal ("Gen_type::>=: Internal error"); return Gen_type (0); } Gen_type Gen_type::operator<=(const Gen_type& right_val) const { if (is_array () || right_val.is_array ()) { // At least one is an array Msg::inst()->error ("<=: Can't compare arrays"); return Gen_type (0); } if (type != right_val.type) { Msg::inst()->error ("<=; can't compare operands of different types"); return Gen_type (0); } if (type == 'i') return Gen_type (int_value <= right_val.int_value); if (type == 'c') return Gen_type (str_value <= right_val.str_value); if (type == 'u') return Gen_type (true); Msg::inst()->fatal ("Gen_type::<=: Internal error"); return Gen_type (-1); } Gen_type Gen_type::operator==(const Gen_type& right_val) const { if (type == 'i') return Gen_type (int_value == right_val.int_value); if (type == 'c') return Gen_type (str_value == right_val.str_value); if (type == 'a') return Gen_type (arr_value == right_val.arr_value); if (type == 'u') return Gen_type (true); Msg::inst()->fatal ("Gen_type::==|~==: Internal error"); return Gen_type (-1); } Gen_type Gen_type::weak_eq (const Gen_type& right_val) const { if (type == right_val.type) { if (type != 'a') return *this == right_val; if (arr_value.size () != right_val.arr_value.size ()) return Gen_type (0); Gen_type_c_iter j = right_val.arr_value.begin (); for (Gen_type_c_iter i = arr_value.begin (); i != arr_value.end (); i++, j++) { if (! (i->weak_eq (*j))) return Gen_type (0); } return Gen_type (1); } // Since now operands have different types: if (type == 'a' || right_val.type == 'a') { Msg::inst()->warning ("~==: can't compare array with scalar type; comparison FALSE", "~==: compare array with scalar; FALSE"); return Gen_type (0); } switch (type) { case 'i': if (right_val.is_string ()) return Gen_type (itoa (int_value)) == right_val; else if (right_val.is_undefined ()) return *this == Gen_type (0); break; case 'c': if (right_val.is_int ()) return *this == Gen_type (itoa (right_val.int_value)); else if (right_val.is_undefined ()) return *this == Gen_type (""); break; case 'u': if (right_val.is_int ()) return Gen_type (0) == right_val; else if (right_val.is_string ()) return Gen_type ("") == right_val; break; default: Msg::inst()->fatal ("Gen_type::~==: Internal error"); } Msg::inst()->fatal ("Gen_type::~==: Internal error"); return Gen_type (-1); } Gen_type Gen_type::operator!=(const Gen_type& right_val) const { if (type == 'i') return Gen_type (int_value != right_val.int_value); if (type == 'c') return Gen_type (str_value != right_val.str_value); if (type == 'a') return Gen_type ( arr_value != right_val.arr_value); if (type == 'u') return Gen_type (false); Msg::inst()->fatal ("Gen_type::!=: Internal error"); return Gen_type (-1); } Gen_type Gen_type::weak_neq (const Gen_type& right_val) const { if (type == right_val.type) { if (type != 'a') return *this != right_val; if (arr_value.size () != right_val.arr_value.size ()) return Gen_type (1); Gen_type_c_iter j = right_val.arr_value.begin (); for (Gen_type_c_iter i = arr_value.begin (); i != arr_value.end (); i++, j++) { if (! (i->weak_neq (*j))) return Gen_type (0); } return Gen_type (1); } // Since now operands have different types: if (type == 'a' || right_val.type == 'a') { Msg::inst()->warning ( "~!=: can't compare array with scalar type; comparison TRUE", "~!=: compare array with scalar; TRUE"); return Gen_type (1); } switch (type) { case 'i': if (right_val.is_string ()) return Gen_type (itoa (int_value)) != right_val; else if (right_val.is_undefined ()) return *this != Gen_type (0); break; case 'c': if (right_val.is_int ()) return *this != Gen_type (itoa (right_val.int_value)); else if (right_val.is_undefined ()) return *this != Gen_type (""); break; case 'u': if (right_val.is_int ()) return Gen_type (0) != right_val; else if (right_val.is_string ()) return Gen_type ("") != right_val; break; default: Msg::inst()->fatal ("Gen_type::~==: Internal error"); } return Gen_type (-1); } Gen_type Gen_type::operator+(const Gen_type& right_val) const { if (is_array () || right_val.is_array () || is_list () || right_val.is_list ()) { // At least one is an array or a list Gen_type ret_value ('a'); ret_value.push_items (*this); ret_value.push_items (right_val); return ret_value; } else { // None of the expressions is an array switch (type) { case 'i': if (right_val.is_int ()) return Gen_type (int_value + right_val.int_value); else if (right_val.is_string ()) return Gen_type (string (itoa (int_value)) + right_val.str_value); else if (right_val.is_undefined ()) return *this; break; case 'c': if (right_val.is_int ()) return Gen_type (str_value + string (itoa (right_val.int_value))); else if (right_val.is_string ()) return Gen_type (str_value + right_val.str_value); else if (right_val.is_undefined ()) return *this; break; case 'u': return right_val; break; default: Msg::inst()->fatal ("Gen_type::+: Internal error"); } Msg::inst()->fatal ("Gen_type::+: Internal error"); return Gen_type (-1); } } Gen_type Gen_type::operator-(const Gen_type& right_val) const { if ( !(is_int () || is_undefined ()) ) { Msg::inst()->error ("operator -; first operand has bad type"); return Gen_type (-1); } if ( !(right_val.is_int () || right_val.is_undefined ()) ) { Msg::inst()->error ("operator -; second operand has bad type"); return Gen_type (-1); } int first_operand = is_int () ? int_value : 0; int second_operand = right_val.is_int () ? right_val.int_value : 0; return Gen_type (first_operand - second_operand); } Gen_type Gen_type::operator-() const { switch (type) { case 'i': return Gen_type (- int_value); break; case 'c': Msg::inst()->error ("-: Can't negate a string variable"); return Gen_type (str_value); break; case 'a': Msg::inst()->error ("-: Can't negate an array variable"); return Gen_type (str_value); break; case 'u': return *this; default: Msg::inst()->fatal ("Gen_type::- Internal error"); return Gen_type (0); break; } } Gen_type Gen_type::operator*(const Gen_type& right_val) const { if ( ! (is_int () || is_undefined () || right_val.is_int () || right_val.is_undefined ())) { Msg::inst()->error ("operator *; bad type(s)"); return Gen_type (-1); } switch (type) { case 'i': if (right_val.is_int ()) return Gen_type (int_value * right_val.int_value); else if (right_val.is_string ()) { string ret_value; for (int i=0; iget_string (); return Gen_type (ret_value); } else if (right_val.is_undefined ()) return Gen_type (""); break; case 'a': if (right_val.is_int ()) { Gen_type ret_value ('a'); for (int i=0; ifatal ("Gen_type::operator*; Internal Error"); } Msg::inst()->fatal ("Gen_type::operator*; Internal Error"); return Gen_type (-1); } Gen_type Gen_type::operator/(const Gen_type& right_val) const { if ( !(is_int () || is_undefined ()) ) { Msg::inst()->error ("operator /; first operand has bad type"); return Gen_type (-1); } if ( !(right_val.is_int () || right_val.is_undefined ()) ) { Msg::inst()->error ("operator /; second operand has bad type"); return Gen_type (-1); } int first_operand = is_int () ? int_value : 0; int second_operand = right_val.is_int () ? right_val.int_value : 0; if (!second_operand) { Msg::inst()->error ("operator /; division by 0"); return Gen_type (-1); } return Gen_type (first_operand / second_operand); } Gen_type Gen_type::operator%(const Gen_type& right_val) const { if ( !(is_int () || is_undefined ()) ) { Msg::inst()->error ("operator /; first operand has bad type"); return Gen_type (-1); } if ( !(right_val.is_int () || right_val.is_undefined ()) ) { Msg::inst()->error ("operator /; second operand has bad type"); return Gen_type (-1); } int first_operand = is_int () ? int_value : 0; int second_operand = right_val.is_int () ? right_val.int_value : 0; if (!second_operand) { Msg::inst()->error ("operator /; division by 0"); return Gen_type (-1); } return Gen_type (first_operand % second_operand); } Gen_type Gen_type::operator^(const Gen_type& right_val) const { if ( !(is_int () || is_undefined ()) ) { Msg::inst()->error ("operator /; first operand has bad type"); return Gen_type (-1); } if ( !(right_val.is_int () || right_val.is_undefined ()) ) { Msg::inst()->error ("operator /; second operand has bad type"); return Gen_type (-1); } int first_operand = is_int () ? int_value : 0; int second_operand = right_val.is_int () ? right_val.int_value : 0; return Gen_type ((int) pow (first_operand, second_operand)); } // Conversion bool Gen_type::to_bool () { if (is_int ()) return (int_value != 0); else if (is_string ()) return (str_value != ""); else if (is_array ()) return ! arr_value.empty (); else if (is_undefined ()) return 0; else { Msg::inst()->fatal ("Gen_type::to_bool () -- Internal Error"); return 0; } } int Gen_type::to_int () { if (is_int ()) return int_value; else if (is_string ()) return atoi (str_value.c_str ()); else if (is_array ()) return arr_value.size (); else if (is_undefined ()) return 0; else { Msg::inst()->fatal ("Gen_type::to_int () -- Internal Error"); return 0; } } string Gen_type::to_string (bool scalar_only) const { if (is_int ()) return itoa (int_value); else if (is_string ()) return str_value; else if (is_array ()) { if (scalar_only) { Msg::inst()->error ("Arrays not allowed within this context"); return ""; } string res = "{ "; for (Gen_type_c_iter i = arr_value.begin (); i != arr_value.end (); i++) { if (i != arr_value.begin ()) res += ", "; res += i->to_string (); } return res + " }"; } else if (is_undefined ()) return ""; else { Msg::inst()->fatal ("Gen_type::to_string () -- Internal Error"); return ""; } } Gen_type Gen_type::get_element (Gen_type index) { if (! index.is_int ()) { Msg::inst()->error ("index must be an integer"); return Gen_type (-1); } unsigned int index_int = index.int_value; if (arr_value.empty ()) { Msg::inst()->warning ("Empty Array"); return Gen_type (-1); } if (index_int > arr_value.size () - 1) { Msg::inst()->warning ("Array index out of bound", "Out of bound"); return Gen_type (-1); } return arr_value [index_int]; } Gen_type Gen_type::set_element (Gen_type value) { arr_value.push_back (value); return value; } Gen_type Gen_type::set_element (Gen_type index, Gen_type value, bool shift) { if (! index.is_int ()) { Msg::inst()->error ("index must be an integer"); return Gen_type (-1); } int index_int = index.int_value; int n_elements = arr_value.size (); if (index_int > n_elements - 1) { // Array has less than INDEX elements ... let's insert empty elements for (int i=0; i < index_int - n_elements; i++) arr_value.push_back (Gen_type ("")); arr_value.push_back (value); } else { if (shift) { // Array has [more than] INDEX elements and shift is true ... // let's jump to INDEX and set the element Gen_type_iter it = arr_value.begin () + index_int; arr_value.insert (it, value); } else arr_value [index_int] = value; } return value; } void Gen_type::erase (unsigned int pos) { if (! is_array ()) Msg::inst()->fatal ("Gen_type::erase called on non array variable"); if (pos > arr_value.size () - 1) Msg::inst()->warning ("Array index out of bound", "Out of bound"); else arr_value.erase (arr_value.begin () + pos); } void Gen_type::erase (unsigned int pos, unsigned int len) { if (! is_array ()) Msg::inst()->fatal ("Gen_type::erase called on non array variable"); if (pos + len > arr_value.size () - 1) Msg::inst()->warning ("Array index out of bound", "Out of bound"); else arr_value.erase (arr_value.begin () + pos, arr_value.begin () + pos + len); } Variables::Variables () { Gen_type months = Gen_type ('a'); months.set_element (0, "January"); months.set_element (1, "February"); months.set_element (2, "March"); months.set_element (3, "April"); months.set_element (4, "May"); months.set_element (5, "June"); months.set_element (6, "July"); months.set_element (7, "August"); months.set_element (8, "September"); months.set_element (9, "October"); months.set_element (10, "November"); months.set_element (11, "December"); vars.insert (make_pair (string ("_months"), months)); Gen_type days = Gen_type ('a'); days.set_element (0, "Sunday"); days.set_element (1, "Monday"); days.set_element (2, "Tuesday"); days.set_element (3, "Wednesday"); days.set_element (4, "Thursday"); days.set_element (5, "Friday"); days.set_element (6, "Saturday"); vars.insert (make_pair (string ("_days"), days)); } /* Define a variable called NAME and store VALUE within. Return VALUE */ Gen_type Variables::set_var (string name, Gen_type value) { Var_iterator iter; // If a variable with the same already exist we erase it if ( ( iter = vars.find (name) ) != vars.end () ) vars.erase (iter); vars.insert (make_pair (name, value)); return value; } /* Given a string NAME = VALUE, define a variable called NAME and store VALUE within. Return VALUE or empty string in case of failure */ Gen_type Variables::set_var (string assignment) { unsigned int eq_pos; if ((eq_pos = assignment.find ('=')) != string::npos) { string name = assignment.substr (0, eq_pos); string value = assignment.substr (eq_pos+1, assignment.length()); return set_var (name, Gen_type (value)); } else return set_var (assignment, Gen_type ("")); } // Return the value stored within variable NAME Gen_type Variables::get_var (string name) { Var_iterator iter; if ( ( iter = vars.find (name) ) == vars.end ()) { Msg::inst()->warning ("variable `" + name + "' not defined", name + " not def"); return Gen_type (); } return (*vars.find (name)).second; } Gen_type Variables::get_array_element (string name, Gen_type index) { Gen_type var = get_var (name); if (var.is_array ()) return get_var (name).get_element (index); else return Gen_type (); } Gen_type Variables::set_array_element (string name, Gen_type index, Gen_type value, bool shift) { Gen_type arr = get_var (name); if (!arr.is_array ()) { Msg::inst()->error (name + " is not an array"); return Gen_type (""); } arr.set_element (index, value, shift); set_var (name, arr); return value; } // Undefine variable NAME; return TRUE if such variable existed bool Variables::undef (string name) { Var_iterator iter; if ( ( iter = vars.find (name) ) != vars.end ()) { vars.erase (iter); return true; } return false; }