Author: dragonking
Date: Wed Apr 9 20:36:16 2008
New Revision: 25713
URL: http://svn.gna.org/viewcvs/wesnoth?rev=25713&view=rev
Log:
Add support for a map to the formula system
Syntax:
{ 'elvish fighter' -> 40, 'elvish archer' -> 30 }
Changed comments in the formula system from
{ text of a comment } to # text of a comment #
Modified:
trunk/src/formula.cpp
trunk/src/formula_tokenizer.cpp
trunk/src/formula_tokenizer.hpp
trunk/src/variant.cpp
trunk/src/variant.hpp
Modified: trunk/src/formula.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/formula.cpp?rev=25713&r1=25712&r2=25713&view=diff
==============================================================================
--- trunk/src/formula.cpp (original)
+++ trunk/src/formula.cpp Wed Apr 9 20:36:16 2008
@@ -100,6 +100,27 @@
res.reserve(items_.size());
for(std::vector<expression_ptr>::const_iterator i =
items_.begin(); i != items_.end(); ++i) {
res.push_back((*i)->evaluate(variables));
+ }
+
+ return variant(&res);
+ }
+
+ std::vector<expression_ptr> items_;
+};
+
+class map_expression : public formula_expression {
+public:
+ explicit map_expression(const std::vector<expression_ptr>& items)
+ : items_(items)
+ {}
+
+private:
+ variant execute(const formula_callable& variables) const {
+ std::map<variant,variant> res;
+ for(std::vector<expression_ptr>::const_iterator i =
items_.begin(); ( i != items_.end() ) && ( i+1 != items_.end() ) ; i+=2) {
+ variant key = (*i)->evaluate(variables);
+ variant value = (*(i+1))->evaluate(variables);
+ res[ key ] = value;
}
return variant(&res);
@@ -475,6 +496,41 @@
} else if(i1->type == TOKEN_RPARENS || i1->type ==
TOKEN_RSQUARE) {
--parens;
} else if(i1->type == TOKEN_COMMA && !parens) {
+ res->push_back(parse_expression(beg,i1, symbols));
+ beg = i1+1;
+ }
+
+ ++i1;
+ }
+
+ if(beg != i1) {
+ res->push_back(parse_expression(beg,i1, symbols));
+ }
+}
+
+void parse_set_args(const token* i1, const token* i2,
+ std::vector<expression_ptr>* res,
+ function_symbol_table* symbols)
+{
+ int parens = 0;
+ bool check_pointer = false;
+ const token* beg = i1;
+ while(i1 != i2) {
+ if(i1->type == TOKEN_LPARENS || i1->type == TOKEN_LSQUARE) {
+ ++parens;
+ } else if(i1->type == TOKEN_RPARENS || i1->type ==
TOKEN_RSQUARE) {
+ --parens;
+ } else if( i1->type == TOKEN_POINTER && !parens ) {
+ if (!check_pointer) {
+ check_pointer = true;
+ res->push_back(parse_expression(beg,i1,
symbols));
+ beg = i1+1;
+ } else {
+ std::cerr << "Too many '->' operators\n";
+ throw formula_error();
+ }
+ } else if( i1->type == TOKEN_COMMA && !parens ) {
+ check_pointer = false;
res->push_back(parse_expression(beg,i1, symbols));
beg = i1+1;
}
@@ -598,9 +654,15 @@
if(i1->type == TOKEN_LPARENS && (i2-1)->type == TOKEN_RPARENS) {
return parse_expression(i1+1,i2-1,symbols);
} else if(i1->type == TOKEN_LSQUARE && (i2-1)->type ==
TOKEN_RSQUARE) {
+ //create a list
std::vector<expression_ptr> args;
parse_args(i1+1,i2-1,&args,symbols);
return expression_ptr(new
list_expression(args));
+ } else if(i1->type == TOKEN_LBRACKET && (i2-1)->type ==
TOKEN_RBRACKET) {
+ //create a map TODO: add support for a set
+ std::vector<expression_ptr> args;
+ parse_set_args(i1+1,i2-1,&args,symbols);
+ return expression_ptr(new map_expression(args));
} else if(i2 - i1 == 1) {
if(i1->type == TOKEN_KEYWORD) {
if(std::string(i1->begin,i1->end) ==
"functions") {
Modified: trunk/src/formula_tokenizer.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/formula_tokenizer.cpp?rev=25713&r1=25712&r2=25713&view=diff
==============================================================================
--- trunk/src/formula_tokenizer.cpp (original)
+++ trunk/src/formula_tokenizer.cpp Wed Apr 9 20:36:16 2008
@@ -31,7 +31,7 @@
};
//create the array with list of possible tokens
-token_type token_types[] = { {
regex("^(not\\b|and\\b|or\\b|where\\b|d(?=[^a-zA-Z])|\\*|\\+|\\-|\\^|%|/|<=|>=|<|>|!=|=|\\.)"),
TOKEN_OPERATOR },
+token_type token_types[] = { {
regex("^(not\\b|and\\b|or\\b|where\\b|d(?=[^a-zA-Z])|\\*|\\+|-(?=[^>])|\\^|%|/|<=|>=|<|>|!=|=|\\.)"),
TOKEN_OPERATOR },
{ regex("^functions\\b"), TOKEN_KEYWORD },
{ regex("^def\\b"), TOKEN_KEYWORD },
{ regex("^'[^']*'"), TOKEN_STRING_LITERAL
},
@@ -41,10 +41,13 @@
{ regex("^\\)"), TOKEN_RPARENS },
{ regex("^\\["), TOKEN_LSQUARE },
{ regex("^\\]"), TOKEN_RSQUARE },
- { regex("^\\{.*?\\}"), TOKEN_COMMENT },
+ { regex("^\\{"), TOKEN_LBRACKET },
+ { regex("^\\}"), TOKEN_RBRACKET },
+ { regex("^#.*?#"), TOKEN_COMMENT },
{ regex("^,"), TOKEN_COMMA },
{ regex("^;"), TOKEN_SEMICOLON },
- { regex("^\\s+"), TOKEN_WHITESPACE }
+ { regex("^\\s+"), TOKEN_WHITESPACE },
+ { regex("^->"), TOKEN_POINTER }
};
}
@@ -57,7 +60,7 @@
res.type = t.type;
res.begin = i1;
i1 = res.end = i1 + match.length();
-
+
return res;
}
}
Modified: trunk/src/formula_tokenizer.hpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/formula_tokenizer.hpp?rev=25713&r1=25712&r2=25713&view=diff
==============================================================================
--- trunk/src/formula_tokenizer.hpp (original)
+++ trunk/src/formula_tokenizer.hpp Wed Apr 9 20:36:16 2008
@@ -25,9 +25,10 @@
TOKEN_IDENTIFIER, TOKEN_INTEGER,
TOKEN_LPARENS, TOKEN_RPARENS,
TOKEN_LSQUARE, TOKEN_RSQUARE,
+ TOKEN_LBRACKET, TOKEN_RBRACKET,
TOKEN_COMMA, TOKEN_SEMICOLON,
TOKEN_WHITESPACE, TOKEN_KEYWORD,
- TOKEN_COMMENT };
+ TOKEN_COMMENT, TOKEN_POINTER };
struct token {
TOKEN_TYPE type;
Modified: trunk/src/variant.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/variant.cpp?rev=25713&r1=25712&r2=25713&view=diff
==============================================================================
--- trunk/src/variant.cpp (original)
+++ trunk/src/variant.cpp Wed Apr 9 20:36:16 2008
@@ -28,6 +28,8 @@
return "list";
case variant::TYPE_STRING:
return "string";
+ case variant::TYPE_MAP:
+ return "map";
default:
assert(false);
return "invalid";
@@ -80,6 +82,13 @@
int refcount;
};
+struct variant_map {
+ variant_map() : refcount(0)
+ {}
+ std::map<variant,variant> elements;
+ int refcount;
+};
+
void variant::increment_refcount()
{
switch(type_) {
@@ -88,6 +97,9 @@
break;
case TYPE_STRING:
++string_->refcount;
+ break;
+ case TYPE_MAP:
+ ++map_->refcount;
break;
case TYPE_CALLABLE:
intrusive_ptr_add_ref(callable_);
@@ -111,6 +123,11 @@
case TYPE_STRING:
if(--string_->refcount == 0) {
delete string_;
+ }
+ break;
+ case TYPE_MAP:
+ if(--map_->refcount == 0) {
+ delete map_;
}
break;
case TYPE_CALLABLE:
@@ -154,6 +171,15 @@
increment_refcount();
}
+variant::variant(std::map<variant,variant>* map)
+ : type_(TYPE_MAP)
+{
+ assert(map);
+ map_ = new variant_map;
+ map_->elements.swap(*map);
+ increment_refcount();
+}
+
variant::variant(const variant& v)
{
memcpy(this, &v, sizeof(v));
@@ -191,15 +217,44 @@
return list_->elements[n];
}
+const variant& variant::operator[](const variant v) const
+{
+ if(type_ == TYPE_CALLABLE) {
+ assert(v.as_int() == 0);
+ return *this;
+ }
+
+ if(type_ == TYPE_MAP) {
+ assert(map_);
+ std::map<variant,variant>::const_iterator i =
map_->elements.find(v);
+ if (i == map_->elements.end())
+ {
+ static variant null_variant;
+ return null_variant;
+ }
+ return i->second;
+ } else if(type_ == TYPE_LIST) {
+ return operator[](v.as_int());
+ } else {
+ throw type_error(formatter() << "type error: " << " expected a
list or a map but found " << variant_type_to_string(type_) << " (" <<
to_debug_string() << ")");
+ }
+}
+
size_t variant::num_elements() const
{
if(type_ == TYPE_CALLABLE) {
return 1;
}
- must_be(TYPE_LIST);
- assert(list_);
- return list_->elements.size();
+ if (type_ == TYPE_LIST) {
+ assert(list_);
+ return list_->elements.size();
+ } else if (type_ == TYPE_MAP) {
+ assert(map_);
+ return map_->elements.size();
+ } else {
+ throw type_error(formatter() << "type error: " << " expected a
list or a map but found " << variant_type_to_string(type_) << " (" <<
to_debug_string() << ")");
+ }
}
variant variant::get_member(const std::string& str) const
@@ -226,6 +281,8 @@
return callable_ != NULL;
case TYPE_LIST:
return !list_->elements.empty();
+ case TYPE_MAP:
+ return !map_->elements.empty();
case TYPE_STRING:
return !string_->str.empty();
default:
@@ -260,6 +317,17 @@
return variant(&res);
}
}
+ if(type_ == TYPE_MAP) {
+ if(v.type_ == TYPE_MAP) {
+ std::map<variant,variant> res(map_->elements);
+
+ for(std::map<variant,variant>::const_iterator i =
v.map_->elements.begin(); i != v.map_->elements.end(); ++i) {
+ res[i->first] = i->second;
+ }
+
+ return variant(&res);
+ }
+ }
return variant(as_int() + v.as_int());
}
@@ -339,6 +407,10 @@
return true;
}
+ case TYPE_MAP: {
+ return map_->elements == v.map_->elements;
+ }
+
case TYPE_CALLABLE: {
return callable_->equals(v.callable_);
}
@@ -356,15 +428,7 @@
bool variant::operator<=(const variant& v) const
{
if(type_ != v.type_) {
- if(type_ == TYPE_NULL) {
- return variant(0) <= v;
- }
-
- if(v.type_ == TYPE_NULL) {
- return *this <= variant(0);
- }
-
- return false;
+ return type_ < v.type_;
}
switch(type_) {
@@ -390,6 +454,10 @@
}
return num_elements() <= v.num_elements();
+ }
+
+ case TYPE_MAP: {
+ return map_->elements <= v.map_->elements;
}
case TYPE_CALLABLE: {
@@ -448,6 +516,21 @@
str += "]";
break;
}
+ case TYPE_MAP: {
+ str += "{";
+ bool first_time = true;
+ for(std::map<variant,variant>::const_iterator
i=map_->elements.begin(); i != map_->elements.end(); ++i) {
+ if(!first_time) {
+ str += ",";
+ }
+ first_time = false;
+ i->first.serialize_to_string(str);
+ str += "->";
+ i->second.serialize_to_string(str);
+ }
+ str += "}";
+ break;
+ }
case TYPE_STRING:
str += "'";
str += string_->str;
@@ -475,6 +558,9 @@
break;
case TYPE_STRING:
return string_->refcount;
+ break;
+ case TYPE_MAP:
+ return map_->refcount;
break;
case TYPE_CALLABLE:
return callable_->refcount();
@@ -504,6 +590,18 @@
res += var.string_cast();
}
+ return res;
+ }
+ case TYPE_MAP: {
+ std::string res = "";
+ for(std::map<variant,variant>::const_iterator
i=map_->elements.begin(); i != map_->elements.end(); ++i) {
+ if(!res.empty()) {
+ res += ",";
+ }
+ res += i->first.string_cast();
+ res += "->";
+ res += i->second.string_cast();
+ }
return res;
}
@@ -568,6 +666,21 @@
s << "}";
break;
}
+ case TYPE_MAP: {
+ s << "{";
+ bool first_time = true;
+ for(std::map<variant,variant>::const_iterator
i=map_->elements.begin(); i != map_->elements.end(); ++i) {
+ if(!first_time) {
+ s << ",";
+ }
+ first_time = false;
+ s << i->first.to_debug_string(seen);
+ s << "->";
+ s << i->second.to_debug_string(seen);
+ }
+ s << "}";
+ break;
+ }
case TYPE_STRING: {
s << "'" << string_->str << "'";
break;
Modified: trunk/src/variant.hpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/variant.hpp?rev=25713&r1=25712&r2=25713&view=diff
==============================================================================
--- trunk/src/variant.hpp (original)
+++ trunk/src/variant.hpp Wed Apr 9 20:36:16 2008
@@ -25,6 +25,7 @@
struct variant_list;
struct variant_string;
+struct variant_map;
struct type_error {
explicit type_error(const std::string& str);
@@ -38,12 +39,14 @@
explicit variant(const game_logic::formula_callable* callable);
explicit variant(std::vector<variant>* array);
explicit variant(const std::string& str);
+ explicit variant(std::map<variant,variant>* map);
~variant();
variant(const variant& v);
const variant& operator=(const variant& v);
const variant& operator[](size_t n) const;
+ const variant& operator[](const variant v) const;
size_t num_elements() const;
variant get_member(const std::string& str) const;
@@ -51,6 +54,7 @@
bool is_string() const { return type_ == TYPE_STRING; }
bool is_null() const { return type_ == TYPE_NULL; }
bool is_int() const { return type_ == TYPE_INT; }
+ bool is_map() const { return type_ == TYPE_MAP; }
int as_int() const { if(type_ == TYPE_NULL) { return 0; }
must_be(TYPE_INT); return int_value_; }
bool as_bool() const;
@@ -106,7 +110,7 @@
std::string string_cast() const;
std::string to_debug_string(std::vector<const
game_logic::formula_callable*>* seen=NULL) const;
- enum TYPE { TYPE_NULL, TYPE_INT, TYPE_CALLABLE, TYPE_LIST, TYPE_STRING
};
+ enum TYPE { TYPE_NULL, TYPE_INT, TYPE_CALLABLE, TYPE_LIST, TYPE_STRING,
TYPE_MAP };
private:
void must_be(TYPE t) const;
TYPE type_;
@@ -116,6 +120,7 @@
game_logic::formula_callable* mutable_callable_;
variant_list* list_;
variant_string* string_;
+ variant_map* map_;
};
void increment_refcount();
_______________________________________________
Wesnoth-commits mailing list
[email protected]
https://mail.gna.org/listinfo/wesnoth-commits