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); } }
/* ToString() on a value */ const char *jsV_tostring(js_State *J, js_Value *v) { char buf[32]; const char *p; switch (v->type) { default: case JS_TSHRSTR: return v->u.shrstr; case JS_TUNDEFINED: return "undefined"; case JS_TNULL: return "null"; case JS_TBOOLEAN: return v->u.boolean ? "true" : "false"; case JS_TLITSTR: return v->u.litstr; case JS_TMEMSTR: return v->u.memstr->p; case JS_TNUMBER: p = jsV_numbertostring(J, buf, v->u.number); if (p == buf) { unsigned int n = strlen(p); if (n <= offsetof(js_Value, type)) { char *s = v->u.shrstr; while (n--) *s++ = *p++; *s = 0; v->type = JS_TSHRSTR; return v->u.shrstr; } else { v->type = JS_TMEMSTR; v->u.memstr = jsV_newmemstring(J, p, n); return v->u.memstr->p; } } return p; case JS_TOBJECT: jsV_toprimitive(J, v, JS_HSTRING); return jsV_tostring(J, v); } }
/* ToString() on a value */ const char *jsV_tostring(js_State *J, const js_Value *v) { switch (v->type) { default: case JS_TUNDEFINED: return "undefined"; case JS_TNULL: return "null"; case JS_TBOOLEAN: return v->u.boolean ? "true" : "false"; case JS_TNUMBER: return jsV_numbertostring(J, v->u.number); case JS_TSTRING: return v->u.string; case JS_TOBJECT: { js_Value vv = jsV_toprimitive(J, v, JS_HSTRING); return jsV_tostring(J, &vv); } } }
const char *js_tostring(js_State *J, int idx) { return jsV_tostring(J, stackidx(J, idx)); }