diff options
-rw-r--r-- | src/bindings/curl.nim | 63 | ||||
-rw-r--r-- | src/bindings/quickjs.nim | 28 | ||||
-rw-r--r-- | src/io/request.nim | 6 | ||||
-rw-r--r-- | src/js/javascript.nim | 174 |
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 |