Commit 53175119 authored by twanvl's avatar twanvl

Make == script operator to work correctly on collections (lists)

parent 1209425e
......@@ -251,7 +251,10 @@ ScriptValueP Context::makeClosure(const ScriptValueP& fun) {
if (variables[var].level < level) break;
closure->addBinding(var, variables[var].value);
}
return closure;
// can we simplify?
ScriptValueP better = closure->simplify();
if (better) return better;
else return closure;
}
......@@ -392,8 +395,8 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
case I_AND: OPERATOR_I(&&);
case I_OR: OPERATOR_I(||);
case I_XOR: a = to_script((bool)*a != (bool)*b); break;
case I_EQ: a = to_script( equal(*a,*b)); break;
case I_NEQ: a = to_script(!equal(*a,*b)); break;
case I_EQ: a = to_script( equal(a,b)); break;
case I_NEQ: a = to_script(!equal(a,b)); break;
case I_LT: OPERATOR_DI(<);
case I_GT: OPERATOR_DI(>);
case I_LE: OPERATOR_DI(<=);
......
......@@ -215,7 +215,7 @@ int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const Scr
ScriptValueP it = in->makeIterator(in);
int i = 0;
while (ScriptValueP v = it->next()) {
if (equal(*of, *v)) return i;
if (equal(of, v)) return i;
i++;
}
}
......@@ -384,17 +384,10 @@ SCRIPT_FUNCTION(keyword_usage) {
// ----------------------------------------------------------------------------- : Rule form
/// Turn a script function into a rule, a.k.a. a delayed closure
class ScriptRule : public ScriptValue {
public:
inline ScriptRule(const ScriptValueP& fun) : fun(fun) {}
virtual ScriptType type() const { return SCRIPT_FUNCTION; }
virtual String typeName() const { return fun->typeName() + _(" rule"); }
virtual ScriptValueP eval(Context& ctx) const {
return ctx.makeClosure(fun);
}
private:
ScriptValueP fun;
};
SCRIPT_FUNCTION(rule) {
SCRIPT_PARAM(ScriptValueP, input);
return new_intrusive1<ScriptRule>(input);
}
// ----------------------------------------------------------------------------- : Init
......
......@@ -321,6 +321,17 @@ class ScriptClosure : public ScriptValue {
void applyBindings(Context& ctx) const;
};
/// Turn a script function into a rule, a.k.a. a delayed closure
class ScriptRule : public ScriptValue {
public:
inline ScriptRule(const ScriptValueP& fun) : fun(fun) {}
virtual ScriptType type() const;
virtual String typeName() const;
virtual ScriptValueP eval(Context& ctx) const;
private:
ScriptValueP fun;
};
// ----------------------------------------------------------------------------- : Creating
/// Convert a value to a script value
......@@ -360,7 +371,5 @@ template <> inline bool from_script<bool> (const ScriptValueP& va
template <> inline Color from_script<Color> (const ScriptValueP& value) { return (AColor)*value; }
template <> inline AColor from_script<AColor> (const ScriptValueP& value) { return *value; }
void from_script(const ScriptValueP& value, wxRegEx& out);
// ----------------------------------------------------------------------------- : EOF
#endif
......@@ -38,19 +38,30 @@ ScriptValueP ScriptValue::dependencyMember(const String& name, const Dependency&
ScriptValueP ScriptValue::dependencies(Context&, const Dependency&) const { return dependency_dummy; }
/// compare script values for equallity
bool equal(const ScriptValue& a, const ScriptValue& b) {
if (&a == &b) return true;
ScriptType at = a.type(), bt = b.type();
bool equal(const ScriptValueP& a, const ScriptValueP& b) {
if (a == b) return true;
ScriptType at = a->type(), bt = b->type();
if (at == bt && at == SCRIPT_INT) {
return (int)a == (int)b;
return (int)*a == (int)*b;
} else if ((at == SCRIPT_INT || at == SCRIPT_DOUBLE) &&
(bt == SCRIPT_INT || bt == SCRIPT_DOUBLE)) {
return (double)a == (double)b;
return (double)*a == (double)*b;
} else if (at == SCRIPT_COLLECTION && bt == SCRIPT_COLLECTION) {
// compare each element
if (a->itemCount() != b->itemCount()) return false;
ScriptValueP a_it = a->makeIterator(a);
ScriptValueP b_it = b->makeIterator(b);
while (true) {
ScriptValueP a_v = a_it->next();
ScriptValueP b_v = b_it->next();
if (!a_v || !b_v) return a_v == b_v;
if (!equal(a_v, b_v)) return false;
}
} else {
String as, bs;
const void* ap, *bp;
CompareWhat aw = a.compareAs(as, ap);
CompareWhat bw = b.compareAs(bs, bp);
CompareWhat aw = a->compareAs(as, ap);
CompareWhat bw = b->compareAs(bs, bp);
// compare pointers or strings
if (aw == COMPARE_AS_STRING || bw == COMPARE_AS_STRING) {
return as == bs;
......@@ -402,10 +413,9 @@ void ScriptClosure::applyBindings(Context& ctx) const {
}
}
// ----------------------------------------------------------------------------- : Destructing
void from_script(const ScriptValueP& value, wxRegEx& regex) {
if (!regex.Compile(*value, wxRE_ADVANCED)) {
throw ScriptError(_ERROR_2_("can't convert", value->typeName(), _TYPE_("regex")));
}
ScriptType ScriptRule::type() const { return SCRIPT_FUNCTION; }
String ScriptRule::typeName() const { return fun->typeName() + _(" rule"); }
ScriptValueP ScriptRule::eval(Context& ctx) const {
return ctx.makeClosure(fun);
}
......@@ -29,6 +29,7 @@ enum ScriptType
, SCRIPT_FUNCTION
, SCRIPT_OBJECT // Only ScriptObject
, SCRIPT_COLLECTION
, SCRIPT_REGEX
, SCRIPT_ITERATOR
, SCRIPT_DUMMY
, SCRIPT_ERROR
......@@ -102,7 +103,7 @@ extern ScriptValueP script_false; ///< The preallocated false value
extern ScriptValueP dependency_dummy; ///< Dummy value used during dependency analysis
/// compare script values for equallity
bool equal(const ScriptValue& a, const ScriptValue& b);
bool equal(const ScriptValueP& a, const ScriptValueP& b);
// ----------------------------------------------------------------------------- : EOF
#endif
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