Commit 843d312f authored by twanvl's avatar twanvl

ScriptObject now looks for a default member for everything that it can not...

ScriptObject now looks for a default member for everything that it can not handle, meaning that scripts based on values now work.
parent 15f64ab2
......@@ -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
......
......@@ -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
}
......
......@@ -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<ToUpdate> 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<ToUpdate>& to_update, Age starting_age
void ScriptManager::updateToUpdate(const ToUpdate& u, deque<ToUpdate>& 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);
......
......@@ -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. */
......
......@@ -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;
};
......
......@@ -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
......
......@@ -79,7 +79,9 @@ class GetMember : private GetDefaultMember {
/// Handle an object: we are done if the name matches
template <typename T>
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 <typename T> void handle(const T&);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment