Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 224 lines (177 sloc) 6.92 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
/* $Id: formula_callable.hpp 25895 2008-04-17 18:57:13Z mordante $ */
/*
Copyright (C) 2008 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.

See the COPYING file for more details.
*/

#ifndef FORMULA_CALLABLE_HPP_INCLUDED
#define FORMULA_CALLABLE_HPP_INCLUDED

#include <iostream>
#include <map>
#include <string>

#include "reference_counted_object.hpp"
#include "variant.hpp"

namespace game_logic
{

enum FORMULA_ACCESS_TYPE { FORMULA_READ_ONLY, FORMULA_WRITE_ONLY, FORMULA_READ_WRITE };
struct formula_input {
std::string name;
FORMULA_ACCESS_TYPE access;
formula_input(const std::string& name, FORMULA_ACCESS_TYPE access=FORMULA_READ_WRITE)
: name(name), access(access)
{}
};

//interface for objects that can have formulae run on them
class formula_callable : public reference_counted_object {
public:
explicit formula_callable(bool has_self=false) : has_self_(has_self)
{}

variant query_value(const std::string& key) const {
if(has_self_ && key == "self") {
return variant(this);
}
return get_value(key);
}

variant query_value_by_slot(int slot) const {
return get_value_by_slot(slot);
}

void mutate_value(const std::string& key, const variant& value) {
set_value(key, value);
}

void mutate_value_by_slot(int slot, const variant& value) {
set_value_by_slot(slot, value);
}

std::vector<formula_input> inputs() const {
std::vector<formula_input> res;
get_inputs(&res);
return res;
}

bool equals(const formula_callable* other) const {
return do_compare(other) == 0;
}

bool less(const formula_callable* other) const {
return do_compare(other) < 0;
}

virtual void get_inputs(std::vector<formula_input>* /*inputs*/) const {};

void serialize(std::string& str) const {
serialize_to_string(str);
}

bool has_key(const std::string& key) const
{ return !query_value(key).is_null(); }

// In order to provide support for widgets to be able to have FFL handlers for events
// The following two functions are provided for them to use to respectively execute
// a command and create a new formula from a variant (which is expected to contain FFL
// commands). If you're making some new that object that provides a custom symbol
// table or supports different types of command_callable you should override these
// two functions to provide widget support.
virtual bool execute_command(const variant &v);
virtual formula_ptr create_formula(const variant& v);

protected:
virtual ~formula_callable() {}

virtual void set_value(const std::string& key, const variant& value);
virtual void set_value_by_slot(int slot, const variant& value);
virtual int do_compare(const formula_callable* callable) const {
return this < callable ? -1 : (this == callable ? 0 : 1);
}

virtual void serialize_to_string(std::string& str) const;
private:
virtual variant get_value(const std::string& key) const = 0;
virtual variant get_value_by_slot(int slot) const;
bool has_self_;
};

class formula_callable_no_ref_count : public formula_callable {
public:
formula_callable_no_ref_count() {
turn_reference_counting_off();
}
virtual ~formula_callable_no_ref_count() {}
};

class formula_callable_with_backup : public formula_callable {
const formula_callable& main_;
const formula_callable& backup_;
variant get_value_by_slot(int slot) const {
return backup_.query_value_by_slot(slot);
}

variant get_value(const std::string& key) const {
variant var = main_.query_value(key);
if(var.is_null()) {
return backup_.query_value(key);
}

return var;
}

void get_inputs(std::vector<formula_input>* inputs) const {
main_.get_inputs(inputs);
backup_.get_inputs(inputs);
}
public:
formula_callable_with_backup(const formula_callable& main, const formula_callable& backup) : formula_callable(false), main_(main), backup_(backup)
{}
};

class formula_variant_callable_with_backup : public formula_callable {
variant var_;
const formula_callable& backup_;
variant get_value(const std::string& key) const {
variant var = var_.get_member(key);
if(var.is_null()) {
return backup_.query_value(key);
}

return var;
}

variant get_value_by_slot(int slot) const {
return backup_.query_value_by_slot(slot);
}

void get_inputs(std::vector<formula_input>* inputs) const {
backup_.get_inputs(inputs);
}

public:
formula_variant_callable_with_backup(const variant& var, const formula_callable& backup) : formula_callable(false), var_(var), backup_(backup)
{}
};

class map_formula_callable : public formula_callable {
public:
explicit map_formula_callable(variant node);
explicit map_formula_callable(const formula_callable* fallback=NULL);
explicit map_formula_callable(const std::map<std::string, variant>& m);
variant write() const;
map_formula_callable& add(const std::string& key, const variant& value);
void set_fallback(const formula_callable* fallback) { fallback_ = fallback; }

//adds an entry and gets direct access to the variant. Use with caution
//and for cases where calling add() repeatedy isn't efficient enough.
variant& add_direct_access(const std::string& key);

bool empty() const { return values_.empty(); }
void clear() { values_.clear(); }
bool contains(const std::string& key) const { return values_.count(key) != 0; }

const std::map<std::string, variant>& values() const { return values_; }

typedef std::map<std::string,variant>::const_iterator const_iterator;

const_iterator begin() const { return values_.begin(); }
const_iterator end() const { return values_.end(); }

variant& ref(const std::string& key) { return values_[key]; }

private:
//map_formula_callable(const map_formula_callable&);

variant get_value_by_slot(int slot) const {
return fallback_->query_value_by_slot(slot);
}

variant get_value(const std::string& key) const;
void get_inputs(std::vector<formula_input>* inputs) const;
void set_value(const std::string& key, const variant& value);
std::map<std::string,variant> values_;
const formula_callable* fallback_;
};

typedef boost::intrusive_ptr<formula_callable> formula_callable_ptr;
typedef boost::intrusive_ptr<const formula_callable> const_formula_callable_ptr;

typedef boost::intrusive_ptr<map_formula_callable> map_formula_callable_ptr;
typedef boost::intrusive_ptr<const map_formula_callable> const_map_formula_callable_ptr;

class command_callable : public formula_callable {
public:
virtual void execute(formula_callable& context) const = 0;
private:
variant get_value(const std::string& key) const { return variant(); }
void get_inputs(std::vector<game_logic::formula_input>* inputs) const {}
};

}

#endif
Something went wrong with that request. Please try again.