mirror of
https://github.com/ccxvii/mujs.git
synced 2026-09-21 22:53:41 +08:00
Add virtual string array index properties for characters.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user