diff options
author | bptato <nincsnevem662@gmail.com> | 2023-10-25 14:27:20 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-10-25 14:48:31 +0200 |
commit | 34cb7ac286ed5e37c6ff3774387b6a3eee6ab046 (patch) | |
tree | 3712f5a22fcc0802a36d5cfe91aa6513ac9a633d /src/js | |
parent | 80ff0251133d20a11d2ab428ac6f27aa14c45782 (diff) | |
download | chawan-34cb7ac286ed5e37c6ff3774387b6a3eee6ab046.tar.gz |
js: refine isInstanceOf check in functions
Special case the global object, check for inheritance, etc.
Diffstat (limited to 'src/js')
-rw-r--r-- | src/js/fromjs.nim | 29 | ||||
-rw-r--r-- | src/js/javascript.nim | 13 | ||||
-rw-r--r-- | src/js/opaque.nim | 1 |
3 files changed, 30 insertions, 13 deletions
diff --git a/src/js/fromjs.nim b/src/js/fromjs.nim index f5fc7d31..1d455090 100644 --- a/src/js/fromjs.nim +++ b/src/js/fromjs.nim @@ -14,7 +14,7 @@ import types/opt proc fromJS*[T](ctx: JSContext, val: JSValue): JSResult[T] -func isInstanceOf*(ctx: JSContext, val: JSValue, class: string): bool = +func isInstanceOfNonGlobal(ctx: JSContext, val: JSValue, class: string): bool = let ctxOpaque = ctx.getOpaque() var classid = JS_GetClassID(val) let tclassid = ctxOpaque.creg[class] @@ -31,6 +31,28 @@ func isInstanceOf*(ctx: JSContext, val: JSValue, class: string): bool = break return found +func isInstanceOfGlobal(ctx: JSContext, val: JSValue, class: string): bool = + let ctxOpaque = ctx.getOpaque() + #TODO gparent only works for a single level. (But this is not really a + # problem right now, because our global objects have at most one inheritance + # level.) + if ctx.isGlobal(class) or ctxOpaque.creg[class] == ctxOpaque.gparent: + # undefined -> global + if JS_IsUndefined(val): + return true + if JS_IsObject(val): + let global = JS_GetGlobalObject(ctx) + let p0 = JS_VALUE_GET_PTR(global) + let p1 = JS_VALUE_GET_PTR(val) + JS_FreeValue(ctx, global) + if p0 == p1: + return true + return false + +func isInstanceOf*(ctx: JSContext, val: JSValue, class: string): bool = + return ctx.isInstanceOfGlobal(val, class) or + ctx.isInstanceOfNonGlobal(val, class) + func toString(ctx: JSContext, val: JSValue): Opt[string] = var plen: csize_t let outp = JS_ToCStringLen(ctx, addr plen, val) # cstring @@ -367,12 +389,11 @@ proc fromJSPObj0(ctx: JSContext, val: JSValue, t: string): return err(nil) if JS_IsNull(val): return ok(nil) - let ctxOpaque = ctx.getOpaque() - if ctxOpaque.gclaz == t: + if ctx.isInstanceOfGlobal(val, t): return ok(?getGlobalOpaque0(ctx, val)) if not JS_IsObject(val): return err(newTypeError("Value is not an object")) - if not isInstanceOf(ctx, val, t): + if not isInstanceOfNonGlobal(ctx, val, t): let errmsg = t & " expected" JS_ThrowTypeError(ctx, cstring(errmsg)) return err(newTypeError(errmsg)) diff --git a/src/js/javascript.nim b/src/js/javascript.nim index fefc3ed8..3f6de0a2 100644 --- a/src/js/javascript.nim +++ b/src/js/javascript.nim @@ -255,6 +255,7 @@ func newJSClass*(ctx: JSContext, cdef: JSClassDefConst, tname: string, let global = JS_GetGlobalObject(ctx) assert ctxOpaque.gclaz == "" ctxOpaque.gclaz = tname + ctxOpaque.gparent = parent if JS_SetPrototype(ctx, global, proto) != 1: raise newException(Defect, "Failed to set global prototype: " & $cdef.class_name) @@ -780,9 +781,7 @@ proc newJSProcBody(gen: var JSFuncGenerator, isva: bool): NimNode = let tn = ident(gen.thisname.get) let ev = gen.errval result.add(quote do: - if not (JS_IsUndefined(`tn`) or ctx.isGlobal(`tt`)) and - not isInstanceOf(ctx, `tn`, `tt`): - # undefined -> global. + if not ctx.isInstanceOf(`tn`, `tt`): discard JS_ThrowTypeError(ctx, "'%s' called on an object that is not an instance of %s", `fn`, `tt`) return `ev` @@ -1315,9 +1314,7 @@ proc registerGetters(stmts: NimNode, info: RegistryInfo, let id = ident($GETTER & "_" & tname & "_" & fn) stmts.add(quote do: proc `id`(ctx: JSContext, this: JSValue): JSValue {.cdecl.} = - if not (JS_IsUndefined(this) or ctx.isGlobal(`tname`)) and - not ctx.isInstanceOf(this, `tname`): - # undefined -> global. + if not ctx.isInstanceOf(this, `tname`): return JS_ThrowTypeError(ctx, "'%s' called on an object that is not an instance of %s", `fn`, `jsname`) @@ -1342,9 +1339,7 @@ proc registerSetters(stmts: NimNode, info: RegistryInfo, stmts.add(quote do: proc `id`(ctx: JSContext, this: JSValue, val: JSValue): JSValue {.cdecl.} = - if not (JS_IsUndefined(this) or ctx.isGlobal(`tname`)) and - not ctx.isInstanceOf(this, `tname`): - # undefined -> global. + if not ctx.isInstanceOf(this, `tname`): return JS_ThrowTypeError(ctx, "'%s' called on an object that is not an instance of %s", `fn`, `jsname`) diff --git a/src/js/opaque.nim b/src/js/opaque.nim index 30456602..1f0ad529 100644 --- a/src/js/opaque.nim +++ b/src/js/opaque.nim @@ -25,6 +25,7 @@ type # `unforgeable[classid]'.) unforgeable*: Table[JSClassID, seq[JSCFunctionListEntry]] gclaz*: string + gparent*: JSClassID sym_refs*: array[JSSymbolRefs, JSAtom] str_refs*: array[JSStrRefs, JSAtom] Array_prototype_values*: JSValue |