about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/bindings/curl.nim63
-rw-r--r--src/bindings/quickjs.nim28
-rw-r--r--src/io/request.nim6
-rw-r--r--src/js/javascript.nim174
4 files changed, 146 insertions, 125 deletions
diff --git a/src/bindings/curl.nim b/src/bindings/curl.nim
index 7c88f3f6..0a3f3fd0 100644
--- a/src/bindings/curl.nim
+++ b/src/bindings/curl.nim
@@ -33,8 +33,8 @@ const
   CURLINFO_PTR = 0x400000 # same as SLIST
   CURLINFO_SOCKET = 0x500000
   CURLINFO_OFF_T = 0x600000
-  CURLINFO_MASK = 0x0fffff
-  CURLINFO_TYPEMASK = 0xf00000
+  CURLINFO_MASK {.used.} = 0x0fffff
+  CURLINFO_TYPEMASK {.used.} = 0xf00000
 
 {.push cdecl, dynlib: curllib.}
 
@@ -51,6 +51,8 @@ type
   CURLoption* {.size: sizeof(cint).} = enum
     # Long
     CURLOPT_PORT = CURLOPTTYPE_LONG + 3
+    CURLOPT_SSLVERSION = CURLOPTTYPE_VALUES + 32
+    CURLOPT_TIMECONDITION = CURLOPTTYPE_VALUES + 33
     CURLOPT_POST = CURLOPTTYPE_LONG + 47
     CURLOPT_FOLLOWLOCATION = CURLOPTTYPE_LONG + 52
     CURLOPT_POSTFIELDSIZE = CURLOPTTYPE_LONG + 60
@@ -90,9 +92,25 @@ type
     # Long
     CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2
 
+    # Double
+    CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3
+
+    # S-list
+    CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27
+    CURLINFO_COOKIELIST = CURLINFO_SLIST + 28
+
+    # Pointer
+    CURLINFO_CERTINFO = CURLINFO_PTR + 34
+    CURLINFO_TLS_SESSION = CURLINFO_PTR + 43
+    CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45
+
     # Socket
     CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44
 
+    # Off_t
+    CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7
+    CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 9
+
   CURLcode* {.size: sizeof(cint).} = enum
     CURLE_OK = 0,
     CURLE_UNSUPPORTED_PROTOCOL,    # 1 
@@ -221,24 +239,27 @@ type
     CURLE_UNRECOVERABLE_POLL,      # 99 - poll/select returned fatal error 
     CURL_LAST # never use! 
 
-proc curl_global_init*(flags: clong): CURLcode {.importc: "curl_global_init".}
-proc curl_global_cleanup*() {.importc: "curl_global_cleanup".}
-
-proc curl_easy_init*(): CURL {.importc: "curl_easy_init".}
-proc curl_easy_cleanup*(handle: CURL) {.importc: "curl_easy_cleanup".}
-proc curl_easy_setopt*(handle: CURL, option: CURLoption): CURLcode {.importc: "curl_easy_setopt", varargs.}
-proc curl_easy_perform*(handle: CURL): CURLcode {.importc: "curl_easy_perform".}
-proc curl_easy_getinfo*(handle: CURL, info: CURLINFO): CURLcode {.importc: "curl_easy_getinfo", varargs.}
-
-proc curl_mime_init*(handle: CURL): curl_mime {.importc: "curl_mime_init".}
-proc curl_mime_free*(mime: curl_mime) {.importc: "curl_mime_free".}
-proc curl_mime_addpart*(mime: curl_mime): curl_mimepart {.importc: "curl_mime_addpart".}
-proc curl_mime_name*(part: curl_mimepart, name: cstring) {.importc: "curl_mime_name".}
-proc curl_mime_data*(part: curl_mimepart, data: cstring, datasize: csize_t) {.importc: "curl_mime_name".}
-proc curl_mime_filename*(part: curl_mimepart, name: cstring) {.importc: "curl_mime_filename".}
-proc curl_mime_filedata*(part: curl_mimepart, filename: cstring) {.importc: "curl_mime_filedata".}
-
-proc curl_slist_append*(slist: curl_slist, str: cstring): curl_slist {.importc: "curl_slist_append".}
-proc curl_slist_free_all*(slist: curl_slist) {.importc: "curl_slist_free_all".}
+{.push importc.}
+
+proc curl_global_init*(flags: clong): CURLcode
+proc curl_global_cleanup*()
+
+proc curl_easy_init*(): CURL
+proc curl_easy_cleanup*(handle: CURL)
+proc curl_easy_setopt*(handle: CURL, option: CURLoption): CURLcode {.varargs.}
+proc curl_easy_perform*(handle: CURL): CURLcode
+proc curl_easy_getinfo*(handle: CURL, info: CURLINFO): CURLcode {.varargs.}
+
+proc curl_mime_init*(handle: CURL): curl_mime
+proc curl_mime_free*(mime: curl_mime)
+proc curl_mime_addpart*(mime: curl_mime): curl_mimepart
+proc curl_mime_name*(part: curl_mimepart, name: cstring)
+proc curl_mime_data*(part: curl_mimepart, data: cstring, datasize: csize_t)
+proc curl_mime_filename*(part: curl_mimepart, name: cstring)
+proc curl_mime_filedata*(part: curl_mimepart, filename: cstring)
+
+proc curl_slist_append*(slist: curl_slist, str: cstring): curl_slist
+proc curl_slist_free_all*(slist: curl_slist)
+{.pop.}
 
 {.pop.}
diff --git a/src/bindings/quickjs.nim b/src/bindings/quickjs.nim
index d216f6cf..290cbeca 100644
--- a/src/bindings/quickjs.nim
+++ b/src/bindings/quickjs.nim
@@ -88,6 +88,8 @@ type
   JSCFunction* = proc (ctx: JSContext, this_val: JSValue, argc: int, argv: ptr JSValue): JSValue {.cdecl.}
   JSGetterFunction* = proc(ctx: JSContext, this_val: JSValue): JSValue {.cdecl.}
   JSSetterFunction* = proc(ctx: JSContext, this_val: JSValue, val: JSValue): JSValue {.cdecl.}
+  JSGetterMagicFunction* = proc(ctx: JSContext, this_val: JSValue, magic: cint): JSValue {.cdecl.}
+  JSSetterMagicFunction* = proc(ctx: JSContext, this_val: JSValue, val: JSValue, magic: cint): JSValue {.cdecl.}
   JSInterruptHandler* = proc (rt: JSRuntime, opaque: pointer): int {.cdecl.}
   JSClassID* = uint32
   JSAtom* = uint32
@@ -130,6 +132,8 @@ type
     generic*: JSCFunction
     getter*: JSGetterFunction
     setter*: JSSetterFunction
+    getter_magic*: JSGetterMagicFunction
+    setter_magic*: JSSetterMagicFunction
 
   JSCFunctionListEntryFunc = object
     length*: uint8
@@ -236,17 +240,29 @@ template JS_CFUNC_DEF*(n: string, len: uint8, func1: JSCFunction): JSCFunctionLi
                        prop_flags: JS_PROP_WRITABLE or JS_PROP_CONFIGURABLE,
                        def_type: JS_DEF_CFUNC,
                        u: JSCFunctionListEntryU(
-                         `func`: JSCFunctionListEntryFunc(length: len,
-                                                          cproto: JS_CFUNC_generic,
-                                                          cfunc: JSCFunctionType(generic: func1))))
+                         `func`: JSCFunctionListEntryFunc(
+                           length: len,
+                           cproto: JS_CFUNC_generic,
+                           cfunc: JSCFunctionType(generic: func1))))
 
 template JS_CGETSET_DEF*(n: string, fgetter, fsetter: untyped): JSCFunctionListEntry =
   JSCFunctionListEntry(name: cstring(n),
                        prop_flags: JS_PROP_CONFIGURABLE,
                        def_type: JS_DEF_CGETSET,
                        u: JSCFunctionListEntryU(
-                         getset: JSCFunctionListEntryGetSet(get: JSCFunctionType(getter: fgetter),
-                                                            set: JSCFunctionType(setter: fsetter))))
+                         getset: JSCFunctionListEntryGetSet(
+                           get: JSCFunctionType(getter: fgetter),
+                           set: JSCFunctionType(setter: fsetter))))
+
+template JS_CGETSET_MAGIC_DEF*(n: string, fgetter, fsetter: untyped, m: cint): JSCFunctionListEntry =
+  JSCFunctionListEntry(name: cstring(n),
+                       prop_flags: JS_PROP_CONFIGURABLE,
+                       def_type: JS_DEF_CGETSET_MAGIC,
+                       magic: m,
+                       u: JSCFunctionListEntryU(
+                         getset: JSCFunctionListEntryGetSet(
+                           get: JSCFunctionType(getter_magic: fgetter),
+                           set: JSCFunctionType(setter_magic: fsetter))))
 
 
 {.push header: qjsheader, importc, cdecl.}
@@ -289,7 +305,7 @@ proc JS_NewUint32*(ctx: JSContext, val: uint32): JSValue
 proc JS_NewUint64*(ctx: JSContext, val: uint64): JSValue
 proc JS_NewBigInt64*(ctx: JSContext, val: int64): JSValue
 proc JS_NewBigUInt64*(ctx: JSContext, val: uint64): JSValue
-proc JS_NewFloat64*(ctx: JSContext, val: uint64): JSValue
+proc JS_NewFloat64*(ctx: JSContext, val: cdouble): JSValue
 
 proc JS_NewAtomLen*(ctx: JSContext, str: cstring, len: csize_t): JSAtom
 proc JS_ValueToAtom*(ctx: JSContext, val: JSValue): JSAtom
diff --git a/src/io/request.nim b/src/io/request.nim
index 6e6f3f40..9332f9ff 100644
--- a/src/io/request.nim
+++ b/src/io/request.nim
@@ -174,7 +174,11 @@ func getOrDefault*(headers: HeaderList, k: string, default = ""): string =
     default
 
 proc readAll*(response: Response): string {.jsfunc.} =
-  return response.body.readAll()
+  result = response.body.readAll()
+  response.body.close()
+
+proc close*(response: Response) {.jsfunc.} =
+  response.body.close()
 
 proc addRequestModule*(ctx: JSContext) =
   ctx.registerType(Request)
diff --git a/src/js/javascript.nim b/src/js/javascript.nim
index 798b2180..24a87622 100644
--- a/src/js/javascript.nim
+++ b/src/js/javascript.nim
@@ -611,7 +611,7 @@ func toJSBool(ctx: JSContext, b: bool): JSValue =
   return JS_NewBool(ctx, b)
 
 proc getTypePtr[T](x: T): pointer =
-  when T is RootRef:
+  when T is RootRef or T is pointer:
     # I'm so sorry.
     # (This dereferences the object's first member, m_type. Probably.)
     return cast[ptr pointer](x)[]
@@ -689,7 +689,12 @@ type
     j: int # js parameters accounted for (not including fix ones, e.g. `this')
     res: NimNode
 
-var RegisteredFunctions {.compileTime.}: Table[string, seq[(NimNode, NimNode)]]
+  RegisteredFunction = object
+    name: string
+    id: NimNode
+    magic: uint16
+
+var RegisteredFunctions {.compileTime.}: Table[string, seq[RegisteredFunction]]
 
 proc getGenerics(fun: NimNode): Table[string, seq[NimNode]] =
   var node = fun.findChild(it.kind == nnkBracket)
@@ -949,11 +954,15 @@ proc finishFunCallList(gen: var JSFuncGenerator) =
 
 var js_funcs {.compileTime.}: Table[string, JSFuncGenerator]
 
-proc registerFunction(gen: JSFuncGenerator) =
-  if gen.thisType notin RegisteredFunctions:
-    RegisteredFunctions[gen.thisType] = @[(newStrLitNode(gen.funcName), ident(gen.newName))]
+proc registerFunction(typ: string, name: string, id: NimNode, magic: uint16 = 0) =
+  let nf = RegisteredFunction(name: name, id: id, magic: magic)
+  if typ notin RegisteredFunctions:
+    RegisteredFunctions[typ] = @[nf]
   else:
-    RegisteredFunctions[gen.thisType].add((newStrLitNode(gen.funcName), ident(gen.newName)))
+    RegisteredFunctions[typ].add(nf)
+
+proc registerFunction(gen: JSFuncGenerator) =
+  registerFunction(gen.thisType, gen.funcName, ident(gen.newName))
   js_funcs[gen.funcName] = gen
 
 var js_errors {.compileTime.}: Table[string, seq[string]]
@@ -1158,40 +1167,6 @@ macro jsfunc*(fun: typed) =
 template jsget*() {.pragma.}
 template jsset*() {.pragma.}
 
-proc findPragmas(otab: var Table[string, seq[NimNode]], t: NimNode) =
-  let typ = t.getTypeInst()[1] # The type, as declared.
-  var impl = typ.getTypeImpl() # ref t
-  assert impl.kind == nnkRefTy, "Only ref nodes are supported..."
-  impl = impl[0].getImpl()
-  # stolen from std's macros.customPragmaNode
-  var identDefsStack = newSeq[NimNode](impl[2].len)
-  for i in 0..<identDefsStack.len: identDefsStack[i] = impl[2][i]
-  while identDefsStack.len > 0:
-    var identDefs = identDefsStack.pop()
-
-    case identDefs.kind
-    of nnkRecList:
-      for child in identDefs.children:
-        identDefsStack.add(child)
-    of nnkRecCase:
-      # Add condition definition
-      identDefsStack.add(identDefs[0])
-      # Add branches
-      for i in 1 ..< identDefs.len:
-        identDefsStack.add(identDefs[i].last)
-    else:
-      for i in 0 .. identDefs.len - 3:
-        let varNode = identDefs[i]
-        if varNode.kind == nnkPragmaExpr:
-          var varName = varNode[0]
-          if varName.kind == nnkPostfix:
-            # This is a public field. We are skipping the postfix *
-            varName = varName[1]
-          for pragma in varNode[1]:
-            let pragmaName = ($pragma).tolower()
-            if pragmaName in otab: #TODO this isn't style sensitive...
-              otab[pragmaName].add(varName)
-
 proc nim_finalize_for_js[T](obj: T) =
   for rt in runtimes:
     let rtOpaque = rt.getOpaque()
@@ -1234,104 +1209,109 @@ template fromJS_or_return*(t, ctx, val: untyped): untyped =
     x.get
   )
 
+type JSObjectPragmas = object
+  jsget: seq[NimNode]
+  jsset: seq[NimNode]
+
+proc findPragmas(t: NimNode): JSObjectPragmas =
+  let typ = t.getTypeInst()[1] # The type, as declared.
+  var impl = typ.getTypeImpl() # ref t
+  assert impl.kind == nnkRefTy, "Only ref nodes are supported..."
+  impl = impl[0].getImpl()
+  # stolen from std's macros.customPragmaNode
+  var identDefsStack = newSeq[NimNode](impl[2].len)
+  for i in 0..<identDefsStack.len: identDefsStack[i] = impl[2][i]
+  while identDefsStack.len > 0:
+    var identDefs = identDefsStack.pop()
+
+    case identDefs.kind
+    of nnkRecList:
+      for child in identDefs.children:
+        identDefsStack.add(child)
+    of nnkRecCase:
+      # Add condition definition
+      identDefsStack.add(identDefs[0])
+      # Add branches
+      for i in 1 ..< identDefs.len:
+        identDefsStack.add(identDefs[i].last)
+    else:
+      for i in 0 .. identDefs.len - 3:
+        let varNode = identDefs[i]
+        if varNode.kind == nnkPragmaExpr:
+          var varName = varNode[0]
+          if varName.kind == nnkPostfix:
+            # This is a public field. We are skipping the postfix *
+            varName = varName[1]
+          for pragma in varNode[1]:
+            case $pragma
+            of "jsget": result.jsget.add(varName)
+            of "jsset": result.jsset.add(varName)
+
 macro registerType*(ctx: typed, t: typed, parent: JSClassID = 0, asglobal = false, nointerface = false): JSClassID =
+  result = newStmtList()
   let s = t.strVal
   var sctr = ident("js_illegal_ctor")
   var sfin = ident("js_" & s & "ClassFin")
   var ctorFun: NimNode
   var ctorImpl: NimNode
   var setters, getters: Table[string, NimNode]
-  var pragmas: Table[string, seq[NimNode]]
-  pragmas["jsget"] = @[]
-  pragmas["jsset"] = @[]
-  pragmas.findPragmas(t)
-  result = newStmtList()
-  #TODO use magic functions instead
-  for node in pragmas["jsget"]:
+  let tabList = newNimNode(nnkBracket)
+  let pragmas = findPragmas(t)
+  for node in pragmas.jsget:
     let id = ident("js_get_" & s & "_" & $node)
     let fn = $node
     result.add(quote do:
-      proc `id`(ctx: JSContext, this: JSValue): JSValue =
+      proc `id`(ctx: JSContext, this: JSValue): JSValue {.cdecl.} =
         if not (JS_IsUndefined(this) or ctx.isGlobal(`s`)) and not ctx.isInstanceOf(this, `s`):
           # undefined -> global.
           return JS_ThrowTypeError(ctx, "'%s' called on an object that is not an instance of %s", `fn`, `s`)
         let arg_0 = fromJS_or_return(`t`, ctx, this)
         return toJS(ctx, arg_0.`node`)
     )
-    if s notin RegisteredFunctions:
-      RegisteredFunctions[s] = @[(node, id)]
-    else:
-      RegisteredFunctions[s].add((node, id))
-  for node in pragmas["jsset"]:
+    registerFunction(s, fn, id)
+  for node in pragmas.jsset:
     let id = ident("js_set_" & s & "_" & $node)
     let fn = $node
     result.add(quote do:
-      proc `id`(ctx: JSContext, this: JSValue, val: JSValue): JSValue =
+      proc `id`(ctx: JSContext, this: JSValue, val: JSValue): JSValue {.cdecl.} =
         if not (JS_IsUndefined(this) or ctx.isGlobal(`s`)) and not ctx.isInstanceOf(this, `s`):
           # undefined -> global.
           return JS_ThrowTypeError(ctx, "'%s' called on an object that is not an instance of %s", `fn`, `s`)
-        let arg_0 = (block:
-          let t = fromJS[`t`](ctx, this)
-          if t.isnone:
-            return JS_EXCEPTION
-          t.get
-        )
+        let arg_0 = fromJS_or_return(`t`, ctx, this)
         let arg_1 = val
-        arg_0.`node` = (block:
-          let t = fromJS[typeof(arg_0.`node`)](ctx, arg_1)
-          if t.isnone:
-            return JS_EXCEPTION
-          t.get
-        )
+        arg_0.`node` = fromJS_or_return(typeof(arg_0.`node`), ctx, arg_1)
         return JS_DupValue(ctx, arg_1)
     )
-    if s notin RegisteredFunctions:
-      RegisteredFunctions[s] = @[(node, id)]
-    else:
-      RegisteredFunctions[s].add((node, id))
-  let tabList = newNimNode(nnkBracket)
+    registerFunction(s, fn, id)
+
   if s in RegisteredFunctions:
-    for fun in RegisteredFunctions[s]:
-      #TODO this is a mess
-      var f0 = fun[0]
-      let f1 = fun[1]
-      let f2 = fun[0]
-      if f0.strVal.endsWith("_exceptions"):
-        f0 = newLit(f0.strVal.substr(0, f0.strVal.high - "_exceptions".len))
+    for fun in RegisteredFunctions[s].mitems:
+      var f0 = fun.name
+      let f1 = fun.id
+      if fun.name.endsWith("_exceptions"):
+        fun.name = fun.name.substr(0, fun.name.high - "_exceptions".len)
       if f1.strVal.startsWith("js_new"):
-        ctorImpl = js_funcs[$f2].res
+        ctorImpl = js_funcs[$f0].res
         if ctorFun != nil:
           error("Class " & $s & " has 2+ constructors.")
         ctorFun = f1
       elif f1.strVal.startsWith("js_get"):
-        getters[$f0] = f1
+        getters[f0] = f1
       elif f1.strVal.startsWith("js_set"):
-        setters[$f0] = f1
+        setters[f0] = f1
       else:
         tabList.add(quote do:
           JS_CFUNC_DEF(`f0`, 0, cast[JSCFunction](`f1`)))
+
   for k, v in getters:
     if k in setters:
       let s = setters[k]
-      tabList.add(newCall((quote do: JS_CGETSET_DEF),
-                          newLit(k),
-                          newNimNode(nnkCast).add(quote do: JSGetterFunction,
-                                                  v),
-                          newNimNode(nnkCast).add(quote do: JSSetterFunction,
-                                                  s)))
+      tabList.add(quote do: JS_CGETSET_DEF(`k`, `v`, `s`))
     else:
-      tabList.add(newCall((quote do: JS_CGETSET_DEF),
-                          newLit(k),
-                          newNimNode(nnkCast).add(quote do: JSGetterFunction,
-                                                  v),
-                          newNilLit()))
+      tabList.add(quote do: JS_CGETSET_DEF(`k`, `v`, nil))
   for k, v in setters:
     if k notin getters:
-      tabList.add(newCall((quote do: JS_CGETSET_DEF),
-                          newLit(k),
-                          newNilLit(),
-                          newNimNode(nnkCast).add(quote do: JSSetterFunction,
-                                                  v)))
+      tabList.add(quote do: JS_CGETSET_DEF(`k`, nil, `v`))
 
   if ctorFun != nil:
     sctr = ctorFun