Commit ec70b27d authored by twanvl's avatar twanvl

Added ^ power operator,

Added abs, random_int, random_real, random_shuffle, random_select script functions.
Made == comparison of doubles use a small epsilon, so things like 3/2 == 1.5 are actually true.
parent 10953ee7
...@@ -198,7 +198,7 @@ void ChoiceStyle::initImage() { ...@@ -198,7 +198,7 @@ void ChoiceStyle::initImage() {
// CALL 0 // CALL 0
// PUSH_CONST nil // PUSH_CONST nil
// OR_ELSE // OR_ELSE
intrusive_ptr<ScriptCustomCollection> lookup(new ScriptCustomCollection()); ScriptCustomCollectionP lookup(new ScriptCustomCollection());
FOR_EACH(ci, choice_images) { FOR_EACH(ci, choice_images) {
lookup->key_value[ci.first] = ci.second.getScriptP(); lookup->key_value[ci.first] = ci.second.getScriptP();
} }
......
...@@ -402,6 +402,13 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& ...@@ -402,6 +402,13 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
a = to_script((int)*a % (int)*b); a = to_script((int)*a % (int)*b);
} }
break; break;
case I_POW:
if (at == SCRIPT_DOUBLE || bt == SCRIPT_DOUBLE) {
a = to_script(pow((double)*a, (double)*b));
} else {
a = to_script(pow((int)*a, (int)*b));
}
break;
case I_AND: OPERATOR_B(&&); case I_AND: OPERATOR_B(&&);
case I_OR: OPERATOR_B(||); case I_OR: OPERATOR_B(||);
case I_XOR: OPERATOR_B(!=); case I_XOR: OPERATOR_B(!=);
...@@ -442,7 +449,7 @@ void instrQuaternary(QuaternaryInstructionType i, ScriptValueP& a, const ScriptV ...@@ -442,7 +449,7 @@ void instrQuaternary(QuaternaryInstructionType i, ScriptValueP& a, const ScriptV
// ----------------------------------------------------------------------------- : Simple instructions : objects and closures // ----------------------------------------------------------------------------- : Simple instructions : objects and closures
void Context::makeObject(size_t n) { void Context::makeObject(size_t n) {
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection()); ScriptCustomCollectionP ret(new ScriptCustomCollection());
size_t begin = stack.size() - 2 * n; size_t begin = stack.size() - 2 * n;
for (size_t i = 0 ; i < n ; ++i) { for (size_t i = 0 ; i < n ; ++i) {
const ScriptValueP& key = stack[begin + 2 * i]; const ScriptValueP& key = stack[begin + 2 * i];
......
...@@ -89,6 +89,21 @@ SCRIPT_FUNCTION(to_real) { ...@@ -89,6 +89,21 @@ SCRIPT_FUNCTION(to_real) {
SCRIPT_RETURN(input); SCRIPT_RETURN(input);
} }
SCRIPT_FUNCTION(to_number) {
ScriptValueP input = ctx.getVariable(SCRIPT_VAR_input);
ScriptType t = input->type();
if (t == SCRIPT_BOOL) {
SCRIPT_RETURN((bool)*input ? 1 : 0);
} else if (t == SCRIPT_COLOR) {
AColor c = (AColor)*input;
SCRIPT_RETURN( (c.Red() + c.Blue() + c.Green()) / 3 );
} else if (t == SCRIPT_DOUBLE) {
SCRIPT_RETURN((double)*input);
} else {
SCRIPT_RETURN((int)*input);
}
}
SCRIPT_FUNCTION(to_boolean) { SCRIPT_FUNCTION(to_boolean) {
ScriptValueP input = ctx.getVariable(SCRIPT_VAR_input); ScriptValueP input = ctx.getVariable(SCRIPT_VAR_input);
ScriptType t = input->type(); ScriptType t = input->type();
...@@ -106,6 +121,30 @@ SCRIPT_FUNCTION(to_color) { ...@@ -106,6 +121,30 @@ SCRIPT_FUNCTION(to_color) {
SCRIPT_RETURN(input); SCRIPT_RETURN(input);
} }
// ----------------------------------------------------------------------------- : Math
SCRIPT_FUNCTION(abs) {
ScriptValueP input = ctx.getVariable(SCRIPT_VAR_input);
ScriptType t = input->type();
if (t == SCRIPT_DOUBLE) {
SCRIPT_RETURN(fabs((double)*input));
} else {
SCRIPT_RETURN(abs((int)*input));
}
}
SCRIPT_FUNCTION(random_real) {
SCRIPT_PARAM_DEFAULT_C(double, begin, 0.0);
SCRIPT_PARAM_DEFAULT_C(double, end, 1.0);
SCRIPT_RETURN( (double)rand() / RAND_MAX * (end - begin) + begin );
}
SCRIPT_FUNCTION(random_int) {
SCRIPT_PARAM_DEFAULT_C(int, begin, 0);
SCRIPT_PARAM_C( int, end);
SCRIPT_RETURN( rand() % (end - begin) + begin );
}
// ----------------------------------------------------------------------------- : String stuff // ----------------------------------------------------------------------------- : String stuff
// convert a string to upper case // convert a string to upper case
...@@ -142,8 +181,8 @@ SCRIPT_FUNCTION(trim) { ...@@ -142,8 +181,8 @@ SCRIPT_FUNCTION(trim) {
// extract a substring // extract a substring
SCRIPT_FUNCTION(substring) { SCRIPT_FUNCTION(substring) {
SCRIPT_PARAM_C(String, input); SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_DEFAULT(int, begin, 0); SCRIPT_PARAM_DEFAULT_C(int, begin, 0);
SCRIPT_PARAM_DEFAULT(int, end, INT_MAX); SCRIPT_PARAM_DEFAULT_C(int, end, INT_MAX);
if (begin < 0) begin = 0; if (begin < 0) begin = 0;
if (end < 0) end = 0; if (end < 0) end = 0;
if (begin >= end || (size_t)begin >= input.size()) { if (begin >= end || (size_t)begin >= input.size()) {
...@@ -302,7 +341,7 @@ ScriptValueP sort_script(Context& ctx, const ScriptValueP& list, ScriptValue& or ...@@ -302,7 +341,7 @@ ScriptValueP sort_script(Context& ctx, const ScriptValueP& list, ScriptValue& or
} }
sort(values.begin(), values.end(), smart_less_first); sort(values.begin(), values.end(), smart_less_first);
// return collection // return collection
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection()); ScriptCustomCollectionP ret(new ScriptCustomCollection());
FOR_EACH(v, values) { FOR_EACH(v, values) {
ret->value.push_back(v.second); ret->value.push_back(v.second);
} }
...@@ -365,7 +404,7 @@ SCRIPT_FUNCTION(filter_list) { ...@@ -365,7 +404,7 @@ SCRIPT_FUNCTION(filter_list) {
SCRIPT_PARAM_C(ScriptValueP, input); SCRIPT_PARAM_C(ScriptValueP, input);
SCRIPT_PARAM_C(ScriptValueP, filter); SCRIPT_PARAM_C(ScriptValueP, filter);
// filter a collection // filter a collection
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection()); ScriptCustomCollectionP ret(new ScriptCustomCollection());
ScriptValueP it = input->makeIterator(input); ScriptValueP it = input->makeIterator(input);
while (ScriptValueP v = it->next()) { while (ScriptValueP v = it->next()) {
ctx.setVariable(SCRIPT_VAR_input, v); ctx.setVariable(SCRIPT_VAR_input, v);
...@@ -383,6 +422,57 @@ SCRIPT_FUNCTION(sort_list) { ...@@ -383,6 +422,57 @@ SCRIPT_FUNCTION(sort_list) {
return sort_script(ctx, input, *order_by); return sort_script(ctx, input, *order_by);
} }
SCRIPT_FUNCTION(random_shuffle) {
SCRIPT_PARAM_C(ScriptValueP, input);
// convert to CustomCollection
ScriptCustomCollectionP ret(new ScriptCustomCollection());
ScriptValueP it = input->makeIterator(input);
while (ScriptValueP v = it->next()) {
ret->value.push_back(v);
}
// shuffle
random_shuffle(ret->value.begin(), ret->value.end());
return ret;
}
SCRIPT_FUNCTION(random_select) {
SCRIPT_PARAM_C(ScriptValueP, input);
SCRIPT_OPTIONAL_PARAM(int, count) {
// pick a single one
int itemCount = input->itemCount();
if (itemCount == 0) {
throw ScriptError(String::Format(_("Can not select a random item from an empty collection"), count));
}
return input->getIndex( rand() % itemCount );
} else {
// pick many
SCRIPT_PARAM_DEFAULT_C(bool, replace, false);
ScriptCustomCollectionP ret(new ScriptCustomCollection);
int itemCount = input->itemCount();
if (replace) {
if (itemCount == 0) {
throw ScriptError(String::Format(_("Can not select %d items from an empty collection"), count));
}
for (int i = 0 ; i < count ; ++i) {
ret->value.push_back( input->getIndex( rand() % itemCount ) );
}
} else {
if (count > itemCount) {
throw ScriptError(String::Format(_("Can not select %d items from a collection conaining only %d items"), count, input->itemCount()));
}
// transfer all to ret and shuffle
ScriptValueP it = input->makeIterator(input);
while (ScriptValueP v = it->next()) {
ret->value.push_back(v);
}
random_shuffle(ret->value.begin(), ret->value.end());
// keep only the first 'count'
ret->value.resize(count);
}
return ret;
}
}
// ----------------------------------------------------------------------------- : Keywords // ----------------------------------------------------------------------------- : Keywords
...@@ -454,8 +544,13 @@ void init_script_basic_functions(Context& ctx) { ...@@ -454,8 +544,13 @@ void init_script_basic_functions(Context& ctx) {
ctx.setVariable(_("to string"), script_to_string); ctx.setVariable(_("to string"), script_to_string);
ctx.setVariable(_("to int"), script_to_int); ctx.setVariable(_("to int"), script_to_int);
ctx.setVariable(_("to real"), script_to_real); ctx.setVariable(_("to real"), script_to_real);
ctx.setVariable(_("to number"), script_to_number);
ctx.setVariable(_("to boolean"), script_to_boolean); ctx.setVariable(_("to boolean"), script_to_boolean);
ctx.setVariable(_("to color"), script_to_color); ctx.setVariable(_("to color"), script_to_color);
// math
ctx.setVariable(_("abs"), script_abs);
ctx.setVariable(_("random_real"), script_random_real);
ctx.setVariable(_("random_int"), script_random_int);
// string // string
ctx.setVariable(_("to upper"), script_to_upper); ctx.setVariable(_("to upper"), script_to_upper);
ctx.setVariable(_("to lower"), script_to_lower); ctx.setVariable(_("to lower"), script_to_lower);
...@@ -482,6 +577,8 @@ void init_script_basic_functions(Context& ctx) { ...@@ -482,6 +577,8 @@ void init_script_basic_functions(Context& ctx) {
ctx.setVariable(_("number of items"), script_number_of_items); ctx.setVariable(_("number of items"), script_number_of_items);
ctx.setVariable(_("filter list"), script_filter_list); ctx.setVariable(_("filter list"), script_filter_list);
ctx.setVariable(_("sort list"), script_sort_list); ctx.setVariable(_("sort list"), script_sort_list);
ctx.setVariable(_("random shuffle"), script_random_shuffle);
ctx.setVariable(_("random select"), script_random_select);
// keyword // keyword
ctx.setVariable(_("expand keywords"), script_expand_keywords); ctx.setVariable(_("expand keywords"), script_expand_keywords);
ctx.setVariable(_("expand keywords rule"), new_intrusive1<ScriptRule>(script_expand_keywords)); ctx.setVariable(_("expand keywords rule"), new_intrusive1<ScriptRule>(script_expand_keywords));
......
...@@ -344,7 +344,7 @@ class ScriptBreakRule : public ScriptValue { ...@@ -344,7 +344,7 @@ class ScriptBreakRule : public ScriptValue {
virtual String typeName() const { return _("break_rule"); } virtual String typeName() const { return _("break_rule"); }
virtual ScriptValueP eval(Context& ctx) const { virtual ScriptValueP eval(Context& ctx) const {
SCRIPT_PARAM_C(String, input); SCRIPT_PARAM_C(String, input);
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection); ScriptCustomCollectionP ret(new ScriptCustomCollection);
while (regex.Matches(input)) { while (regex.Matches(input)) {
// match, append to result // match, append to result
size_t start, len; size_t start, len;
...@@ -393,7 +393,7 @@ SCRIPT_FUNCTION_WITH_SIMPLIFY(break_text) { ...@@ -393,7 +393,7 @@ SCRIPT_FUNCTION_WITH_SIMPLIFY(break_text) {
SCRIPT_PARAM_C(String, input); SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_C(ScriptRegexP, match); SCRIPT_PARAM_C(ScriptRegexP, match);
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context); SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection); ScriptCustomCollectionP ret(new ScriptCustomCollection);
// find all matches // find all matches
while (match->regex.Matches(input)) { while (match->regex.Matches(input)) {
// match, append to result // match, append to result
......
...@@ -119,8 +119,7 @@ class TokenIterator { ...@@ -119,8 +119,7 @@ class TokenIterator {
bool isAlpha_(Char c) { return isAlpha(c) || c==_('_'); } bool isAlpha_(Char c) { return isAlpha(c) || c==_('_'); }
bool isAlnum_(Char c) { return isAlnum(c) || c==_('_'); } bool isAlnum_(Char c) { return isAlnum(c) || c==_('_'); }
bool isOper (Char c) { return c==_('+') || c==_('-') || c==_('*') || c==_('/') || c==_('!') || c==_('.') || c==_('@') || bool isOper (Char c) { return wxStrchr(_("+-*/!.@%^&:=<>;,"),c) != nullptr; }
c==_(':') || c==_('=') || c==_('<') || c==_('>') || c==_(';') || c==_(','); }
bool isLparen(Char c) { return c==_('(') || c==_('[') || c==_('{'); } bool isLparen(Char c) { return c==_('(') || c==_('[') || c==_('{'); }
bool isRparen(Char c) { return c==_(')') || c==_(']') || c==_('}'); } bool isRparen(Char c) { return c==_(')') || c==_(']') || c==_('}'); }
bool isDigitOrDot(Char c) { return isDigit(c) || c==_('.'); } bool isDigitOrDot(Char c) { return isDigit(c) || c==_('.'); }
...@@ -347,6 +346,7 @@ enum Precedence ...@@ -347,6 +346,7 @@ enum Precedence
, PREC_CMP // == != < > <= >= , PREC_CMP // == != < > <= >=
, PREC_ADD // + - , PREC_ADD // + -
, PREC_MUL // * / mod , PREC_MUL // * / mod
, PREC_POW // ^ (right associative)
, PREC_UNARY // - not (unary operators) , PREC_UNARY // - not (unary operators)
, PREC_FUN // [] () . (function call, member) , PREC_FUN // [] () . (function call, member)
, PREC_STRING // +{ }+ (smart string operators) , PREC_STRING // +{ }+ (smart string operators)
...@@ -680,10 +680,11 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc ...@@ -680,10 +680,11 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
else if (minPrec <= PREC_CMP && token==_(">=")) parseOper(input, script, PREC_ADD, I_BINARY, I_GE); else if (minPrec <= PREC_CMP && token==_(">=")) parseOper(input, script, PREC_ADD, I_BINARY, I_GE);
else if (minPrec <= PREC_ADD && token==_("+")) parseOper(input, script, PREC_MUL, I_BINARY, I_ADD); else if (minPrec <= PREC_ADD && token==_("+")) parseOper(input, script, PREC_MUL, I_BINARY, I_ADD);
else if (minPrec <= PREC_ADD && token==_("-")) parseOper(input, script, PREC_MUL, I_BINARY, I_SUB); else if (minPrec <= PREC_ADD && token==_("-")) parseOper(input, script, PREC_MUL, I_BINARY, I_SUB);
else if (minPrec <= PREC_MUL && token==_("*")) parseOper(input, script, PREC_UNARY, I_BINARY, I_MUL); else if (minPrec <= PREC_MUL && token==_("*")) parseOper(input, script, PREC_POW, I_BINARY, I_MUL);
else if (minPrec <= PREC_MUL && token==_("/")) parseOper(input, script, PREC_UNARY, I_BINARY, I_FDIV); else if (minPrec <= PREC_MUL && token==_("/")) parseOper(input, script, PREC_POW, I_BINARY, I_FDIV);
else if (minPrec <= PREC_MUL && token==_("div")) parseOper(input, script, PREC_UNARY, I_BINARY, I_DIV); else if (minPrec <= PREC_MUL && token==_("div")) parseOper(input, script, PREC_POW, I_BINARY, I_DIV);
else if (minPrec <= PREC_MUL && token==_("mod")) parseOper(input, script, PREC_UNARY, I_BINARY, I_MOD); else if (minPrec <= PREC_MUL && token==_("mod")) parseOper(input, script, PREC_POW, I_BINARY, I_MOD);
else if (minPrec <= PREC_POW && token==_("^")) parseOper(input, script, PREC_POW, I_BINARY, I_POW);
else if (minPrec <= PREC_FUN && token==_(".")) { // get member by name else if (minPrec <= PREC_FUN && token==_(".")) { // get member by name
const Token& token = input.read(); const Token& token = input.read();
if (token == TOK_NAME || token == TOK_INT || token == TOK_DOUBLE || token == TOK_STRING) { if (token == TOK_NAME || token == TOK_INT || token == TOK_DOUBLE || token == TOK_STRING) {
......
...@@ -58,6 +58,8 @@ void init_script_variables() { ...@@ -58,6 +58,8 @@ void init_script_variables() {
VarN(in_context,_("in context")); VarN(in_context,_("in context"));
Var(recursive); Var(recursive);
Var(order); Var(order);
Var(begin);
Var(end);
Var(filter); Var(filter);
Var(choice); Var(choice);
Var(choices); Var(choices);
......
No preview for this file type
...@@ -119,12 +119,11 @@ class ScriptCollection : public ScriptValue { ...@@ -119,12 +119,11 @@ class ScriptCollection : public ScriptValue {
inline ScriptCollection(const Collection* v) : value(v) {} inline ScriptCollection(const Collection* v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_COLLECTION; } virtual ScriptType type() const { return SCRIPT_COLLECTION; }
virtual String typeName() const { return _TYPE_1_("collection of", type_name(*value->begin())); } virtual String typeName() const { return _TYPE_1_("collection of", type_name(*value->begin())); }
virtual ScriptValueP getMember(const String& name) const { virtual ScriptValueP getIndex(int index) const {
long index; if (index >= 0 && index < (int)value->size()) {
if (name.ToLong(&index) && index >= 0 && (size_t)index < value->size()) {
return to_script(value->at(index)); return to_script(value->at(index));
} else { } else {
return ScriptValue::getMember(name); return ScriptValue::getIndex(index);
} }
} }
virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const { virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const {
...@@ -196,6 +195,7 @@ class ScriptCustomCollection : public ScriptValue { ...@@ -196,6 +195,7 @@ class ScriptCustomCollection : public ScriptValue {
virtual ScriptType type() const { return SCRIPT_COLLECTION; } virtual ScriptType type() const { return SCRIPT_COLLECTION; }
virtual String typeName() const { return _TYPE_("collection"); } virtual String typeName() const { return _TYPE_("collection"); }
virtual ScriptValueP getMember(const String& name) const; virtual ScriptValueP getMember(const String& name) const;
virtual ScriptValueP getIndex(int index) const;
virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const; virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const;
virtual int itemCount() const { return (int)value.size(); } virtual int itemCount() const { return (int)value.size(); }
/// Collections can be compared by comparing pointers /// Collections can be compared by comparing pointers
...@@ -210,6 +210,8 @@ class ScriptCustomCollection : public ScriptValue { ...@@ -210,6 +210,8 @@ class ScriptCustomCollection : public ScriptValue {
map<String,ScriptValueP> key_value; map<String,ScriptValueP> key_value;
}; };
DECLARE_POINTER_TYPE(ScriptCustomCollection);
// ----------------------------------------------------------------------------- : Collections : concatenation // ----------------------------------------------------------------------------- : Collections : concatenation
/// Script value containing the concatenation of two collections /// Script value containing the concatenation of two collections
...@@ -219,6 +221,7 @@ class ScriptConcatCollection : public ScriptValue { ...@@ -219,6 +221,7 @@ class ScriptConcatCollection : public ScriptValue {
virtual ScriptType type() const { return SCRIPT_COLLECTION; } virtual ScriptType type() const { return SCRIPT_COLLECTION; }
virtual String typeName() const { return _TYPE_("collection"); } virtual String typeName() const { return _TYPE_("collection"); }
virtual ScriptValueP getMember(const String& name) const; virtual ScriptValueP getMember(const String& name) const;
virtual ScriptValueP getIndex(int index) const;
virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const; virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const;
virtual int itemCount() const { return a->itemCount() + b->itemCount(); } virtual int itemCount() const { return a->itemCount() + b->itemCount(); }
/// Collections can be compared by comparing pointers /// Collections can be compared by comparing pointers
...@@ -260,6 +263,7 @@ class ScriptObject : public ScriptValue { ...@@ -260,6 +263,7 @@ class ScriptObject : public ScriptValue {
} }
} }
} }
virtual ScriptValueP getIndex(int index) const { ScriptValueP d = getDefault(); return d ? d->getIndex(index) : ScriptValue::getIndex(index); }
virtual ScriptValueP dependencyMember(const String& name, const Dependency& dep) const { virtual ScriptValueP dependencyMember(const String& name, const Dependency& dep) const {
mark_dependency_member(*value, name, dep); mark_dependency_member(*value, name, dep);
return getMember(name); return getMember(name);
......
...@@ -24,7 +24,6 @@ ScriptValue::operator bool() const { throw Script ...@@ -24,7 +24,6 @@ ScriptValue::operator bool() const { throw Script
ScriptValue::operator double() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("double" ))); } ScriptValue::operator double() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("double" ))); }
ScriptValue::operator AColor() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("color" ))); } ScriptValue::operator AColor() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("color" ))); }
ScriptValueP ScriptValue::eval(Context&) const { return delayError(_ERROR_2_("can't convert", typeName(), _TYPE_("function"))); } ScriptValueP ScriptValue::eval(Context&) const { return delayError(_ERROR_2_("can't convert", typeName(), _TYPE_("function"))); }
ScriptValueP ScriptValue::getMember(const String& name) const { return delayError(_ERROR_2_("has no member", typeName(), name)); }
ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); } ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); }
ScriptValueP ScriptValue::makeIterator(const ScriptValueP&) const { return delayError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); } ScriptValueP ScriptValue::makeIterator(const ScriptValueP&) const { return delayError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); }
int ScriptValue::itemCount() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); } int ScriptValue::itemCount() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); }
...@@ -32,12 +31,28 @@ CompareWhat ScriptValue::compareAs(String& compare_str, void const*& compare_pt ...@@ -32,12 +31,28 @@ CompareWhat ScriptValue::compareAs(String& compare_str, void const*& compare_pt
compare_str = toString(); compare_str = toString();
return COMPARE_AS_STRING; return COMPARE_AS_STRING;
} }
ScriptValueP ScriptValue::getMember(const String& name) const {
long index;
if (name.ToLong(&index)) {
return getIndex(index);
} else {
return delayError(_ERROR_2_("has no member", typeName(), name));
}
}
ScriptValueP ScriptValue::getIndex(int index) const {
return delayError(_ERROR_2_("has no member", typeName(), String()<<index));
}
ScriptValueP ScriptValue::simplifyClosure(ScriptClosure&) const { return ScriptValueP(); } ScriptValueP ScriptValue::simplifyClosure(ScriptClosure&) const { return ScriptValueP(); }
ScriptValueP ScriptValue::dependencyMember(const String& name, 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; } ScriptValueP ScriptValue::dependencies(Context&, const Dependency&) const { return dependency_dummy; }
bool approx_equal(double a, double b) {
return a == b || fabs(a - b) < 1e-14;
}
/// compare script values for equallity /// compare script values for equallity
bool equal(const ScriptValueP& a, const ScriptValueP& b) { bool equal(const ScriptValueP& a, const ScriptValueP& b) {
if (a == b) return true; if (a == b) return true;
...@@ -48,7 +63,7 @@ bool equal(const ScriptValueP& a, const ScriptValueP& b) { ...@@ -48,7 +63,7 @@ bool equal(const ScriptValueP& a, const ScriptValueP& b) {
return (bool)*a == (bool)*b; return (bool)*a == (bool)*b;
} else if ((at == SCRIPT_INT || at == SCRIPT_DOUBLE) && } else if ((at == SCRIPT_INT || at == SCRIPT_DOUBLE) &&
(bt == SCRIPT_INT || bt == SCRIPT_DOUBLE)) { (bt == SCRIPT_INT || bt == SCRIPT_DOUBLE)) {
return (double)*a == (double)*b; return approx_equal( (double)*a, (double)*b);
} else if (at == SCRIPT_COLLECTION && bt == SCRIPT_COLLECTION) { } else if (at == SCRIPT_COLLECTION && bt == SCRIPT_COLLECTION) {
// compare each element // compare each element
if (a->itemCount() != b->itemCount()) return false; if (a->itemCount() != b->itemCount()) return false;
...@@ -338,12 +353,14 @@ ScriptValueP ScriptCustomCollection::getMember(const String& name) const { ...@@ -338,12 +353,14 @@ ScriptValueP ScriptCustomCollection::getMember(const String& name) const {
if (it != key_value.end()) { if (it != key_value.end()) {
return it->second; return it->second;
} else { } else {
long index; return ScriptValue::getMember(name);
if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) { }
return value.at(index); }
} else { ScriptValueP ScriptCustomCollection::getIndex(int index) const {
return ScriptValue::getMember(name); if (index >= 0 && (size_t)index < value.size()) {
} return value.at(index);
} else {
return ScriptValue::getIndex(index);
} }
} }
ScriptValueP ScriptCustomCollection::makeIterator(const ScriptValueP& thisP) const { ScriptValueP ScriptCustomCollection::makeIterator(const ScriptValueP& thisP) const {
...@@ -381,6 +398,14 @@ ScriptValueP ScriptConcatCollection::getMember(const String& name) const { ...@@ -381,6 +398,14 @@ ScriptValueP ScriptConcatCollection::getMember(const String& name) const {
return b->getMember(name); return b->getMember(name);
} }
} }
ScriptValueP ScriptConcatCollection::getIndex(int index) const {
int itemsInA = a->itemCount();
if (index < itemsInA) {
return a->getIndex(index);
} else {
return b->getIndex(index - itemsInA);
}
}
ScriptValueP ScriptConcatCollection::makeIterator(const ScriptValueP& thisP) const { ScriptValueP ScriptConcatCollection::makeIterator(const ScriptValueP& thisP) const {
return new_intrusive2<ScriptConcatCollectionIterator>(a->makeIterator(a), b->makeIterator(b)); return new_intrusive2<ScriptConcatCollectionIterator>(a->makeIterator(a), b->makeIterator(b));
} }
......
...@@ -96,6 +96,8 @@ class ScriptValue : public IntrusivePtrBaseWithDelete { ...@@ -96,6 +96,8 @@ class ScriptValue : public IntrusivePtrBaseWithDelete {
virtual ScriptValueP next(); virtual ScriptValueP next();
/// Return the number of items in this value (assuming it is a collection) /// Return the number of items in this value (assuming it is a collection)
virtual int itemCount() const; virtual int itemCount() const;
/// Get a member at the given index
virtual ScriptValueP getIndex(int index) const;
}; };
extern ScriptValueP script_nil; ///< The preallocated nil value extern ScriptValueP script_nil; ///< The preallocated nil value
......
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