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;
	}
}
Exemple #3
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;
}
Exemple #5
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);
		}
	}
}
Exemple #7
0
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);
}
Exemple #8
0
unsigned short js_touint16(js_State *J, int idx)
{
	return jsV_numbertouint16(jsV_tonumber(J, stackidx(J, idx)));
}
Exemple #9
0
int js_toint32(js_State *J, int idx)
{
	return jsV_numbertoint32(jsV_tonumber(J, stackidx(J, idx)));
}
Exemple #10
0
double js_tointeger(js_State *J, int idx)
{
	return jsV_numbertointeger(jsV_tonumber(J, stackidx(J, idx)));
}
Exemple #11
0
double jsV_tointeger(js_State *J, js_Value *v)
{
	return jsV_numbertointeger(jsV_tonumber(J, v));
}