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")) { js_pushnumber(J, obj->u.a.length); return 1; } } 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_pushrune(J, js_runeat(J, obj->u.s.string, k)); return 1; } } if (obj->type == JS_CREGEXP) { if (!strcmp(name, "source")) { js_pushliteral(J, obj->u.r.source); return 1; } if (!strcmp(name, "global")) { js_pushboolean(J, obj->u.r.flags & JS_REGEXP_G); return 1; } if (!strcmp(name, "ignoreCase")) { js_pushboolean(J, obj->u.r.flags & JS_REGEXP_I); return 1; } if (!strcmp(name, "multiline")) { js_pushboolean(J, obj->u.r.flags & JS_REGEXP_M); return 1; } if (!strcmp(name, "lastIndex")) { js_pushnumber(J, obj->u.r.last); return 1; } } ref = jsV_getproperty(J, obj, name); if (ref) { if (ref->getter) { js_pushobject(J, ref->getter); js_pushobject(J, obj); js_call(J, 0); } else { js_pushvalue(J, ref->value); } return 1; } return 0; }
static void jsR_defproperty(js_State *J, js_Object *obj, const char *name, int atts, js_Value *value, js_Object *getter, js_Object *setter) { js_Property *ref; unsigned int k; if (obj->type == JS_CARRAY) if (!strcmp(name, "length")) goto readonly; 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")) goto readonly; } ref = jsV_setproperty(J, obj, name); if (ref) { if (value) { if (!(ref->atts & JS_READONLY)) ref->value = *value; else if (J->strict) js_typeerror(J, "'%s' is read-only", name); } if (getter) { if (!(ref->atts & JS_DONTCONF)) ref->getter = getter; else if (J->strict) js_typeerror(J, "'%s' is non-configurable", name); } if (setter) { if (!(ref->atts & JS_DONTCONF)) ref->setter = setter; else if (J->strict) js_typeerror(J, "'%s' is non-configurable", name); } ref->atts |= atts; } return; readonly: if (J->strict) js_typeerror(J, "'%s' is read-only or non-configurable", name); }
static int itshadow(js_State *J, js_Object *top, js_Object *bot, const char *name) { 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; }
const char *jsV_nextiterator(js_State *J, js_Object *io) { int k; if (io->type != JS_CITERATOR) js_typeerror(J, "not an iterator"); while (io->u.iter.head) { js_Iterator *next = io->u.iter.head->next; const char *name = io->u.iter.head->name; js_free(J, io->u.iter.head); 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; }
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")) goto dontconf; if (obj->type == JS_CSTRING) { if (!strcmp(name, "length")) goto dontconf; if (js_isarrayindex(J, name, &k)) if (js_runeat(J, obj->u.s.string, k)) goto dontconf; } if (obj->type == JS_CREGEXP) { if (!strcmp(name, "source")) goto dontconf; if (!strcmp(name, "global")) goto dontconf; if (!strcmp(name, "ignoreCase")) goto dontconf; if (!strcmp(name, "multiline")) goto dontconf; if (!strcmp(name, "lastIndex")) goto dontconf; } ref = jsV_getownproperty(J, obj, name); if (ref) { if (ref->atts & JS_DONTCONF) goto dontconf; jsV_delproperty(J, obj, name); } return 1; dontconf: if (J->strict) js_typeerror(J, "'%s' is non-configurable", name); return 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); }