Add virtual string array index properties for characters.

This commit is contained in:
Tor Andersson
2014-02-07 16:40:22 +01:00
parent d59d0e2721
commit b219aef882
7 changed files with 108 additions and 39 deletions
+2 -2
View File
@@ -802,8 +802,8 @@ void js_dumpvalue(js_State *J, js_Value v)
case JS_CCFUNCTION: printf("[CFunction %p]", v.u.object->u.c.function); break;
case JS_CBOOLEAN: printf("[Boolean %d]", v.u.object->u.boolean); break;
case JS_CNUMBER: printf("[Number %g]", v.u.object->u.number); break;
case JS_CSTRING: printf("[String'%s']", v.u.object->u.string); break;
case JS_CERROR: printf("[Error %s]", v.u.object->u.string); break;
case JS_CSTRING: printf("[String'%s']", v.u.object->u.s.string); break;
case JS_CERROR: printf("[Error %s]", v.u.object->u.s.string); break;
case JS_CITERATOR: printf("[Iterator %p]", v.u.object); break;
case JS_CUSERDATA:
printf("[Userdata %s %p]", v.u.object->u.user.tag, v.u.object->u.user.data);
+3
View File
@@ -39,6 +39,9 @@ void js_newfunction(js_State *J, js_Function *function, js_Environment *scope);
void js_newscript(js_State *J, js_Function *function);
js_Regexp *js_toregexp(js_State *J, int idx);
int js_isarrayindex(js_State *J, const char *str, unsigned int *idx);
int js_runeat(js_State *J, const char *s, int i);
void js_pushcharat(js_State *J, const char *s, int pos);
void js_dup(js_State *J);
void js_rot2(js_State *J);
+33 -9
View File
@@ -218,10 +218,14 @@ void jsV_delproperty(js_State *J, js_Object *obj, const char *name)
static int itshadow(js_State *J, js_Object *top, js_Object *bot, const char *name)
{
unsigned int k;
while (top != bot) {
js_Property *prop = lookup(top->properties, name);
if (prop && !(prop->atts & JS_DONTENUM))
return 1;
if (top->type == JS_CSTRING)
if (js_isarrayindex(J, name, &k) && k < top->u.s.length)
return 1;
top = top->prototype;
}
return 0;
@@ -231,22 +235,38 @@ static void itwalk(js_State *J, js_Object *io, js_Object *top, int own)
{
js_Object *obj = top;
js_Iterator *tail = NULL;
char buf[32];
unsigned int k;
#define ITADD(x) \
js_Iterator *node = malloc(sizeof *node); \
node->name = x; \
node->next = NULL; \
if (!tail) { \
io->u.iter.head = tail = node; \
} else { \
tail->next = node; \
tail = node; \
}
while (obj) {
js_Property *prop = obj->head;
while (prop) {
if (!(prop->atts & JS_DONTENUM) && !itshadow(J, top, obj, prop->name)) {
js_Iterator *node = malloc(sizeof *node);
node->name = prop->name;
node->next = NULL;
if (!tail) {
io->u.iter.head = tail = node;
} else {
tail->next = node;
tail = node;
}
ITADD(prop->name);
}
prop = prop->next;
}
if (obj->type == JS_CSTRING) {
for (k = 0; k < obj->u.s.length; ++k) {
sprintf(buf, "%u", k);
if (!itshadow(J, top, obj, buf)) {
ITADD(js_intern(J, buf));
}
}
}
if (own)
break;
obj = obj->prototype;
@@ -264,6 +284,7 @@ js_Object *jsV_newiterator(js_State *J, js_Object *obj, int own)
const char *jsV_nextiterator(js_State *J, js_Object *io)
{
unsigned int k;
if (io->type != JS_CITERATOR)
js_typeerror(J, "not an iterator");
while (io->u.iter.head) {
@@ -273,6 +294,9 @@ const char *jsV_nextiterator(js_State *J, js_Object *io)
io->u.iter.head = next;
if (jsV_getproperty(J, io->u.iter.target, name))
return name;
if (io->u.iter.target->type == JS_CSTRING)
if (js_isarrayindex(J, name, &k) && k < io->u.iter.target->u.s.length)
return name;
}
return NULL;
}
+45 -13
View File
@@ -357,9 +357,18 @@ void js_rot(js_State *J, int n)
/* Property access that takes care of attributes and getters/setters */
int js_isarrayindex(js_State *J, const char *str, unsigned int *idx)
{
char buf[32];
*idx = jsV_numbertouint32(jsV_stringtonumber(J, str));
sprintf(buf, "%u", *idx);
return !strcmp(buf, str);
}
static int jsR_hasproperty(js_State *J, js_Object *obj, const char *name)
{
js_Property *ref;
unsigned int k;
if (obj->type == JS_CARRAY) {
if (!strcmp(name, "length")) {
@@ -368,7 +377,16 @@ static int jsR_hasproperty(js_State *J, js_Object *obj, const char *name)
}
}
// TODO: String array indexing
if (obj->type == JS_CSTRING) {
if (!strcmp(name, "length")) {
js_pushnumber(J, obj->u.s.length);
return 1;
}
if (js_isarrayindex(J, name, &k)) {
js_pushcharat(J, obj->u.s.string, k);
return 1;
}
}
if (obj->type == JS_CREGEXP) {
if (!strcmp(name, "source")) {
@@ -417,12 +435,10 @@ static void jsR_getproperty(js_State *J, js_Object *obj, const char *name)
static void jsR_setproperty(js_State *J, js_Object *obj, const char *name, const js_Value *value)
{
js_Property *ref;
unsigned int k;
int own;
if (obj->type == JS_CARRAY) {
unsigned int k;
char buf[32];
if (!strcmp(name, "length")) {
double rawlen = jsV_tonumber(J, value);
unsigned int newlen = jsV_numbertouint32(rawlen);
@@ -431,16 +447,18 @@ static void jsR_setproperty(js_State *J, js_Object *obj, const char *name, const
jsV_resizearray(J, obj, newlen);
return;
}
k = jsV_numbertouint32(jsV_stringtonumber(J, name));
if (k >= obj->u.a.length) {
sprintf(buf, "%u", k);
if (!strcmp(buf, name))
if (js_isarrayindex(J, name, &k))
if (k >= obj->u.a.length)
obj->u.a.length = k + 1;
}
}
// TODO: String array indexing
if (obj->type == JS_CSTRING) {
if (!strcmp(name, "length"))
return;
if (js_isarrayindex(J, name, &k))
if (js_runeat(J, obj->u.s.string, k))
return;
}
if (obj->type == JS_CREGEXP) {
if (!strcmp(name, "source")) return;
@@ -476,12 +494,19 @@ static void jsR_defproperty(js_State *J, js_Object *obj, const char *name,
int atts, const js_Value *value, js_Object *getter, js_Object *setter)
{
js_Property *ref;
unsigned int k;
if (obj->type == JS_CARRAY)
if (!strcmp(name, "length"))
return;
// TODO: String array indexing
if (obj->type == JS_CSTRING) {
if (!strcmp(name, "length"))
return;
if (js_isarrayindex(J, name, &k))
if (js_runeat(J, obj->u.s.string, k))
return;
}
if (obj->type == JS_CREGEXP) {
if (!strcmp(name, "source")) return;
@@ -506,11 +531,18 @@ static void jsR_defproperty(js_State *J, js_Object *obj, const char *name,
static int jsR_delproperty(js_State *J, js_Object *obj, const char *name)
{
js_Property *ref;
unsigned int k;
if (obj->type == JS_CARRAY)
if (!strcmp(name, "length")) return 0;
// TODO: String array indexing
if (obj->type == JS_CSTRING) {
if (!strcmp(name, "length"))
return 0;
if (js_isarrayindex(J, name, &k))
if (js_runeat(J, obj->u.s.string, k))
return 0;
}
if (obj->type == JS_CREGEXP) {
if (!strcmp(name, "source")) return 0;
+19 -6
View File
@@ -23,7 +23,7 @@ static int Sp_toString(js_State *J, int argc)
{
js_Object *self = js_toobject(J, 0);
if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
js_pushliteral(J, self->u.string);
js_pushliteral(J, self->u.s.string);
return 1;
}
@@ -31,11 +31,11 @@ static int Sp_valueOf(js_State *J, int argc)
{
js_Object *self = js_toobject(J, 0);
if (self->type != JS_CSTRING) js_typeerror(J, "not a string");
js_pushliteral(J, self->u.string);
js_pushliteral(J, self->u.s.string);
return 1;
}
static inline Rune runeAt(const char *s, int i)
int js_runeat(js_State *J, const char *s, int i)
{
Rune rune = 0;
while (i-- >= 0) {
@@ -65,12 +65,24 @@ static inline const char *utfidx(const char *s, int i)
return s;
}
void js_pushcharat(js_State *J, const char *s, int pos)
{
char buf[UTFmax + 1];
Rune rune = js_runeat(J, s, pos);
if (rune > 0) {
buf[runetochar(buf, &rune)] = 0;
js_pushstring(J, buf);
} else {
js_pushundefined(J);
}
}
static int Sp_charAt(js_State *J, int argc)
{
char buf[UTFmax + 1];
const char *s = js_tostring(J, 0);
int pos = js_tointeger(J, 1);
Rune rune = runeAt(s, pos);
Rune rune = js_runeat(J, s, pos);
if (rune > 0) {
buf[runetochar(buf, &rune)] = 0;
js_pushstring(J, buf);
@@ -84,7 +96,7 @@ static int Sp_charCodeAt(js_State *J, int argc)
{
const char *s = js_tostring(J, 0);
int pos = js_tointeger(J, 1);
Rune rune = runeAt(s, pos);
Rune rune = js_runeat(J, s, pos);
if (rune > 0)
js_pushnumber(J, rune);
else
@@ -652,7 +664,8 @@ static int Sp_split(js_State *J, int argc)
void jsB_initstring(js_State *J)
{
J->String_prototype->u.string = "";
J->String_prototype->u.s.string = "";
J->String_prototype->u.s.length = 0;
js_pushobject(J, J->String_prototype);
{
+2 -8
View File
@@ -191,14 +191,8 @@ static js_Object *jsV_newnumber(js_State *J, double v)
static js_Object *jsV_newstring(js_State *J, const char *v)
{
js_Object *obj = jsV_newobject(J, JS_CSTRING, J->String_prototype);
obj->u.string = v;
{
js_Property *ref;
ref = jsV_setproperty(J, obj, "length");
ref->value.type = JS_TNUMBER;
ref->value.u.number = utflen(v);
ref->atts = JS_READONLY | JS_DONTENUM | JS_DONTCONF;
}
obj->u.s.string = v;
obj->u.s.length = utflen(v);
return obj;
}
+4 -1
View File
@@ -62,7 +62,10 @@ struct js_Object
union {
int boolean;
double number;
const char *string;
struct {
const char *string;
unsigned int length;
} s;
struct {
unsigned int length;
} a;