Files
MagicSetEditor2/src/script/scriptable.hpp
T
twanvl 1ffaa5bd58 made a start with script functions
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@62 0fc631ac-6414-0410-93d0-97cfa31319b6
2006-10-31 12:17:36 +00:00

129 lines
4.0 KiB
C++

//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_SCRIPT_SCRIPTABLE
#define HEADER_SCRIPT_SCRIPTABLE
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/reflect.hpp>
#include <util/defaultable.hpp>
#include <script/script.hpp>
#include <script/parser.hpp>
DECLARE_INTRUSIVE_POINTER_TYPE(Script);
class Context;
// ----------------------------------------------------------------------------- : Store
/// Store a ScriptValue in a variable
void store(const ScriptValueP& val, String& var);
void store(const ScriptValueP& val, int& var);
void store(const ScriptValueP& val, double& var);
void store(const ScriptValueP& val, bool& var);
void store(const ScriptValueP& val, Defaultable<String>& var);
// ----------------------------------------------------------------------------- : OptionalScript
/// An optional script,
class OptionalScript {
public:
~OptionalScript();
/// Is the script set?
inline operator bool() const { return !!script; }
/// Invoke the script, return the result, or script_nil if there is no script
ScriptValueP invoke(Context& ctx) const;
/// Invoke the script on a value
/** Assigns the result to value if it has changed.
* Returns true if the value has changed.
*/
template <typename T>
bool invokeOn(Context& ctx, T& value) const {
if (script) {
T new_value;
store(new_value, script->invoke(ctx));
if (value != new_value) {
value = new_value;
return true;
}
}
return false;
}
/// Initialize things this script depends on by adding dep to their list of dependent scripts
void initDependencies(Context&, const Dependency& dep) const;
private:
ScriptP script; ///< The script, may be null if there is no script
String unparsed; ///< Unparsed script, for writing back to a file
// parse the unparsed string, while reading
void parse(Reader&);
DECLARE_REFLECTION();
template <typename T> friend class Scriptable;
};
// ----------------------------------------------------------------------------- : Scriptable
/// A script that defines a calculation to find a value
/** NOTE: reading MUST happen inside a block */
template <typename T>
class Scriptable {
public:
Scriptable() : value() {}
Scriptable(const T& value) : value(value) {}
inline operator const T& () const { return value; }
inline bool isScripted() const { return script; }
/// Updates the value by executing the script, returns true if the value has changed
inline bool update(Context& ctx) {
return script.invokeOn(ctx, value);
}
inline void initDependencies(Context& ctx, const Dependency& dep) const {
script.initDependencies(ctx, dep);
}
private:
T value; ///< The actual value
OptionalScript script; ///< The optional script
DECLARE_REFLECTION();
};
// we need some custom io, because the behaviour is different for each of Reader/Writer/GetMember
template <typename T>
void Reader::handle(Scriptable<T>& s) {
handle(s.script.unparsed);
if (starts_with(s.script.unparsed, _("script:"))) {
s.script.unparsed = s.script.unparsed.substr(7);
s.script.parse(*this);
} else {
handle(s.value);
}
}
template <typename T>
void Writer::handle(const Scriptable<T>& s) {
if (s.script) {
handle(s.script);
} else {
handle(s.value);
}
}
template <typename T>
void GetDefaultMember::handle(const Scriptable<T>& s) {
// just handle as the value
handle(s.value);
}
// ----------------------------------------------------------------------------- : EOF
#endif