Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/source/reference/embedding/the_stack.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,7 @@ The following functions convert a squirrel value in the stack to a C value::
The function sq_cmp compares 2 values from the stack and returns their relation (like strcmp() in ANSI C).::

SQInteger sq_cmp(HSQUIRRELVM v);

The function sq_cmpex works like sq_cmp, but reports error conditions and sets alwaysfalse to SQTrue if the comparison would always return false, as is the case with floating-point NAN.::

SQRESULT sq_cmpex(HSQUIRRELVM v,SQInteger *res,SQBool *alwaysfalse);
2 changes: 2 additions & 0 deletions doc/source/reference/language/metamethods.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ returns an integer as follow:
| < 0 | if ``this`` < ``other`` |
+-----------+----------------------------+

can also return a floating-point NAN value, which results in ``< > <= >=`` returning false and ``<=>`` returning NAN.

^^^^^^^^^^^^^^^^^^^^^^^^
_call
^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
1 change: 1 addition & 0 deletions include/squirrel.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ SQUIRREL_API SQInteger sq_gettop(HSQUIRRELVM v);
SQUIRREL_API void sq_settop(HSQUIRRELVM v,SQInteger newtop);
SQUIRREL_API SQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize);
SQUIRREL_API SQInteger sq_cmp(HSQUIRRELVM v);
SQUIRREL_API SQRESULT sq_cmpex(HSQUIRRELVM v, SQInteger *res, SQBool *alwaysfalse);
SQUIRREL_API void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx);

/*object creation handling*/
Expand Down
14 changes: 12 additions & 2 deletions squirrel/sqapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -859,10 +859,20 @@ void sq_remove(HSQUIRRELVM v, SQInteger idx)
SQInteger sq_cmp(HSQUIRRELVM v)
{
SQInteger res;
v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res);
bool alwaysfalse;
v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res,alwaysfalse);
return res;
}

SQRESULT sq_cmpex(HSQUIRRELVM v, SQInteger *res, SQBool *alwaysfalse)
{
if (!res || !alwaysfalse) return SQ_ERROR;
bool af;
SQRESULT result = v->ObjCmp(stack_get(v, -1), stack_get(v, -2), *res, af) ? SQ_OK : SQ_ERROR;
*alwaysfalse = af ? SQTrue : SQFalse;
return result;
}

SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)
{
sq_aux_paramscheck(v, 3);
Expand Down Expand Up @@ -1197,7 +1207,7 @@ SQRESULT sq_tailcall(HSQUIRRELVM v, SQInteger nparams)
{
return sq_throwerror(v, _SC("generators cannot be tail called"));
}

SQInteger stackbase = (v->_top - nparams) - v->_stackbase;
if (!v->TailCall(clo, stackbase, nparams)) {
return SQ_ERROR;
Expand Down
3 changes: 2 additions & 1 deletion squirrel/sqbaselib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,8 @@ static SQInteger array_find(HSQUIRRELVM v)
static bool _sort_compare(HSQUIRRELVM v, SQArray *arr, SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)
{
if(func < 0) {
if(!v->ObjCmp(a,b,ret)) return false;
bool alwaysfalse;
if(!v->ObjCmp(a,b,ret,alwaysfalse)) return false;
}
else {
SQInteger top = sq_gettop(v);
Expand Down
32 changes: 23 additions & 9 deletions squirrel/sqvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,14 @@ bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o)
}

#define _RET_SUCCEED(exp) { result = (exp); return true; }
bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result, bool &alwaysfalse)
{
SQObjectType t1 = sq_type(o1), t2 = sq_type(o2);
alwaysfalse = false;
if((t1 == OT_FLOAT && isnan(_float(o1))) || (t2 == OT_FLOAT && isnan(_float(o2)))) {
alwaysfalse = true;
_RET_SUCCEED(0);
}
if(t1 == t2) {
if(_rawval(o1) == _rawval(o2))_RET_SUCCEED(0);
SQObjectPtr res;
Expand All @@ -225,8 +230,12 @@ bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
if(_delegable(o1)->GetMetaMethod(this, MT_CMP, closure)) {
Push(o1);Push(o2);
if(CallMetaMethod(closure,MT_CMP,2,res)) {
if(sq_type(res) == OT_FLOAT && isnan(_float(res))) {
alwaysfalse = true;
_RET_SUCCEED(0);
}
if(sq_type(res) != OT_INTEGER) {
Raise_Error(_SC("_cmp must return an integer"));
Raise_Error(_SC("_cmp must return an integer or NAN"));
return false;
}
_RET_SUCCEED(_integer(res))
Expand All @@ -236,7 +245,12 @@ bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
}
//continues through (no break needed)
default:
#ifdef NO_POINTER_CMP
Raise_CompareError(o1,o2);
return false;
#else
_RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 );
#endif
}
assert(0);
//if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; }
Expand All @@ -259,7 +273,6 @@ bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
else if(t1==OT_NULL) {_RET_SUCCEED(-1);}
else if(t2==OT_NULL) {_RET_SUCCEED(1);}
else { Raise_CompareError(o1,o2); return false; }

}
assert(0);
_RET_SUCCEED(0); //cannot happen
Expand All @@ -268,13 +281,14 @@ bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res)
{
SQInteger r;
if(ObjCmp(o1,o2,r)) {
bool alwaysfalse;
if(ObjCmp(o1,o2,r,alwaysfalse)) {
switch(op) {
case CMP_G: res = (r > 0); return true;
case CMP_GE: res = (r >= 0); return true;
case CMP_L: res = (r < 0); return true;
case CMP_LE: res = (r <= 0); return true;
case CMP_3W: res = r; return true;
case CMP_G: res = (!alwaysfalse && r > 0); return true;
case CMP_GE: res = (!alwaysfalse && r >= 0); return true;
case CMP_L: res = (!alwaysfalse && r < 0); return true;
case CMP_LE: res = (!alwaysfalse && r <= 0); return true;
case CMP_3W: if (alwaysfalse) res = NAN; else res = r; return true;
}
assert(0);
}
Expand Down
2 changes: 1 addition & 1 deletion squirrel/sqvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ typedef sqvector<CallInfo> CallInfoVec;
bool NewSlotA(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,const SQObjectPtr &attrs,bool bstatic,bool raw);
bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res);
bool Clone(const SQObjectPtr &self, SQObjectPtr &target);
bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res);
bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res,bool &alwaysfalse);
bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest);
static bool IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res);
bool ToString(const SQObjectPtr &o,SQObjectPtr &res);
Expand Down