void js_concat(js_State *J) { js_Value va = js_toprimitive(J, -2, JS_HNONE); js_Value vb = js_toprimitive(J, -1, JS_HNONE); if (va.type == JS_TSTRING || vb.type == JS_TSTRING) { const char *sa = jsV_tostring(J, &va); const char *sb = jsV_tostring(J, &vb); char *sab = js_malloc(J, strlen(sa) + strlen(sb) + 1); strcpy(sab, sa); strcat(sab, sb); if (js_try(J)) { js_free(J, sab); js_throw(J); } js_pop(J, 2); js_pushstring(J, sab); js_endtry(J); js_free(J, sab); } else { double x = jsV_tonumber(J, &va); double y = jsV_tonumber(J, &vb); js_pop(J, 2); js_pushnumber(J, x + y); } }
int js_compare(js_State *J, int *okay) { js_Value va = js_toprimitive(J, -2, JS_HNUMBER); js_Value vb = js_toprimitive(J, -1, JS_HNUMBER); *okay = 1; if (va.type == JS_TSTRING && vb.type == JS_TSTRING) { return strcmp(va.u.string, vb.u.string); } else { double x = jsV_tonumber(J, &va); double y = jsV_tonumber(J, &vb); if (isnan(x) || isnan(y)) *okay = 0; return x < y ? -1 : x > y ? 1 : 0; } }
int js_equal(js_State *J) { js_Value *x = js_tovalue(J, -2); js_Value *y = js_tovalue(J, -1); retry: if (JSV_ISSTRING(x) && JSV_ISSTRING(y)) return !strcmp(JSV_TOSTRING(x), JSV_TOSTRING(y)); if (x->type == y->type) { if (x->type == JS_TUNDEFINED) return 1; if (x->type == JS_TNULL) return 1; if (x->type == JS_TNUMBER) return x->u.number == y->u.number; if (x->type == JS_TBOOLEAN) return x->u.boolean == y->u.boolean; if (x->type == JS_TOBJECT) return x->u.object == y->u.object; return 0; } if (x->type == JS_TNULL && y->type == JS_TUNDEFINED) return 1; if (x->type == JS_TUNDEFINED && y->type == JS_TNULL) return 1; if (x->type == JS_TNUMBER && JSV_ISSTRING(y)) return x->u.number == jsV_tonumber(J, y); if (JSV_ISSTRING(x) && y->type == JS_TNUMBER) return jsV_tonumber(J, x) == y->u.number; if (x->type == JS_TBOOLEAN) { x->type = JS_TNUMBER; x->u.number = x->u.boolean; goto retry; } if (y->type == JS_TBOOLEAN) { y->type = JS_TNUMBER; y->u.number = y->u.boolean; goto retry; } if ((JSV_ISSTRING(x) || x->type == JS_TNUMBER) && y->type == JS_TOBJECT) { jsV_toprimitive(J, y, JS_HNONE); goto retry; } if (x->type == JS_TOBJECT && (JSV_ISSTRING(y) || y->type == JS_TNUMBER)) { jsV_toprimitive(J, x, JS_HNONE); goto retry; } return 0; }
int js_equal(js_State *J) { js_Value x = js_tovalue(J, -2); js_Value y = js_tovalue(J, -1); retry: if (x.type == y.type) { if (x.type == JS_TUNDEFINED) return 1; if (x.type == JS_TNULL) return 1; if (x.type == JS_TNUMBER) return x.u.number == y.u.number; if (x.type == JS_TBOOLEAN) return x.u.boolean == y.u.boolean; if (x.type == JS_TSTRING) return !strcmp(x.u.string, y.u.string); if (x.type == JS_TOBJECT) return x.u.object == y.u.object; return 0; } if (x.type == JS_TNULL && y.type == JS_TUNDEFINED) return 1; if (x.type == JS_TUNDEFINED && y.type == JS_TNULL) return 1; if (x.type == JS_TNUMBER && y.type == JS_TSTRING) return x.u.number == jsV_tonumber(J, &y); if (x.type == JS_TSTRING && y.type == JS_TNUMBER) return jsV_tonumber(J, &x) == y.u.number; if (x.type == JS_TBOOLEAN) { x.type = JS_TNUMBER; x.u.number = x.u.boolean; goto retry; } if (y.type == JS_TBOOLEAN) { y.type = JS_TNUMBER; y.u.number = y.u.boolean; goto retry; } if ((x.type == JS_TSTRING || x.type == JS_TNUMBER) && y.type == JS_TOBJECT) { y = jsV_toprimitive(J, &y, JS_HNONE); goto retry; } if (x.type == JS_TOBJECT && (y.type == JS_TSTRING || y.type == JS_TNUMBER)) { x = jsV_toprimitive(J, &x, JS_HNONE); goto retry; } return 0; }
/* ToNumber() on a value */ double jsV_tonumber(js_State *J, js_Value *v) { switch (v->type) { default: case JS_TSHRSTR: return jsV_stringtonumber(J, v->u.shrstr); case JS_TUNDEFINED: return NAN; case JS_TNULL: return 0; case JS_TBOOLEAN: return v->u.boolean; case JS_TNUMBER: return v->u.number; case JS_TLITSTR: return jsV_stringtonumber(J, v->u.litstr); case JS_TMEMSTR: return jsV_stringtonumber(J, v->u.memstr->p); case JS_TOBJECT: jsV_toprimitive(J, v, JS_HNUMBER); return jsV_tonumber(J, v); } }
/* ToNumber() on a value */ double jsV_tonumber(js_State *J, const js_Value *v) { switch (v->type) { default: case JS_TUNDEFINED: return NAN; case JS_TNULL: return 0; case JS_TBOOLEAN: return v->u.boolean; case JS_TNUMBER: return v->u.number; case JS_TSTRING: return jsV_stringtonumber(J, v->u.string); case JS_TOBJECT: { js_Value vv = jsV_toprimitive(J, v, JS_HNUMBER); return jsV_tonumber(J, &vv); } } }
static void jsR_setproperty(js_State *J, js_Object *obj, const char *name, js_Value *value) { js_Property *ref; unsigned int k; int own; if (obj->type == JS_CARRAY) { if (!strcmp(name, "length")) { double rawlen = jsV_tonumber(J, value); unsigned int newlen = jsV_numbertouint32(rawlen); if (newlen != rawlen) js_rangeerror(J, "array length"); jsV_resizearray(J, obj, newlen); return; } if (js_isarrayindex(J, name, &k)) if (k >= obj->u.a.length) obj->u.a.length = k + 1; } if (obj->type == JS_CSTRING) { if (!strcmp(name, "length")) goto readonly; if (js_isarrayindex(J, name, &k)) if (js_runeat(J, obj->u.s.string, k)) goto readonly; } if (obj->type == JS_CREGEXP) { if (!strcmp(name, "source")) goto readonly; if (!strcmp(name, "global")) goto readonly; if (!strcmp(name, "ignoreCase")) goto readonly; if (!strcmp(name, "multiline")) goto readonly; if (!strcmp(name, "lastIndex")) { obj->u.r.last = jsV_tointeger(J, value); return; } } /* First try to find a setter in prototype chain */ ref = jsV_getpropertyx(J, obj, name, &own); if (ref && ref->setter) { js_pushobject(J, ref->setter); js_pushobject(J, obj); js_pushvalue(J, *value); js_call(J, 1); js_pop(J, 1); return; } /* Property not found on this object, so create one */ if (!ref || !own) ref = jsV_setproperty(J, obj, name); if (ref) { if (!(ref->atts & JS_READONLY)) ref->value = *value; else goto readonly; } return; readonly: if (J->strict) js_typeerror(J, "'%s' is read-only", name); }
unsigned short js_touint16(js_State *J, int idx) { return jsV_numbertouint16(jsV_tonumber(J, stackidx(J, idx))); }
int js_toint32(js_State *J, int idx) { return jsV_numbertoint32(jsV_tonumber(J, stackidx(J, idx))); }
double js_tointeger(js_State *J, int idx) { return jsV_numbertointeger(jsV_tonumber(J, stackidx(J, idx))); }
double jsV_tointeger(js_State *J, js_Value *v) { return jsV_numbertointeger(jsV_tonumber(J, v)); }