diff --git a/src/script/dependency.cpp b/src/script/dependency.cpp index 78c172cc..e90f0ba1 100644 --- a/src/script/dependency.cpp +++ b/src/script/dependency.cpp @@ -25,8 +25,6 @@ class DependencyDummy : public ScriptIterator { virtual ScriptType type() const { return SCRIPT_DUMMY; } virtual String typeName() const { return _("dummy"); } virtual ScriptValueP next() { return ScriptValueP(); } - virtual ScriptValueP eval(Context&) const { return dependency_dummy; } // dummy() == dummy - virtual ScriptValueP getMember(const String&) const { return dependency_dummy; } // dummy.* = dummy }; ScriptValueP dependency_dummy(new DependencyDummy); @@ -52,6 +50,9 @@ class DependencyUnion : public ScriptValue { virtual ScriptValueP makeIterator() const { return unified(a->makeIterator(), b->makeIterator()); } + virtual ScriptValueP dependencyMember(const String& name, const Dependency& dep) const { + return unified(a->dependencyMember(name,dep), b->dependencyMember(name,dep)); + } private: ScriptValueP a, b; }; @@ -212,8 +213,7 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) // Get an object member (almost as normal) case I_MEMBER_C: { String name = *script.constants[i.data]; - stack.back()->signalDependent(*this, dep, name); // dependency on member - stack.back() = stack.back()->getMember(name); + stack.back() = stack.back()->dependencyMember(name, dep); // dependency on member break; } // Loop over a container, push next value or jump (almost as normal) @@ -295,8 +295,7 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) break; case I_MEMBER: { String name = *b; - a->signalDependent(*this, dep, name); // dependency on member - a = a->getMember(name); + a = a->dependencyMember(name, dep); // dependency on member break; } case I_ADD: unify(a, b); // may be function composition diff --git a/src/script/image.cpp b/src/script/image.cpp index 956d750b..c44ddccf 100644 --- a/src/script/image.cpp +++ b/src/script/image.cpp @@ -123,7 +123,7 @@ ScriptImageP ScriptableImage::update(Context& ctx, Package& pkg, UInt width, UIn bool ScriptableImage::upToDate(Context& ctx, Age age) const { try { WITH_DYNAMIC_ARG(last_update_age, age.get()); - return (int)*script.invoke(ctx); + return script_image_up_to_date(script.invoke(ctx)); } catch (Error e) { return true; // script gives errors, don't update } diff --git a/src/script/script_manager.cpp b/src/script/script_manager.cpp index ddb30d8b..df904a62 100644 --- a/src/script/script_manager.cpp +++ b/src/script/script_manager.cpp @@ -78,6 +78,15 @@ Context& ScriptManager::getContext(const StyleSheetP& stylesheet) { return *ctx; } } +Context& ScriptManager::getContext(const CardP& card) { + Context& ctx = getContext(set.stylesheetFor(card)); + if (card) { + ctx.setVariable(_("card"), toScript(card)); + } else { + ctx.setVariable(_("card"), script_nil); + } + return ctx; +} void ScriptManager::initDependencies(Context& ctx, Game& game) { if (game.dependencies_initialized) return; @@ -115,7 +124,7 @@ void ScriptManager::onAction(const Action& action, bool undone) { void ScriptManager::updateStyles(const CardP& card) { // lastUpdatedCard = card; StyleSheetP stylesheet = set.stylesheetFor(card); - Context& ctx = getContext(stylesheet); + Context& ctx = getContext(card); // update all styles FOR_EACH(s, stylesheet->card_style) { if (s->update(ctx)) { @@ -130,7 +139,7 @@ void ScriptManager::updateValue(Value& value, const CardP& card) { Age starting_age; // the start of the update process deque to_update; // execute script for initial changed value - value.update(getContext(set.stylesheetFor(card))); + value.update(getContext(card)); // update dependent scripts alsoUpdate(to_update, value.fieldP->dependent_scripts, card); updateRecursive(to_update, starting_age); @@ -144,7 +153,7 @@ void ScriptManager::updateAll() { } // update card data of all cards FOR_EACH(card, set.cards) { - Context& ctx = getContext(set.stylesheetFor(card)); + Context& ctx = getContext(card); FOR_EACH(v, card->data) { v->update(ctx); } @@ -171,7 +180,7 @@ void ScriptManager::updateRecursive(deque& to_update, Age starting_age void ScriptManager::updateToUpdate(const ToUpdate& u, deque& to_update, Age starting_age) { Age age = u.value->last_script_update; if (starting_age < age) return; // this value was already updated - Context& ctx = getContext(set.stylesheetFor(u.card)); + Context& ctx = getContext(u.card); if (u.value->update(ctx)) { // changed, send event // ScriptValueEvent change(&*u.card, u.value); diff --git a/src/script/script_manager.hpp b/src/script/script_manager.hpp index 0a25b121..3d33c9b6 100644 --- a/src/script/script_manager.hpp +++ b/src/script/script_manager.hpp @@ -41,7 +41,9 @@ class ScriptManager : public ActionListener { ~ScriptManager(); /// Get a context to use for the set, for a given stylesheet - Context& getContext(const StyleSheetP& s); + Context& getContext(const StyleSheetP&); + /// Get a context to use for the set, for a given card + Context& getContext(const CardP&); // Update all styles for a particular card void updateStyles(const CardP& card); @@ -66,8 +68,8 @@ class ScriptManager : public ActionListener { // Something that needs to be updated struct ToUpdate { - Value* value; // value to update - CardP card; // card the value is in, or 0 if it is not a card field + Value* value; ///< value to update + CardP card; ///< card the value is in, or CadP() if it is not a card field }; /// Update all things in to_update, and things that depent on them, etc. /** Only update things that are older than starting_age. */ diff --git a/src/script/value.cpp b/src/script/value.cpp index 729330c6..1bb3dea0 100644 --- a/src/script/value.cpp +++ b/src/script/value.cpp @@ -23,8 +23,8 @@ ScriptValueP ScriptValue::next() { throw InternalEr ScriptValueP ScriptValue::makeIterator() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); } int ScriptValue::itemCount() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); } -void ScriptValue::signalDependent(Context&, const Dependency&, const String& name) {} -ScriptValueP ScriptValue::dependencies(Context&, const Dependency&) const { return dependency_dummy; } +ScriptValueP ScriptValue::dependencyMember(const String& name, const Dependency&) const { return dependency_dummy; } +ScriptValueP ScriptValue::dependencies(Context&, const Dependency&) const { return dependency_dummy; } // ----------------------------------------------------------------------------- : Iterators @@ -167,6 +167,15 @@ class ScriptString : public ScriptValue { } } virtual int itemCount() const { return (int)value.size(); } + virtual ScriptValueP getMember(const String& name) const { + // get member returns characters + long index; + if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) { + return toScript(String(1,value[index])); + } else { + throw ScriptError(_("String \"") + value + _("\" has no member ") + name); + } + } private: String value; }; diff --git a/src/script/value.hpp b/src/script/value.hpp index f50b07e2..5deaaeaf 100644 --- a/src/script/value.hpp +++ b/src/script/value.hpp @@ -68,9 +68,15 @@ class ScriptValue { /// Get a member variable from this value virtual ScriptValueP getMember(const String& name) const; + /// Signal that a script depends on a member of this value + /** It is the abstract version of getMember*/ + virtual ScriptValueP dependencyMember(const String& name, const Dependency&) const; /// Evaluate this value (if it is a function) virtual ScriptValueP eval(Context&) const; + /// Mark the scripts that this function depends on + /** Return value is an abstract version of the return value of eval */ + virtual ScriptValueP dependencies(Context&, const Dependency&) const; /// Return an iterator for the current collection, an iterator is a value that has next() virtual ScriptValueP makeIterator() const; @@ -79,11 +85,6 @@ class ScriptValue { /// Return the number of items in this value (assuming it is a collection) virtual int itemCount() const; - /// Signal that a script depends on a member of this value - virtual void signalDependent(Context&, const Dependency&, const String& name); - /// Mark the scripts that this function depends on - /** Return value is an abstract version of the return value of eval */ - virtual ScriptValueP dependencies(Context&, const Dependency&) const; protected: /// Delete this object @@ -158,7 +159,7 @@ class ScriptCollection : public ScriptValue { virtual String typeName() const { return _("collection"); } virtual ScriptValueP getMember(const String& name) const { long index; - if (name.ToLong(&index)) { + if (name.ToLong(&index) && index >= 0 && (size_t)index < value->size()) { return toScript(value->at(index)); } else { throw ScriptError(_("Collection has no member ") + name); @@ -220,14 +221,31 @@ class ScriptObject : public ScriptValue { inline ScriptObject(const T& v) : value(v) {} virtual ScriptType type() const { return SCRIPT_OBJECT; } virtual String typeName() const { return _("object"); } + virtual operator String() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator String(); } + virtual operator double() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator double(); } + virtual operator int() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator int(); } + virtual operator Color() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator Color(); } virtual ScriptValueP getMember(const String& name) const { GetMember gm(name); gm.handle(*value); if (gm.result()) return gm.result(); - else throw ScriptError(_("Object has no member '") + name + _("'")); + else { + // try nameless member + ScriptValueP d = getDefault(); + if (d) { + return d->getMember(name); + } else { + throw ScriptError(_("Object has no member '") + name + _("'")); + } + } } private: T value; ///< The object + ScriptValueP getDefault() const { + GetDefaultMember gdm; + gdm.handle(*value); + return gdm.result(); + } }; // ----------------------------------------------------------------------------- : Creating diff --git a/src/util/io/get_member.hpp b/src/util/io/get_member.hpp index e7b39f96..4aa4c40c 100644 --- a/src/util/io/get_member.hpp +++ b/src/util/io/get_member.hpp @@ -79,7 +79,9 @@ class GetMember : private GetDefaultMember { /// Handle an object: we are done if the name matches template void handle(const Char* name, const T& object) { - if (!gdm.result() && name == target_name) gdm.handle(object); + if (!gdm.result() && cannocial_name_compare(target_name, name)) { + gdm.handle(object); + } } /// Handle an object: investigate children template void handle(const T&);