diff --git a/doc/script/operators.txt b/doc/script/operators.txt index 2f9f1157..bac3bf41 100644 --- a/doc/script/operators.txt +++ b/doc/script/operators.txt @@ -9,8 +9,8 @@ MSE script supports most basic mathamatical operators: @"3" + "2" == "32"@ concatenate two strings or compose two functions (see below) | @a - b@ @3 - 2 == 1@ Substract two numbers | @a * b@ @3 * 2 == 6@ Multiply two numbers -| @a / b@ @3 / 2 == 1@
Divide two numbers.
Rounds towards zero for [[type:int]]s.
- @3 / 2.0 == 1.5@ Does not round for [[type:double]]s. +| @a / b@ @3 / 2 == 1.5@ Divide two numbers. Does not round, always produces a [[type:double]]. +| @a div b@ @3 div 2 == 1@ Divide two numbers. Rounds towards zero, producing an [[type:int]].
| @a mod b@ @3 mod 2 == 1@ Take the remainder after integer division (modulo) | @-a@ @-(3 + 2) == -5@ Negate a number (make it negative if positive and vice versa) @@ -36,6 +36,8 @@ It is also possible to compare values. All comparisons evaluate to either @true@ @"x" <= "y"@ Is a less than b or are they equal? | @a >= b@ @2 >= 1@
@"x" >= "x"@ Is a greater than b or are they equal? +| @min(a,b)@ @min(1,2) == 1@ Returns the smallest of two values. +| @max(a,b)@ @max(1,2) == 2@ Returns the largest of two values. --Booleans-- [[type:Boolean]]s (for example from comparisons) can be combined using: @@ -60,13 +62,13 @@ Operators can be grouped differently using parentheses. The exact order of precedence is given in the following table, higher in the table means that this operator binds tighter to its arguments, @*@ binds tighter then @+@. | @a(...)@, @a.b@, @a[b]@ Function calls, property access, see below -| @-a@, @not@ Unary operators -| @*@, @/@, @mod@ Multiplication and division -| @+@, @-@ Addition and substraction +| @-a@, @not@ Unary operators +| @*@, @/@, @div@, @mod@ Multiplication and division +| @+@, @-@ Addition and substraction | @==@, @!=@, @<@, @>@, @<=@, @>=@ Comparisons -| @and@, @or@, @xor@ Boolean operators -| @:=@ Assignement, see below -| @;@ Sequence, see below +| @and@, @or@, @xor@ Boolean operators +| @:=@ Assignement, see below +| @;@ Sequence, see below --Properties-- Properties of types, as described in the [[type:index|data type section]] of the documentation, can be accessed using the @.@ operator: diff --git a/src/script/context.cpp b/src/script/context.cpp index 3e1431f7..eccad998 100644 --- a/src/script/context.cpp +++ b/src/script/context.cpp @@ -138,6 +138,12 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { break; } + // Closure object + case I_CLOSURE: { + makeClosure(i.data); + break; + } + // Simple instruction: unary case I_UNARY: { instrUnary(i.instr1, stack.back()); @@ -278,18 +284,6 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) { } \ break -// operator on strings or doubles or ints, when in doubt, uses strings -#define OPERATOR_SDI(OP) \ - if (at == SCRIPT_INT && bt == SCRIPT_INT) { \ - a = to_script((int)*a OP (int)*b); \ - } else if ((at == SCRIPT_INT || at == SCRIPT_DOUBLE) && \ - (bt == SCRIPT_INT || bt == SCRIPT_DOUBLE)) { \ - a = to_script((double)*a OP (double)*b); \ - } else { \ - a = to_script(a->toString() OP b->toString()); \ - } \ - break - /// Composition of two functions class ScriptCompose : public ScriptValue { public: @@ -330,6 +324,8 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& // a = a; } else if (at == SCRIPT_FUNCTION && bt == SCRIPT_FUNCTION) { a = new_intrusive2(a, b); + } else if (at == SCRIPT_COLLECTION && bt == SCRIPT_COLLECTION) { + a = new_intrusive2(a, b); } else if (at == SCRIPT_INT && bt == SCRIPT_INT) { a = to_script((int)*a + (int)*b); } else if ((at == SCRIPT_INT || at == SCRIPT_DOUBLE) && @@ -341,7 +337,16 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& break; case I_SUB: OPERATOR_DI(-); case I_MUL: OPERATOR_DI(*); - case I_DIV: OPERATOR_DI(/); + case I_FDIV: + a = to_script((double)*a / (double)*b); + break; + case I_DIV: + if (at == SCRIPT_DOUBLE || bt == SCRIPT_DOUBLE) { + a = to_script((int)((double)*a / (double)*b)); + } else { + a = to_script((int)*a / (int)*b); + } + break; case I_MOD: if (at == SCRIPT_DOUBLE || bt == SCRIPT_DOUBLE) { a = to_script(fmod((double)*a, (double)*b)); @@ -352,8 +357,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: OPERATOR_SDI(==); - case I_NEQ: OPERATOR_SDI(!=); + 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(<=); @@ -386,7 +391,7 @@ void instrQuaternary(QuaternaryInstructionType i, ScriptValueP& a, const ScriptV } } -// ----------------------------------------------------------------------------- : Simple instructions : object +// ----------------------------------------------------------------------------- : Simple instructions : objects and closures void Context::makeObject(size_t n) { intrusive_ptr ret(new ScriptCustomCollection()); @@ -402,3 +407,10 @@ void Context::makeObject(size_t n) { stack.resize(begin); stack.push_back(ret); } + +void Context::makeClosure(size_t n) { + //intrusive_ptr ret(new ScriptClosure()); + // TODO + //stack.push_back(ret); + throw InternalError(_("TODO: makeClosure")); +} diff --git a/src/script/context.hpp b/src/script/context.hpp index d8de3cc1..4b58faa8 100644 --- a/src/script/context.hpp +++ b/src/script/context.hpp @@ -101,6 +101,8 @@ class Context { void resetBindings(size_t scope); /// Make an object with n elements, popping 2n values from the stack, and push it onto the stack void makeObject(size_t n); + /// Make a closure with n arguments + void makeClosure(size_t n); }; /// A class that creates a local scope diff --git a/src/script/dependency.cpp b/src/script/dependency.cpp index 75007231..d0644b57 100644 --- a/src/script/dependency.cpp +++ b/src/script/dependency.cpp @@ -250,6 +250,12 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) break; } + // Closure object + case I_CLOSURE: { + makeClosure(i.data); + break; + } + // Get a variable (almost as normal) case I_GET_VAR: { ScriptValueP value = variables[i.data].value; diff --git a/src/script/functions/basic.cpp b/src/script/functions/basic.cpp index c64f5250..394a06cd 100644 --- a/src/script/functions/basic.cpp +++ b/src/script/functions/basic.cpp @@ -173,24 +173,6 @@ SCRIPT_FUNCTION(remove_tags) { // ----------------------------------------------------------------------------- : Collection stuff -/// 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(); - if (at != bt) { - return false; - } else if (at == SCRIPT_INT) { - return (int)a == (int)b; - } else if (at == SCRIPT_DOUBLE) { - return (double)a == (double)b; - } else if (at == SCRIPT_STRING) { - return a.toString() == b.toString(); - } else { - // compare pointers, must be equal and not null - const void *ap = a.comparePointer(), *bp = b.comparePointer(); - return (ap && ap == bp); - } -} /// position of some element in a vector /** 0 based index, -1 if not found */ diff --git a/src/script/parser.cpp b/src/script/parser.cpp index 71591152..47761076 100644 --- a/src/script/parser.cpp +++ b/src/script/parser.cpp @@ -112,7 +112,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==_('.') || +bool isOper (Char c) { return c==_('+') || c==_('-') || c==_('*') || c==_('/') || c==_('!') || c==_('.') || c==_('@') || c==_(':') || c==_('=') || c==_('<') || c==_('>') || c==_(';') || c==_(','); } bool isLparen(Char c) { return c==_('(') || c==_('[') || c==_('{'); } bool isRparen(Char c) { return c==_(')') || c==_(']') || c==_('}'); } @@ -623,7 +623,8 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc 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_DIV); + 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_FUN && token==_(".")) { // get member by name const Token& token = input.read(); @@ -655,6 +656,16 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc FOR_EACH(arg,arguments) { script.addInstruction(I_NOP, arg); } + } else if (minPrec <= PREC_FUN && token==_("@")) { + // closure call, read arguments + expectToken(input, _("(")); + vector arguments; + parseCallArguments(input, script, arguments); + // generate instruction + script.addInstruction(I_CLOSURE, (unsigned int)arguments.size()); + FOR_EACH(arg,arguments) { + script.addInstruction(I_NOP, arg); + } } else if (minPrec <= PREC_STRING && token==_("\"{")) { // for smart strings: "x" {{ e }} "y" // optimize: "" + e -> e diff --git a/src/script/script.cpp b/src/script/script.cpp index 905d0980..678d6ee8 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -154,6 +154,7 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const { case I_LOOP: ret += _("loop"); break; case I_MAKE_OBJECT: ret += _("make object");break; case I_CALL: ret += _("call"); break; + case I_CLOSURE: ret += _("closure"); break; case I_UNARY: ret += _("unary\t"); switch (i.instr1) { case I_ITERATOR_C: ret += _("iterator_c"); break; @@ -200,7 +201,7 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const { ret += _("\t") + constants[i.data]->toString(); ret += _("\t(") + constants[i.data]->typeName() + _(")"); break; - case I_JUMP: case I_JUMP_IF_NOT: case I_LOOP: case I_CALL: // int + case I_JUMP: case I_JUMP_IF_NOT: case I_LOOP: case I_MAKE_OBJECT: case I_CALL: case I_CLOSURE: // int ret += String::Format(_("\t%d"), i.data); break; case I_GET_VAR: case I_SET_VAR: case I_NOP: // variable @@ -235,7 +236,7 @@ const Instruction* Script::backtraceSkip(const Instruction* instr, int to_skip) to_skip += 2; break; // nett stack effect 1-3 == -2 case I_QUATERNARY: to_skip += 3; break; // nett stack effect 1-4 == -3 - case I_CALL: + case I_CALL: case I_CLOSURE: to_skip += instr->data; // arguments of call break; case I_MAKE_OBJECT: @@ -299,13 +300,15 @@ String Script::instructionName(const Instruction* instr) const { + _(".") + constants[instr->data]->toString(); } else if (instr->instr == I_BINARY && instr->instr2 == I_MEMBER) { - throw _("??\?[...]"); + return _("??\?[...]"); } else if (instr->instr == I_BINARY && instr->instr2 == I_ADD) { return _("??? + ???"); } else if (instr->instr == I_NOP) { return _("??\?(...)"); } else if (instr->instr == I_CALL) { return instructionName(backtraceSkip(instr - 1, instr->data)) + _("(...)"); + } else if (instr->instr == I_CLOSURE) { + return instructionName(backtraceSkip(instr - 1, instr->data)) + _("@(...)"); } else { return _("??\?"); } diff --git a/src/script/script.hpp b/src/script/script.hpp index 446a4b2a..043aa121 100644 --- a/src/script/script.hpp +++ b/src/script/script.hpp @@ -35,11 +35,12 @@ enum InstructionType , I_MAKE_OBJECT = 8 ///< arg = int : make a list/map with n elements, pops 2n values of the stack, n key/value pairs // Functions , I_CALL = 9 ///< arg = int, n*var : call the top item of the stack, with the given number of arguments (set with SET_VAR, but in the activation record of the call) +, I_CLOSURE = 10 ///< arg = int, n*var : construct a call closure object with the given arguments // Simple instructions -, I_UNARY = 10 ///< arg = 1ary instr : pop 1 value, apply a function, push the result -, I_BINARY = 11 ///< arg = 2ary instr : pop 2 values, apply a function, push the result -, I_TERNARY = 12 ///< arg = 3ary instr : pop 3 values, apply a function, push the result -, I_QUATERNARY = 13 ///< arg = 4ary instr : pop 4 values, apply a function, push the result +, I_UNARY = 11 ///< arg = 1ary instr : pop 1 value, apply a function, push the result +, I_BINARY = 12 ///< arg = 2ary instr : pop 2 values, apply a function, push the result +, I_TERNARY = 13 ///< arg = 3ary instr : pop 3 values, apply a function, push the result +, I_QUATERNARY = 14 ///< arg = 4ary instr : pop 4 values, apply a function, push the result }; /// Types of unary instructions (taking one argument from the stack) @@ -55,13 +56,14 @@ enum BinaryInstructionType , I_ITERATOR_R ///< Make an iterator for a range (two integers) , I_MEMBER ///< Member of an object // Arithmatic -, I_ADD ///< add +, I_ADD ///< add , I_SUB ///< subtract , I_MUL ///< multiply -, I_DIV ///< divide +, I_FDIV ///< floating point division +, I_DIV ///< integer division , I_MOD ///< modulus // Logical -, I_AND ///< logical and +, I_AND ///< logical and , I_OR ///< logical or , I_XOR ///< logical xor // Comparison diff --git a/src/script/to_value.hpp b/src/script/to_value.hpp index b3f385e6..b8e20944 100644 --- a/src/script/to_value.hpp +++ b/src/script/to_value.hpp @@ -61,7 +61,7 @@ class ScriptDelayedError : public ScriptValue { virtual operator int() const; virtual operator AColor() const; virtual int itemCount() const; - virtual const void* comparePointer() const; + virtual CompareWhat compareAs(String&, void const*&) const; // these can propagate the error virtual ScriptValueP getMember(const String& name) const; virtual ScriptValueP dependencyMember(const String& name, const Dependency&) const; @@ -82,6 +82,7 @@ inline ScriptValueP delayError(const String& m) { struct ScriptIterator : public ScriptValue { virtual ScriptType type() const;// { return SCRIPT_ITERATOR; } virtual String typeName() const;// { return "iterator"; } + virtual CompareWhat compareAs(String&, void const*&) const; // { return COMPARE_NO; } /// Return the next item for this iterator, or ScriptValueP() if there is no such item virtual ScriptValueP next() = 0; @@ -129,7 +130,10 @@ class ScriptCollection : public ScriptValue { } virtual int itemCount() const { return (int)value->size(); } /// Collections can be compared by comparing pointers - virtual const void* comparePointer() const { return value; } + virtual CompareWhat compareAs(String&, void const*& compare_ptr) const { + compare_ptr = value; + return COMPARE_AS_POINTER; + } private: /// Store a pointer to a collection, collections are only ever used for structures owned outside the script const Collection* value; @@ -168,12 +172,15 @@ class ScriptMap : public ScriptValue { return get_member(*value, name); } virtual int itemCount() const { return (int)value->size(); } - /// Collections can be compared by comparing pointers - virtual const void* comparePointer() const { return value; } virtual ScriptValueP dependencyMember(const String& name, const Dependency& dep) const { mark_dependency_member(*value, name, dep); return getMember(name); } + /// Collections can be compared by comparing pointers + virtual CompareWhat compareAs(String&, void const*& compare_ptr) const { + compare_ptr = value; + return COMPARE_AS_POINTER; + } private: /// Store a pointer to a collection, collections are only ever used for structures owned outside the script const Collection* value; @@ -190,7 +197,10 @@ class ScriptCustomCollection : public ScriptValue { virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const; virtual int itemCount() const { return (int)value.size(); } /// Collections can be compared by comparing pointers - virtual const void* comparePointer() const { return &value; } + virtual CompareWhat compareAs(String&, void const*& compare_ptr) const { + compare_ptr = this; + return COMPARE_AS_POINTER; + } /// The collection as a list (contains all values) vector value; @@ -198,6 +208,28 @@ class ScriptCustomCollection : public ScriptValue { map key_value; }; +// ----------------------------------------------------------------------------- : Collections : concatenation + +/// Script value containing the concatenation of two collections +class ScriptConcatCollection : public ScriptValue { + public: + inline ScriptConcatCollection(ScriptValueP a, ScriptValueP b) : a(a), b(b) {} + virtual ScriptType type() const { return SCRIPT_COLLECTION; } + virtual String typeName() const { return _TYPE_("collection"); } + virtual ScriptValueP getMember(const String& name) const; + virtual ScriptValueP makeIterator(const ScriptValueP& thisP) const; + virtual int itemCount() const { return a->itemCount() + b->itemCount(); } + /// Collections can be compared by comparing pointers + virtual CompareWhat compareAs(String&, void const*& compare_ptr) const { + compare_ptr = this; + return COMPARE_AS_POINTER; + } + + private: + ScriptValueP a,b; + friend class ScriptConcatCollectionIterator; +}; + // ----------------------------------------------------------------------------- : Objects /// Script value containing an object (pointer) @@ -238,7 +270,15 @@ class ScriptObject : public ScriptValue { return i >= 0 ? i : ScriptValue::itemCount(); } /// Objects can be compared by comparing pointers - virtual const void* comparePointer() const { return &*value; } + virtual CompareWhat compareAs(String& compare_str, void const*& compare_ptr) const { + ScriptValueP d = getDefault(); + if (d) { + return d->compareAs(compare_str, compare_ptr); + } else { + compare_ptr = &*value; + return COMPARE_AS_POINTER; + } + } /// Get access to the value inline T getValue() const { return value; } private: diff --git a/src/script/value.cpp b/src/script/value.cpp index 319226d1..fb75f12f 100644 --- a/src/script/value.cpp +++ b/src/script/value.cpp @@ -24,11 +24,38 @@ ScriptValueP ScriptValue::getMember(const String& name) const { return delay 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"))); } -const void* ScriptValue::comparePointer() const { return nullptr; } +CompareWhat ScriptValue::compareAs(String& compare_str, void const*& compare_ptr) const { + compare_str = (String)(*this); + return COMPARE_AS_STRING; +} ScriptValueP ScriptValue::dependencyMember(const String& name, const Dependency&) const { return dependency_dummy; } 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(); + if (at == bt && at == SCRIPT_INT) { + return (int)a == (int)b; + } else if ((at == SCRIPT_INT || at == SCRIPT_DOUBLE) && + (bt == SCRIPT_INT || bt == SCRIPT_DOUBLE)) { + return (double)a == (double)b; + } else { + String as, bs; + const void* ap, *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; + } else if (aw == COMPARE_AS_POINTER || bw == COMPARE_AS_POINTER) { + return ap == bp; + } else { + return false; + } + } +} // ----------------------------------------------------------------------------- : Errors @@ -40,7 +67,7 @@ ScriptDelayedError::operator double() const { throw error; } ScriptDelayedError::operator int() const { throw error; } ScriptDelayedError::operator AColor() const { throw error; } int ScriptDelayedError::itemCount() const { throw error; } -const void* ScriptDelayedError::comparePointer() const { throw error; } +CompareWhat ScriptDelayedError::compareAs(String&, void const*&) const { throw error; } ScriptValueP ScriptDelayedError::getMember(const String&) const { return new_intrusive1(error); } ScriptValueP ScriptDelayedError::dependencyMember(const String&, const Dependency&) const { return new_intrusive1(error); } ScriptValueP ScriptDelayedError::eval(Context&) const { return new_intrusive1(error); } @@ -52,6 +79,7 @@ ScriptValueP ScriptDelayedError::makeIterator(const ScriptValueP& thisP) const ScriptType ScriptIterator::type() const { return SCRIPT_ITERATOR; } String ScriptIterator::typeName() const { return _("iterator"); } +CompareWhat ScriptIterator::compareAs(String&, void const*&) const { return COMPARE_NO; } // Iterator over a range of integers class ScriptRangeIterator : public ScriptIterator { @@ -295,3 +323,37 @@ ScriptValueP ScriptCustomCollection::makeIterator(const ScriptValueP& thisP) con return new_intrusive2(&value, thisP); } +// ----------------------------------------------------------------------------- : Concat collection + +// Iterator over a concatenated collection +class ScriptConcatCollectionIterator : public ScriptIterator { + public: + ScriptConcatCollectionIterator(const ScriptValueP& itA, const ScriptValueP& itB) + : itA(itA), itB(itB) {} + virtual ScriptValueP next() { + if (itA) { + ScriptValueP v = itA->next(); + if (v) return v; + else itA = ScriptValueP(); + } + return itB->next(); + } + private: + ScriptValueP itA, itB; +}; + +ScriptValueP ScriptConcatCollection::getMember(const String& name) const { + ScriptValueP member = a->getMember(name); + if (member->type() != SCRIPT_ERROR) return member; + long index; + int itemsInA = a->itemCount(); + if (name.ToLong(&index) && index - itemsInA >= 0 && index - itemsInA < b->itemCount()) { + // adjust integer index + return b->getMember(String() << (index - itemsInA)); + } else { + return b->getMember(name); + } +} +ScriptValueP ScriptConcatCollection::makeIterator(const ScriptValueP& thisP) const { + return new_intrusive2(a->makeIterator(a), b->makeIterator(b)); +} diff --git a/src/script/value.hpp b/src/script/value.hpp index 830a3567..17c63cc4 100644 --- a/src/script/value.hpp +++ b/src/script/value.hpp @@ -33,6 +33,12 @@ enum ScriptType , SCRIPT_ERROR }; +enum CompareWhat +{ COMPARE_NO +, COMPARE_AS_STRING +, COMPARE_AS_POINTER +}; + /// A value that can be handled by the scripting engine. /// Actual values are derived types class ScriptValue : public IntrusivePtrBaseWithDelete { @@ -43,9 +49,9 @@ class ScriptValue : public IntrusivePtrBaseWithDelete { virtual ScriptType type() const = 0; /// Name of the type of value virtual String typeName() const = 0; - /// A pointer that uniquely identifies the value, used for comparing. - /** If implementation is not possible, should return nullptr. */ - virtual const void* comparePointer() const; + /// How to compare this object? + /** Returns 1 if the pointer should be used, 0 otherwise */ + virtual CompareWhat compareAs(String& compare_str, void const*& compare_ptr) const; /// Convert this value to a string virtual operator String() const; @@ -89,5 +95,8 @@ extern ScriptValueP script_true; ///< The preallocated true value 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); + // ----------------------------------------------------------------------------- : EOF #endif diff --git a/tools/website/drupal/mse-drupal-modules/highlight.inc b/tools/website/drupal/mse-drupal-modules/highlight.inc index c558b8e7..354f38a0 100644 --- a/tools/website/drupal/mse-drupal-modules/highlight.inc +++ b/tools/website/drupal/mse-drupal-modules/highlight.inc @@ -131,7 +131,7 @@ function highlight_script($code) { while(strlen($code)) { if (preg_match("@^<[^>]+>@",$code, $matches)) { $ret .= $matches[0]; // plain tag - } else if (preg_match("@^(if|then|else|for( each)?|in(?= )|do|mod|and|or|xor|not|rgb|rgba|from|to)\b(?!:)@",$code, $matches)) { + } else if (preg_match("@^(if|then|else|for( each)?|in(?= )|do|div|mod|and|or|xor|not|rgb|rgba|from|to)\b(?!:)@",$code, $matches)) { $ret .= "" . $matches[0] . ""; } else if (preg_match("@^(include file:)(.*)@",$code, $matches)) { $ret .= "" . $matches[1] . "" . $matches[2];