about summary refs log tree commit diff stats
path: root/src/js
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2023-10-25 11:56:54 +0200
committerbptato <nincsnevem662@gmail.com>2023-10-25 12:04:37 +0200
commit98865ac747766118b94f39f749aba4be62c78022 (patch)
treedd0d6520997eef16fa7238d1dc486affd49057b6 /src/js
parente4cccbeb7488dfe8afbbe51c60fd16557dea923f (diff)
downloadchawan-98865ac747766118b94f39f749aba4be62c78022.tar.gz
Add jspropnames, CSSStyleDeclaration stub
Diffstat (limited to 'src/js')
-rw-r--r--src/js/javascript.nim53
-rw-r--r--src/js/propertyenumlist.nim42
2 files changed, 92 insertions, 3 deletions
diff --git a/src/js/javascript.nim b/src/js/javascript.nim
index 996137cd..e682098a 100644
--- a/src/js/javascript.nim
+++ b/src/js/javascript.nim
@@ -32,6 +32,9 @@
 # {.jsdelprop.} for property deletion. It is like the deleteProperty method
 #   of Proxy. Must return true if deleted, false if not deleted.
 # {.jshasprop.} for overriding has_property. Must return a boolean.
+# {.jspropnames.} overrides get_own_property_names. Must return a
+#   JSPropertyEnumList object.
+# UncheckedArray[JSPropertyEnum]
 
 import macros
 import options
@@ -98,6 +101,7 @@ type
     PROPERTY_SET = "js_prop_set"
     PROPERTY_DEL = "js_prop_del"
     PROPERTY_HAS = "js_prop_has"
+    PROPERTY_NAMES = "js_prop_names"
     FINALIZER = "js_fin"
 
 var runtimes {.threadVar.}: seq[JSRuntime]
@@ -471,6 +475,15 @@ template getJSSetterParams(): untyped =
     newIdentDefs(ident("val"), quote do: JSValue),
   ]
 
+template getJSPropNamesParams(): untyped =
+  [
+    (quote do: cint),
+    newIdentDefs(ident("ctx"), quote do: JSContext),
+    newIdentDefs(ident("ptab"), quote do: ptr JSPropertyEnumArray),
+    newIdentDefs(ident("plen"), quote do: ptr uint32),
+    newIdentDefs(ident("obj"), quote do: JSValue)
+  ]
+
 template fromJS_or_return*(t, ctx, val: untyped): untyped =
   (
     let x = fromJS[t](ctx, val)
@@ -563,6 +576,10 @@ proc addUnionParam0(gen: var JSFuncGenerator, tt: NimNode, s: NimNode, val: NimN
     elif g == bool.getTypeInst():
       hasBoolean = true
     elif g == int.getTypeInst(): #TODO should be SomeNumber
+      assert numg.isNone
+      numg = some(g)
+    elif g == uint32.getTypeInst(): #TODO should be SomeNumber
+      assert numg.isNone
       numg = some(g)
     elif g.getTypeInst().getTypeImpl().kind == nnkRefTy:
       # Assume it's ref object.
@@ -789,7 +806,8 @@ func getFuncName(fun: NimNode, jsname: string): string =
   return x
 
 func getErrVal(t: BoundFunctionType): NimNode =
-  if t in {PROPERTY_GET, PROPERTY_SET, PROPERTY_DEL, PROPERTY_HAS}:
+  if t in {PROPERTY_GET, PROPERTY_SET, PROPERTY_DEL, PROPERTY_HAS,
+      PROPERTY_NAMES}:
     return quote do: cint(-1)
   return quote do: JS_EXCEPTION
 
@@ -976,6 +994,26 @@ macro jsdelprop*(fun: typed) =
   gen.registerFunction()
   return newStmtList(fun, jsProc)
 
+macro jspropnames*(fun: typed) =
+  var gen = setupGenerator(fun, PROPERTY_NAMES, thisname = some("obj"))
+  if gen.newName.strVal in existing_funcs:
+    #TODO TODO TODO ditto
+    error("Function overloading hasn't been implemented yet...")
+  gen.addFixParam("obj")
+  gen.finishFunCallList()
+  let jfcl = gen.jsFunCallList
+  let dl = gen.dielabel
+  gen.jsCallAndRet = quote do:
+    block `dl`:
+      let retv = `jfcl`
+      ptab[] = retv.buffer
+      plen[] = retv.len
+      return cint(0)
+    return cint(-1)
+  let jsProc = gen.newJSProc(getJSPropNamesParams(), false)
+  gen.registerFunction()
+  return newStmtList(fun, jsProc)
+
 macro jsfgetn(jsname: static string, uf: static bool, fun: typed) =
   var gen = setupGenerator(fun, GETTER, jsname = jsname, unforgeable = uf)
   if gen.actualMinArgs != 0 or gen.funcParams.len != gen.minArgs:
@@ -1221,6 +1259,7 @@ type RegistryInfo = object
   propSetFun: NimNode # custom set function ident
   propDelFun: NimNode # custom del function ident
   propHasFun: NimNode # custom has function ident
+  propNamesFun: NimNode # custom property names function ident
   finFun: NimNode # finalizer ident
   finName: NimNode # finalizer wrapper ident
   dfin: NimNode # CheckDestroy finalizer ident
@@ -1252,7 +1291,8 @@ proc newRegistryInfo(t: NimNode, name: string): RegistryInfo =
     propGetFun: newNilLit(),
     propSetFun: newNilLit(),
     propDelFun: newNilLit(),
-    propHasFun: newNilLit()
+    propHasFun: newNilLit(),
+    propNamesFun: newNilLit()
   )
   if info.tname notin js_dtors:
     warning("No destructor has been defined for type " & info.tname)
@@ -1368,6 +1408,10 @@ proc bindFunctions(stmts: NimNode, info: var RegistryInfo) =
         if info.propHasFun.kind != nnkNilLit:
           error("Class " & info.tname & " has 2+ hasprop getters.")
         info.propHasFun = f1
+      of PROPERTY_NAMES:
+        if info.propNamesFun.kind != nnkNilLit:
+          error("Class " & info.tname & " has 2+ propnames getters.")
+        info.propNamesFun = f1
       of FINALIZER:
         f0 = fun.name
         info.finFun = ident(f0)
@@ -1463,16 +1507,19 @@ proc bindEndStmts(endstmts: NimNode, info: RegistryInfo) =
   if info.propGetFun.kind != nnkNilLit or
       info.propSetFun.kind != nnkNilLit or
       info.propDelFun.kind != nnkNilLit or
-      info.propHasFun.kind != nnkNilLit:
+      info.propHasFun.kind != nnkNilLit or
+      info.propNamesFun.kind != nnkNilLit:
     let propGetFun = info.propGetFun
     let propSetFun = info.propSetFun
     let propDelFun = info.propDelFun
     let propHasFun = info.propHasFun
+    let propNamesFun = info.propNamesFun
     endstmts.add(quote do:
       # No clue how to do this in pure nim.
       {.emit: ["""
 static JSClassExoticMethods exotic = {
 	.get_own_property = """, `propGetFun`, """,
+        .get_own_property_names = """, `propNamesFun`, """,
 	.has_property = """, `propHasFun`, """,
 	.set_property = """, `propSetFun`, """,
 	.delete_property = """, `propDelFun`, """
diff --git a/src/js/propertyenumlist.nim b/src/js/propertyenumlist.nim
new file mode 100644
index 00000000..98ad2a4f
--- /dev/null
+++ b/src/js/propertyenumlist.nim
@@ -0,0 +1,42 @@
+import bindings/quickjs
+
+type
+  JSPropertyEnumArray* = ptr UncheckedArray[JSPropertyEnum]
+
+  JSPropertyEnumList* = object
+    buffer*: JSPropertyEnumArray
+    size: uint32
+    len*: uint32
+    ctx: JSContext
+
+  JSPropertyEnumWrapper* = object
+    is_enumerable: bool
+    name: string
+
+func newJSPropertyEnumList*(ctx: JSContext, size: uint32): JSPropertyEnumList =
+  let p = js_malloc(ctx, csize_t(sizeof(JSPropertyEnum)) * csize_t(size))
+  let buffer = cast[JSPropertyEnumArray](p)
+  return JSPropertyEnumList(
+    ctx: ctx,
+    buffer: buffer,
+    size: size
+  )
+
+proc grow(this: var JSPropertyEnumList) =
+  this.size *= 2
+  let p = js_realloc(this.ctx, this.buffer, csize_t(this.size))
+  this.buffer = cast[JSPropertyEnumArray](p)
+
+proc add*(this: var JSPropertyEnumList, val: uint32) =
+  let i = this.len
+  inc this.len
+  if this.size < this.len:
+    this.grow()
+  this.buffer[i].atom = JS_NewAtomUInt32(this.ctx, val)
+
+proc add*(this: var JSPropertyEnumList, val: string) =
+  let i = this.len
+  inc this.len
+  if this.size < this.len:
+    this.grow()
+  this.buffer[i].atom = JS_NewAtomLen(this.ctx, cstring(val), csize_t(val.len))