ref: 2a027a1b21ace51301989dd4009f6a56d183df92
parent: b595422da9eb0260f2457cbf30e3a5f69de76029
author: Tor Andersson <[email protected]>
date: Thu Jan 16 22:21:20 EST 2014
String concatenation.
--- a/jsobject.h
+++ b/jsobject.h
@@ -36,6 +36,12 @@
JS_PCONFIGURABLE = 4,
};
+enum {
+ JS_HNONE,
+ JS_HNUMBER,
+ JS_HSTRING,
+};
+
struct js_Value
{
js_Type type;
@@ -76,6 +82,7 @@
double jsR_tonumber(js_State *J, const js_Value *v);
const char *jsR_tostring(js_State *J, const js_Value *v);
js_Object *jsR_toobject(js_State *J, const js_Value *v);
+js_Value jsR_toprimitive(js_State *J, const js_Value *v, int preferred);
/* jsproperty.c */
js_Object *jsR_newobject(js_State *J, js_Class type);
--- a/jsrun.c
+++ b/jsrun.c
@@ -164,6 +164,12 @@
return jsR_toobject(J, &stack[idx]);
}
+js_Value js_toprimitive(js_State *J, int idx, int hint)
+{
+ idx = stackidx(J, idx);
+ return jsR_toprimitive(J, &stack[idx], hint);
+}
+
/* Stack manipulation */
void js_pop(js_State *J, int n)
@@ -528,17 +534,31 @@
case OP_LOGNOT:
b = js_toboolean(J, -1);
js_pop(J, 1);
- js_pushnumber(J, !b);
+ js_pushboolean(J, !b);
break;
/* Binary expressions */
case OP_ADD:
- // TODO: check string concatenation
- x = js_tonumber(J, -2);
- y = js_tonumber(J, -1);
- js_pop(J, 2);
- js_pushnumber(J, x + y);
+ {
+ 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 = jsR_tostring(J, &va);
+ const char *sb = jsR_tostring(J, &vb);
+ char *sab = malloc(strlen(sa) + strlen(sb) + 1);
+ strcpy(sab, sa);
+ strcat(sab, sb);
+ js_pop(J, 2);
+ js_pushstring(J, sab);
+ free(sab);
+ } else {
+ x = jsR_tonumber(J, &va);
+ y = jsR_tonumber(J, &vb);
+ js_pop(J, 2);
+ js_pushnumber(J, x + y);
+ }
+ }
break;
case OP_SUB:
--- a/jsvalue.c
+++ b/jsvalue.c
@@ -1,15 +1,14 @@
#include "js.h"
#include "jsobject.h"
-enum {
- JS_HNONE,
- JS_HNUMBER,
- JS_HSTRING,
-};
-
-static js_Value jsR_toprimitive(js_State *J, const js_Value *v, int preferred)
+js_Value jsR_toprimitive(js_State *J, const js_Value *v, int preferred)
{
- js_Object *obj = v->u.object;
+ js_Object *obj;
+
+ if (v->type != JS_COBJECT)
+ return *v;
+
+ obj = v->u.object;
if (preferred == JS_HNONE)
preferred = obj->type == JS_CDATE ? JS_HSTRING : JS_HNUMBER;