diff options
author | bptato <nincsnevem662@gmail.com> | 2023-09-17 13:00:20 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-09-17 13:00:20 +0200 |
commit | ba2d0b1d8dae67b6f8d3e815a61d26c7c0b1ce2f (patch) | |
tree | 31e702713bf5514956dda362c9125eec78f8b6a4 | |
parent | ee2ab29090201c2bf08dcb46e7f6ebd35d9bc23a (diff) | |
download | chawan-ba2d0b1d8dae67b6f8d3e815a61d26c7c0b1ce2f.tar.gz |
javascript: static methods, URL.canParse
-rw-r--r-- | src/js/javascript.nim | 69 | ||||
-rw-r--r-- | src/types/url.nim | 17 |
2 files changed, 58 insertions, 28 deletions
diff --git a/src/js/javascript.nim b/src/js/javascript.nim index 6f3038cb..05af7217 100644 --- a/src/js/javascript.nim +++ b/src/js/javascript.nim @@ -87,6 +87,7 @@ type id: NimNode magic: uint16 unforgeable: bool + isstatic: bool BoundFunctionType = enum FUNCTION = "js_func" @@ -208,7 +209,7 @@ func newJSClass*(ctx: JSContext, cdef: JSClassDefConst, tname: string, nimt: pointer, ctor: JSCFunction, funcs: JSFunctionList, parent: JSClassID, asglobal: bool, nointerface: bool, finalizer: proc(val: JSValue), namespace: JSValue, errid: Opt[JSErrorEnum], - unforgeable: JSFunctionList): JSClassID {.discardable.} = + unforgeable, staticfuns: JSFunctionList): JSClassID {.discardable.} = let rt = JS_GetRuntime(ctx) discard JS_NewClassID(addr result) var ctxOpaque = ctx.getOpaque() @@ -254,6 +255,10 @@ func newJSClass*(ctx: JSContext, cdef: JSClassDefConst, tname: string, JS_SetPropertyFunctionList(ctx, global, addr uf[][0], cint(uf[].len)) JS_FreeValue(ctx, global) let jctor = ctx.newJSCFunction($cdef.class_name, ctor, 0, JS_CFUNC_constructor) + if staticfuns.len > 0: + rtOpaque.flist.add(@staticfuns) + JS_SetPropertyFunctionList(ctx, jctor, addr rtOpaque.flist[^1][0], + cint(staticfuns.len)) JS_SetConstructor(ctx, jctor, proto) if errid.isSome: ctx.getOpaque().err_ctors[errid.get] = JS_DupValue(ctx, jctor) @@ -323,6 +328,7 @@ type j: int # js parameters accounted for (not including fix ones, e.g. `this') res: NimNode unforgeable: bool + isstatic: bool var BoundFunctions {.compileTime.}: Table[string, seq[BoundFunction]] @@ -701,13 +707,14 @@ var existing_funcs {.compileTime.}: HashSet[string] var js_dtors {.compileTime.}: HashSet[string] proc newBoundFunction(t: BoundFunctionType, name: string, id: NimNode, - magic: uint16 = 0, uf = false): BoundFunction = + magic: uint16 = 0, uf = false, isstatic = false): BoundFunction = return BoundFunction( t: t, name: name, id: id, magic: magic, - unforgeable: uf + unforgeable: uf, + isstatic: isstatic ) proc registerFunction(typ: string, nf: BoundFunction) = @@ -718,18 +725,18 @@ proc registerFunction(typ: string, nf: BoundFunction) = existing_funcs.incl(nf.id.strVal) proc registerFunction(typ: string, t: BoundFunctionType, name: string, - id: NimNode, magic: uint16 = 0, uf = false) = - let nf = newBoundFunction(t, name, id, magic, uf) + id: NimNode, magic: uint16 = 0, uf = false, isstatic = false) = + let nf = newBoundFunction(t, name, id, magic, uf, isstatic) registerFunction(typ, nf) proc registerConstructor(gen: JSFuncGenerator) = registerFunction(gen.thisType, gen.t, gen.funcName, gen.newName, - uf = gen.unforgeable) + uf = gen.unforgeable, isstatic = gen.isstatic) js_funcs[gen.funcName] = gen proc registerFunction(gen: JSFuncGenerator) = registerFunction(gen.thisType, gen.t, gen.funcName, gen.newName, - uf = gen.unforgeable) + uf = gen.unforgeable, isstatic = gen.isstatic) export JS_ThrowTypeError, JS_ThrowRangeError, JS_ThrowSyntaxError, JS_ThrowInternalError, JS_ThrowReferenceError @@ -745,7 +752,7 @@ proc newJSProcBody(gen: var JSFuncGenerator, isva: bool): NimNode = return JS_ThrowTypeError(ctx, "At least %d arguments required, " & "but only %d passed", `ma`, argc) ) - if gen.thisname.isSome: + if gen.thisname.isSome and not gen.isstatic: let tn = ident(gen.thisname.get) let ev = gen.errval result.add(quote do: @@ -811,8 +818,8 @@ func getActualMinArgs(gen: var JSFuncGenerator): int = return ma proc setupGenerator(fun: NimNode, t: BoundFunctionType, - thisname = some("this"), jsname: string = "", unforgeable = false): - JSFuncGenerator = + thisname = some("this"), jsname: string = "", unforgeable = false, + isstatic = false, thisType = ""): JSFuncGenerator = let jsFunCallList = newStmtList() let funcParams = getParams(fun) var gen = JSFuncGenerator( @@ -828,11 +835,16 @@ proc setupGenerator(fun: NimNode, t: BoundFunctionType, jsFunCallList: jsFunCallList, jsFunCallLists: @[jsFunCallList], jsFunCall: newCall(fun[0]), - unforgeable: unforgeable + unforgeable: unforgeable, + isstatic: isstatic ) gen.addJSContext() gen.actualMinArgs = gen.getActualMinArgs() # must come after passctx is set - gen.addThisName(thisname) + if thisType == "": + gen.addThisName(thisname) + else: + gen.thisType = thisType + gen.newName = ident($gen.t & "_" & gen.funcName) return gen proc makeJSCallAndRet(gen: var JSFuncGenerator, okstmt, errstmt: NimNode) = @@ -1016,8 +1028,10 @@ template jsfset*(fun: typed) = template jsfset*(jsname: static string, fun: typed) = jsfsetn(jsname, fun) -macro jsfuncn*(jsname: static string, uf: static bool, fun: typed) = - var gen = setupGenerator(fun, FUNCTION, jsname = jsname, unforgeable = uf) +macro jsfuncn*(jsname: static string, uf: static bool, + staticname: static string, fun: typed) = + var gen = setupGenerator(fun, FUNCTION, jsname = jsname, unforgeable = uf, + isstatic = staticname != "", thisType = staticname) if gen.minArgs == 0: error("Zero-parameter functions are not supported. (Maybe pass Window or Client?)") gen.addFixParam("this") @@ -1034,16 +1048,19 @@ macro jsfuncn*(jsname: static string, uf: static bool, fun: typed) = return newStmtList(fun, jsProc) template jsfunc*(fun: typed) = - jsfuncn("", false, fun) + jsfuncn("", false, "", fun) template jsuffunc*(fun: typed) = - jsfuncn("", true, fun) + jsfuncn("", true, "", fun) template jsfunc*(jsname: static string, fun: typed) = - jsfuncn(jsname, false, fun) + jsfuncn(jsname, false, "", fun) template jsuffunc*(jsname: static string, fun: typed) = - jsfuncn(jsname, true, fun) + jsfuncn(jsname, true, "", fun) + +template jsstfunc*(name: static string, fun: typed) = + jsfuncn("", false, name, fun) macro jsfin*(fun: typed) = var gen = setupGenerator(fun, FINALIZER, thisname = some("fin")) @@ -1201,6 +1218,7 @@ type RegistryInfo = object dfin: NimNode # CheckDestroy finalizer ident classDef: NimNode # ClassDef ident tabUnforgeable: NimNode # array of unforgeable function table + tabStatic: NimNode # array of static function table func tname(info: RegistryInfo): string = return info.t.strVal @@ -1220,6 +1238,7 @@ proc newRegistryInfo(t: NimNode, name: string): RegistryInfo = classDef: ident("classDef"), tabList: newNimNode(nnkBracket), tabUnforgeable: newNimNode(nnkBracket), + tabStatic: newNimNode(nnkBracket), finName: newNilLit(), finFun: newNilLit(), propGetFun: newNilLit(), @@ -1300,12 +1319,15 @@ proc bindFunctions(stmts: NimNode, info: var RegistryInfo) = case fun.t of FUNCTION: f0 = fun.name - if not fun.unforgeable: - info.tabList.add(quote do: - JS_CFUNC_DEF(`f0`, 0, cast[JSCFunction](`f1`))) - else: + if fun.unforgeable: info.tabUnforgeable.add(quote do: JS_CFUNC_DEF_NOCONF(`f0`, 0, cast[JSCFunction](`f1`))) + elif fun.isstatic: + info.tabStatic.add(quote do: + JS_CFUNC_DEF(`f0`, 0, cast[JSCFunction](`f1`))) + else: + info.tabList.add(quote do: + JS_CFUNC_DEF(`f0`, 0, cast[JSCFunction](`f1`))) of CONSTRUCTOR: info.ctorImpl = js_funcs[$f0].res if info.ctorFun != nil: @@ -1493,10 +1515,11 @@ macro registerType*(ctx: typed, t: typed, parent: JSClassID = 0, let classDef = info.classDef let tname = info.tname let unforgeable = info.tabUnforgeable + let staticfuns = info.tabStatic endstmts.add(quote do: `ctx`.newJSClass(`classDef`, `tname`, getTypePtr(`t`), `sctr`, `tabList`, `parent`, `asglobal`, `nointerface`, `finName`, `namespace`, `errid`, - `unforgeable`) + `unforgeable`, `staticfuns`) ) stmts.add(newBlockStmt(endstmts)) return stmts diff --git a/src/types/url.nim b/src/types/url.nim index 456dd16d..10100ee1 100644 --- a/src/types/url.nim +++ b/src/types/url.nim @@ -956,8 +956,7 @@ proc set*(params: URLSearchParams, name: string, value: string) {.jsfunc.} = first = false params.list[i][1] = value -proc newURL*(s: string, base: Option[string] = none(string)): - JSResult[URL] {.jsctor.} = +proc parseAPIURL(s: string, base: Option[string]): JSResult[URL] = let baseURL = if base.isSome: let x = parseURL(base.get) if x.isNone: @@ -968,11 +967,16 @@ proc newURL*(s: string, base: Option[string] = none(string)): let url = parseURL(s, baseURL) if url.isNone: return err(newTypeError(s & " is not a valid URL")) - url.get.searchParams = newURLSearchParams() - url.get.searchParams.url = url - url.get.searchParams.initURLSearchParams(url.get.query.get("")) return ok(url.get) +proc newURL*(s: string, base: Option[string] = none(string)): + JSResult[URL] {.jsctor.} = + let url = ?parseAPIURL(s, base) + url.searchParams = newURLSearchParams() + url.searchParams.url = some(url) + url.searchParams.initURLSearchParams(url.query.get("")) + return ok(url) + proc origin0*(url: URL): Origin = case url.scheme of "blob": @@ -1097,6 +1101,9 @@ proc setHash*(url: URL, s: string) {.jsfset: "hash".} = url.fragment = some("") discard basicParseURL(s, url = url, stateOverride = some(FRAGMENT_STATE)) +proc canParse(url: string, base: Option[string]): bool {.jsstfunc: "URL".} = + return parseAPIURL(url, base).isSome + proc addURLModule*(ctx: JSContext) = ctx.registerType(URL) ctx.registerType(URLSearchParams) |