mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
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. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1013 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -402,6 +402,13 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
|
||||
a = to_script((int)*a % (int)*b);
|
||||
}
|
||||
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_OR: OPERATOR_B(||);
|
||||
case I_XOR: OPERATOR_B(!=);
|
||||
@@ -442,7 +449,7 @@ void instrQuaternary(QuaternaryInstructionType i, ScriptValueP& a, const ScriptV
|
||||
// ----------------------------------------------------------------------------- : Simple instructions : objects and closures
|
||||
|
||||
void Context::makeObject(size_t n) {
|
||||
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection());
|
||||
ScriptCustomCollectionP ret(new ScriptCustomCollection());
|
||||
size_t begin = stack.size() - 2 * n;
|
||||
for (size_t i = 0 ; i < n ; ++i) {
|
||||
const ScriptValueP& key = stack[begin + 2 * i];
|
||||
|
||||
@@ -89,6 +89,21 @@ SCRIPT_FUNCTION(to_real) {
|
||||
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) {
|
||||
ScriptValueP input = ctx.getVariable(SCRIPT_VAR_input);
|
||||
ScriptType t = input->type();
|
||||
@@ -106,6 +121,30 @@ SCRIPT_FUNCTION(to_color) {
|
||||
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
|
||||
|
||||
// convert a string to upper case
|
||||
@@ -142,8 +181,8 @@ SCRIPT_FUNCTION(trim) {
|
||||
// extract a substring
|
||||
SCRIPT_FUNCTION(substring) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_DEFAULT(int, begin, 0);
|
||||
SCRIPT_PARAM_DEFAULT(int, end, INT_MAX);
|
||||
SCRIPT_PARAM_DEFAULT_C(int, begin, 0);
|
||||
SCRIPT_PARAM_DEFAULT_C(int, end, INT_MAX);
|
||||
if (begin < 0) begin = 0;
|
||||
if (end < 0) end = 0;
|
||||
if (begin >= end || (size_t)begin >= input.size()) {
|
||||
@@ -302,7 +341,7 @@ ScriptValueP sort_script(Context& ctx, const ScriptValueP& list, ScriptValue& or
|
||||
}
|
||||
sort(values.begin(), values.end(), smart_less_first);
|
||||
// return collection
|
||||
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection());
|
||||
ScriptCustomCollectionP ret(new ScriptCustomCollection());
|
||||
FOR_EACH(v, values) {
|
||||
ret->value.push_back(v.second);
|
||||
}
|
||||
@@ -365,7 +404,7 @@ SCRIPT_FUNCTION(filter_list) {
|
||||
SCRIPT_PARAM_C(ScriptValueP, input);
|
||||
SCRIPT_PARAM_C(ScriptValueP, filter);
|
||||
// filter a collection
|
||||
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection());
|
||||
ScriptCustomCollectionP ret(new ScriptCustomCollection());
|
||||
ScriptValueP it = input->makeIterator(input);
|
||||
while (ScriptValueP v = it->next()) {
|
||||
ctx.setVariable(SCRIPT_VAR_input, v);
|
||||
@@ -383,6 +422,57 @@ SCRIPT_FUNCTION(sort_list) {
|
||||
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
|
||||
|
||||
|
||||
@@ -454,8 +544,13 @@ void init_script_basic_functions(Context& ctx) {
|
||||
ctx.setVariable(_("to string"), script_to_string);
|
||||
ctx.setVariable(_("to int"), script_to_int);
|
||||
ctx.setVariable(_("to real"), script_to_real);
|
||||
ctx.setVariable(_("to number"), script_to_number);
|
||||
ctx.setVariable(_("to boolean"), script_to_boolean);
|
||||
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
|
||||
ctx.setVariable(_("to upper"), script_to_upper);
|
||||
ctx.setVariable(_("to lower"), script_to_lower);
|
||||
@@ -482,6 +577,8 @@ void init_script_basic_functions(Context& ctx) {
|
||||
ctx.setVariable(_("number of items"), script_number_of_items);
|
||||
ctx.setVariable(_("filter list"), script_filter_list);
|
||||
ctx.setVariable(_("sort list"), script_sort_list);
|
||||
ctx.setVariable(_("random shuffle"), script_random_shuffle);
|
||||
ctx.setVariable(_("random select"), script_random_select);
|
||||
// keyword
|
||||
ctx.setVariable(_("expand keywords"), script_expand_keywords);
|
||||
ctx.setVariable(_("expand keywords rule"), new_intrusive1<ScriptRule>(script_expand_keywords));
|
||||
|
||||
@@ -344,7 +344,7 @@ class ScriptBreakRule : public ScriptValue {
|
||||
virtual String typeName() const { return _("break_rule"); }
|
||||
virtual ScriptValueP eval(Context& ctx) const {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection);
|
||||
ScriptCustomCollectionP ret(new ScriptCustomCollection);
|
||||
while (regex.Matches(input)) {
|
||||
// match, append to result
|
||||
size_t start, len;
|
||||
@@ -393,7 +393,7 @@ SCRIPT_FUNCTION_WITH_SIMPLIFY(break_text) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_C(ScriptRegexP, match);
|
||||
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
|
||||
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection);
|
||||
ScriptCustomCollectionP ret(new ScriptCustomCollection);
|
||||
// find all matches
|
||||
while (match->regex.Matches(input)) {
|
||||
// match, append to result
|
||||
|
||||
@@ -119,8 +119,7 @@ class TokenIterator {
|
||||
|
||||
bool isAlpha_(Char c) { return isAlpha(c) || c==_('_'); }
|
||||
bool isAlnum_(Char c) { return isAlnum(c) || c==_('_'); }
|
||||
bool isOper (Char c) { return c==_('+') || c==_('-') || c==_('*') || c==_('/') || c==_('!') || c==_('.') || c==_('@') ||
|
||||
c==_(':') || c==_('=') || c==_('<') || c==_('>') || c==_(';') || c==_(','); }
|
||||
bool isOper (Char c) { return wxStrchr(_("+-*/!.@%^&:=<>;,"),c) != nullptr; }
|
||||
bool isLparen(Char c) { return c==_('(') || c==_('[') || c==_('{'); }
|
||||
bool isRparen(Char c) { return c==_(')') || c==_(']') || c==_('}'); }
|
||||
bool isDigitOrDot(Char c) { return isDigit(c) || c==_('.'); }
|
||||
@@ -347,6 +346,7 @@ enum Precedence
|
||||
, PREC_CMP // == != < > <= >=
|
||||
, PREC_ADD // + -
|
||||
, PREC_MUL // * / mod
|
||||
, PREC_POW // ^ (right associative)
|
||||
, PREC_UNARY // - not (unary operators)
|
||||
, PREC_FUN // [] () . (function call, member)
|
||||
, PREC_STRING // +{ }+ (smart string operators)
|
||||
@@ -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_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_MUL && token==_("*")) parseOper(input, script, PREC_UNARY, 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==_("div")) parseOper(input, script, PREC_UNARY, 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==_("*")) parseOper(input, script, PREC_POW, I_BINARY, I_MUL);
|
||||
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_POW, I_BINARY, I_DIV);
|
||||
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
|
||||
const Token& token = input.read();
|
||||
if (token == TOK_NAME || token == TOK_INT || token == TOK_DOUBLE || token == TOK_STRING) {
|
||||
|
||||
@@ -58,6 +58,8 @@ void init_script_variables() {
|
||||
VarN(in_context,_("in context"));
|
||||
Var(recursive);
|
||||
Var(order);
|
||||
Var(begin);
|
||||
Var(end);
|
||||
Var(filter);
|
||||
Var(choice);
|
||||
Var(choices);
|
||||
|
||||
@@ -63,6 +63,7 @@ enum BinaryInstructionType
|
||||
, I_FDIV ///< floating point division
|
||||
, I_DIV ///< integer division
|
||||
, I_MOD ///< modulus
|
||||
, I_POW ///< power
|
||||
// Logical
|
||||
, I_AND ///< logical and
|
||||
, I_OR ///< logical or
|
||||
@@ -116,6 +117,8 @@ enum Variable
|
||||
, SCRIPT_VAR_in_context
|
||||
, SCRIPT_VAR_recursive
|
||||
, SCRIPT_VAR_order
|
||||
, SCRIPT_VAR_begin
|
||||
, SCRIPT_VAR_end
|
||||
, SCRIPT_VAR_filter
|
||||
, SCRIPT_VAR_choice
|
||||
, SCRIPT_VAR_choices
|
||||
|
||||
@@ -119,12 +119,11 @@ class ScriptCollection : public ScriptValue {
|
||||
inline ScriptCollection(const Collection* v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
|
||||
virtual String typeName() const { return _TYPE_1_("collection of", type_name(*value->begin())); }
|
||||
virtual ScriptValueP getMember(const String& name) const {
|
||||
long index;
|
||||
if (name.ToLong(&index) && index >= 0 && (size_t)index < value->size()) {
|
||||
virtual ScriptValueP getIndex(int index) const {
|
||||
if (index >= 0 && index < (int)value->size()) {
|
||||
return to_script(value->at(index));
|
||||
} else {
|
||||
return ScriptValue::getMember(name);
|
||||
return ScriptValue::getIndex(index);
|
||||
}
|
||||
}
|
||||
virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const {
|
||||
@@ -196,6 +195,7 @@ class ScriptCustomCollection : public ScriptValue {
|
||||
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
|
||||
virtual String typeName() const { return _TYPE_("collection"); }
|
||||
virtual ScriptValueP getMember(const String& name) const;
|
||||
virtual ScriptValueP getIndex(int index) const;
|
||||
virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const;
|
||||
virtual int itemCount() const { return (int)value.size(); }
|
||||
/// Collections can be compared by comparing pointers
|
||||
@@ -210,6 +210,8 @@ class ScriptCustomCollection : public ScriptValue {
|
||||
map<String,ScriptValueP> key_value;
|
||||
};
|
||||
|
||||
DECLARE_POINTER_TYPE(ScriptCustomCollection);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Collections : concatenation
|
||||
|
||||
/// Script value containing the concatenation of two collections
|
||||
@@ -219,6 +221,7 @@ class ScriptConcatCollection : public ScriptValue {
|
||||
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
|
||||
virtual String typeName() const { return _TYPE_("collection"); }
|
||||
virtual ScriptValueP getMember(const String& name) const;
|
||||
virtual ScriptValueP getIndex(int index) const;
|
||||
virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const;
|
||||
virtual int itemCount() const { return a->itemCount() + b->itemCount(); }
|
||||
/// Collections can be compared by comparing pointers
|
||||
@@ -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 {
|
||||
mark_dependency_member(*value, name, dep);
|
||||
return getMember(name);
|
||||
|
||||
+33
-8
@@ -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 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::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::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"))); }
|
||||
@@ -32,12 +31,28 @@ CompareWhat ScriptValue::compareAs(String& compare_str, void const*& compare_pt
|
||||
compare_str = toString();
|
||||
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::dependencyMember(const String& name, 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
|
||||
bool equal(const ScriptValueP& a, const ScriptValueP& b) {
|
||||
if (a == b) return true;
|
||||
@@ -48,7 +63,7 @@ bool equal(const ScriptValueP& a, const ScriptValueP& b) {
|
||||
return (bool)*a == (bool)*b;
|
||||
} else if ((at == SCRIPT_INT || at == 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) {
|
||||
// compare each element
|
||||
if (a->itemCount() != b->itemCount()) return false;
|
||||
@@ -338,12 +353,14 @@ ScriptValueP ScriptCustomCollection::getMember(const String& name) const {
|
||||
if (it != key_value.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
long index;
|
||||
if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) {
|
||||
return value.at(index);
|
||||
} else {
|
||||
return ScriptValue::getMember(name);
|
||||
}
|
||||
return ScriptValue::getMember(name);
|
||||
}
|
||||
}
|
||||
ScriptValueP ScriptCustomCollection::getIndex(int index) const {
|
||||
if (index >= 0 && (size_t)index < value.size()) {
|
||||
return value.at(index);
|
||||
} else {
|
||||
return ScriptValue::getIndex(index);
|
||||
}
|
||||
}
|
||||
ScriptValueP ScriptCustomCollection::makeIterator(const ScriptValueP& thisP) const {
|
||||
@@ -381,6 +398,14 @@ ScriptValueP ScriptConcatCollection::getMember(const String& name) const {
|
||||
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 {
|
||||
return new_intrusive2<ScriptConcatCollectionIterator>(a->makeIterator(a), b->makeIterator(b));
|
||||
}
|
||||
|
||||
@@ -96,6 +96,8 @@ class ScriptValue : public IntrusivePtrBaseWithDelete {
|
||||
virtual ScriptValueP next();
|
||||
/// Return the number of items in this value (assuming it is a collection)
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user