From 1e55d920092c9ee00c59f7bd5abe37ff471b4306 Mon Sep 17 00:00:00 2001 From: lcrees Date: Fri, 12 Jan 2018 13:30:03 -0700 Subject: [PATCH 1/8] Add default argument to 'tables.getOrDefault' --- lib/pure/collections/tables.nim | 93 ++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 13 deletions(-) diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 777beabc39..94f16c6e3a 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -158,6 +158,12 @@ template getOrDefaultImpl(t, key): untyped = var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val +template getOrDefaultImpl(t, key, default: untyped): untyped = + mixin rawGet + var hc: Hash + var index = rawGet(t, key, hc) + result = if index >= 0: t.data[index].val else: default + proc `[]`*[A, B](t: Table[A, B], key: A): B {.deprecatedGet.} = ## retrieves the value at ``t[key]``. If `key` is not in `t`, the ## ``KeyError`` exception is raised. One can check with ``hasKey`` whether @@ -175,10 +181,18 @@ proc mget*[A, B](t: var Table[A, B], key: A): var B {.deprecated.} = ## instead. get(t, key) -proc getOrDefault*[A, B](t: Table[A, B], key: A): B = getOrDefaultImpl(t, key) +proc getOrDefault*[A, B](t: Table[A, B], key: A): B = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, the + ## default initialization value for type `B` is returned (e.g. 0 for any + ## integer type). + getOrDefaultImpl(t, key) -template withValue*[A, B](t: var Table[A, B], key: A, - value, body: untyped) = +proc getOrDefault*[A, B](t: Table[A, B], key: A, default: B): B = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, `default` + ## is returned. + getOrDefaultImpl(t, key, default) + +template withValue*[A, B](t: var Table[A, B], key: A, value, body: untyped) = ## retrieves the value at ``t[key]``. ## `value` can be modified in the scope of the ``withValue`` call. ## @@ -325,8 +339,7 @@ proc initTable*[A, B](initialSize=64): Table[A, B] = result.counter = 0 newSeq(result.data, initialSize) -proc toTable*[A, B](pairs: openArray[(A, - B)]): Table[A, B] = +proc toTable*[A, B](pairs: openArray[(A, B)]): Table[A, B] = ## creates a new hash table that contains the given `pairs`. result = initTable[A, B](rightSize(pairs.len)) for key, val in items(pairs): result[key] = val @@ -410,7 +423,16 @@ proc mget*[A, B](t: TableRef[A, B], key: A): var B {.deprecated.} = ## Use ```[]``` instead. t[][key] -proc getOrDefault*[A, B](t: TableRef[A, B], key: A): B = getOrDefault(t[], key) +proc getOrDefault*[A, B](t: TableRef[A, B], key: A): B = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, the + ## default initialization value for type `B` is returned (e.g. 0 for any + ## integer type). + getOrDefault(t[], key) + +proc getOrDefault*[A, B](t: TableRef[A, B], key: A, default: B): B = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, `default` + ## is returned. + getOrDefault(t[], key, default) proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B = ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way @@ -562,8 +584,15 @@ proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B {.deprecated.} = get(t, key) proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, the + ## default initialization value for type `B` is returned (e.g. 0 for any + ## integer type). getOrDefaultImpl(t, key) +proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A, default: B): B = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, `default` + ## is returned. + getOrDefaultImpl(t, key, default) proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. @@ -630,8 +659,7 @@ proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] = result.last = -1 newSeq(result.data, initialSize) -proc toOrderedTable*[A, B](pairs: openArray[(A, - B)]): OrderedTable[A, B] = +proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] = ## creates a new ordered hash table that contains the given `pairs`. result = initOrderedTable[A, B](rightSize(pairs.len)) for key, val in items(pairs): result[key] = val @@ -657,8 +685,7 @@ proc `==`*[A, B](s, t: OrderedTable[A, B]): bool = hs = nxts return true -proc sort*[A, B](t: var OrderedTable[A, B], - cmp: proc (x,y: (A, B)): int) = +proc sort*[A, B](t: var OrderedTable[A, B], cmp: proc (x,y: (A, B)): int) = ## sorts `t` according to `cmp`. This modifies the internal list ## that kept the insertion order, so insertion order is lost after this ## call but key lookup and insertions remain possible after `sort` (in @@ -748,8 +775,16 @@ proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B {.deprecated.} = result = t[][key] proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, the + ## default initialization value for type `B` is returned (e.g. 0 for any + ## integer type). getOrDefault(t[], key) +proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A, default: B): B = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, `default` + ## is returned. + getOrDefault(t[], key, default) + proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B = ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way ## returning a value which can be modified. @@ -802,8 +837,7 @@ proc `==`*[A, B](s, t: OrderedTableRef[A, B]): bool = elif isNil(t): result = false else: result = s[] == t[] -proc sort*[A, B](t: OrderedTableRef[A, B], - cmp: proc (x,y: (A, B)): int) = +proc sort*[A, B](t: OrderedTableRef[A, B], cmp: proc (x,y: (A, B)): int) = ## sorts `t` according to `cmp`. This modifies the internal list ## that kept the insertion order, so insertion order is lost after this ## call but key lookup and insertions remain possible after `sort` (in @@ -916,9 +950,17 @@ proc mget*[A](t: var CountTable[A], key: A): var int {.deprecated.} = ctget(t, key) proc getOrDefault*[A](t: CountTable[A], key: A): int = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, 0 (the + ## default initialization value of `int`), is returned. var index = rawGet(t, key) if index >= 0: result = t.data[index].val +proc getOrDefault*[A](t: CountTable[A], key: A, default: int): int = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, the + ## integer value of `default` is returned. + var index = rawGet(t, key) + result = if index >= 0: t.data[index].val else: default + proc hasKey*[A](t: CountTable[A], key: A): bool = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 @@ -1073,8 +1115,15 @@ proc mget*[A](t: CountTableRef[A], key: A): var int {.deprecated.} = result = t[][key] proc getOrDefault*[A](t: CountTableRef[A], key: A): int = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, 0 (the + ## default initialization value of `int`), is returned. result = t[].getOrDefault(key) +proc getOrDefault*[A](t: CountTableRef[A], key: A, default: int): int = + ## retrieves the value at ``t[key]`` iff `key` is in `t`. Otherwise, the + ## integer value of `default` is returned. + result = t[].getOrDefault(key, default) + proc hasKey*[A](t: CountTableRef[A], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) @@ -1266,7 +1315,7 @@ when isMainModule: #lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here #lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode doAssert 0 == t.getOrDefault(testKey) - t.inc(testKey,3) + t.inc(testKey, 3) doAssert 3 == t.getOrDefault(testKey) block: @@ -1335,3 +1384,21 @@ when isMainModule: var t = initCountTable[int]() for v in items([0, 0, 5, 5, 5]): t.inc(v) doAssert t.smallest == (0, 2) + + block: + var tp: Table[string, string] = initTable[string, string]() + doAssert "test1" == tp.getOrDefault("test1", "test1") + tp["test2"] = "test2" + doAssert "test2" == tp.getOrDefault("test2", "test1") + var tr: TableRef[string, string] = newTable[string, string]() + doAssert "test1" == tr.getOrDefault("test1", "test1") + tr["test2"] = "test2" + doAssert "test2" == tr.getOrDefault("test2", "test1") + var op: OrderedTable[string, string] = initOrderedTable[string, string]() + doAssert "test1" == op.getOrDefault("test1", "test1") + op["test2"] = "test2" + doAssert "test2" == op.getOrDefault("test2", "test1") + var orf: OrderedTableRef[string, string] = newOrderedTable[string, string]() + doAssert "test1" == orf.getOrDefault("test1", "test1") + orf["test2"] = "test2" + doAssert "test2" == orf.getOrDefault("test2", "test1") From 23064bba3a711d3f6bddfb8568c0d1732acdffb2 Mon Sep 17 00:00:00 2001 From: Abhishek Date: Mon, 26 Mar 2018 00:48:39 -0700 Subject: [PATCH 2/8] fix small typo in the documentation (#7411) --- doc/manual/stmts.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt index 721b5cff81..14d272cee0 100644 --- a/doc/manual/stmts.txt +++ b/doc/manual/stmts.txt @@ -145,7 +145,7 @@ the variable has been initialized and does not rely on syntactic properties: x = a() else: x = a() - use x + # use x let statement @@ -296,7 +296,7 @@ empty ``discard`` statement should be used. For non ordinal types it is not possible to list every possible value and so these always require an ``else`` part. -As case statements perform compile-time exhaustiveness checks, the value in +As case statements perform compile-time exhaustiveness checks, the value in every ``of`` branch must be known at compile time. This fact is also exploited to generate more performant code. From 50229293ae5898acc2c30f9cb87b59e2fa0b236a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 27 Mar 2018 00:45:43 -0700 Subject: [PATCH 3/8] doc: fix path to $HOME/.config/nim.cfg to work on POSIX (not just unix but also osx) (#7421) --- doc/nimc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/nimc.rst b/doc/nimc.rst index e949df69c8..151510df26 100644 --- a/doc/nimc.rst +++ b/doc/nimc.rst @@ -115,7 +115,7 @@ The ``nim`` executable processes configuration files in the following directories (in this order; later files overwrite previous settings): 1) ``$nim/config/nim.cfg``, ``/etc/nim.cfg`` (UNIX) or ``%NIMROD%/config/nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option. -2) ``/home/$user/.config/nim.cfg`` (UNIX) or ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option. +2) ``$HOME/.config/nim.cfg`` (POSIX) or ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option. 3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option. 4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project file's path. This file can be skipped with the ``--skipProjCfg`` command line option. 5) A project can also have a project specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command line option. From 53088c05cb3e67f6d27f9639335a7d5e1057a42e Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Tue, 27 Mar 2018 19:23:08 +0300 Subject: [PATCH 4/8] Disable param filtering --- lib/pure/unittest.nim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index fbce087ffd..0034d0c60b 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -150,6 +150,7 @@ var checkpoints {.threadvar.}: seq[string] formatters {.threadvar.}: seq[OutputFormatter] testsFilters {.threadvar.}: HashSet[string] + disabledParamFiltering {.threadvar.}: bool when declared(stdout): abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR") @@ -379,7 +380,7 @@ proc ensureInitialized() = if formatters == nil: formatters = @[OutputFormatter(defaultConsoleFormatter())] - if not testsFilters.isValid: + if not disabledParamFiltering and not testsFilters.isValid: testsFilters.init() when declared(paramCount): # Read tests to run from the command line. @@ -701,3 +702,7 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped = errorTypes.add(exp[i]) result = getAst(expectBody(errorTypes, exp.lineinfo, body)) + +proc disableParamFiltering* = + ## disables filtering tests with the command line params + disabledParamFiltering = true From ace96bf83e711438d517bec33e5d83f27e352726 Mon Sep 17 00:00:00 2001 From: Graham Fawcett Date: Wed, 28 Mar 2018 19:09:16 -0400 Subject: [PATCH 5/8] net.connect (with timeout), raise error on connect failure Under Linux (probably POSIX), the current code tests for timeout, but does not test for connection failure. connectAsync() returns succesfully upon an EINPROGRESS result; but at this point, the connection state is still unknown. After selectWrite() is done, we need to test the socket for errors again. --- lib/pure/net.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pure/net.nim b/lib/pure/net.nim index af9eea51a7..2d1ca8a59d 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1664,6 +1664,9 @@ proc connect*(socket: Socket, address: string, port = Port(0), if selectWrite(s, timeout) != 1: raise newException(TimeoutError, "Call to 'connect' timed out.") else: + let res = getSockOptInt(socket.fd, SOL_SOCKET, SO_ERROR) + if res != 0: + raiseOSError(OSErrorCode(res)) when defineSsl and not defined(nimdoc): if socket.isSSL: socket.fd.setBlocking(true) From bcda71a8a7c05566d729cf83f051dbc51649f6d5 Mon Sep 17 00:00:00 2001 From: cooldome Date: Thu, 29 Mar 2018 08:19:03 +0100 Subject: [PATCH 6/8] fixes #7414 (#7434) --- compiler/ccgstmts.nim | 40 +++++++++++++++++------------------- compiler/cgendata.nim | 9 ++++---- tests/exception/tfinally.nim | 22 +++++++++++++++++++- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 8a54708eee..f6c4204e87 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -37,6 +37,10 @@ proc isAssignedImmediately(n: PNode): bool {.inline.} = return false result = true +proc inExceptBlockLen(p: BProc): int = + for x in p.nestedTryStmts: + if x.inExcept: result.inc + proc genVarTuple(p: BProc, n: PNode) = var tup, field: TLoc if n.kind != nkVarTuple: internalError(n.info, "genVarTuple") @@ -96,7 +100,7 @@ proc startBlock(p: BProc, start: FormatStr = "{$n", setLen(p.blocks, result + 1) p.blocks[result].id = p.labels p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16 - p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16 + p.blocks[result].nestedExceptStmts = p.inExceptBlockLen.int16 proc assignLabel(b: var TBlock): Rope {.inline.} = b.label = "LA" & b.id.rope @@ -344,26 +348,22 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = # Called by return and break stmts. # Deals with issues faced when jumping out of try/except/finally stmts, - var stack: seq[PNode] - newSeq(stack, 0) + var stack = newSeq[tuple[n: PNode, inExcept: bool]](0) - var alreadyPoppedCnt = p.inExceptBlock for i in countup(1, howManyTrys): + let tryStmt = p.nestedTryStmts.pop if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions: # Pop safe points generated by try - if alreadyPoppedCnt > 0: - dec alreadyPoppedCnt - else: + if not tryStmt.inExcept: linefmt(p, cpsStmts, "#popSafePoint();$n") # Pop this try-stmt of the list of nested trys # so we don't infinite recurse on it in the next step. - var tryStmt = p.nestedTryStmts.pop stack.add(tryStmt) # Find finally-stmt for this try-stmt # and generate a copy of its sons - var finallyStmt = lastSon(tryStmt) + var finallyStmt = lastSon(tryStmt.n) if finallyStmt.kind == nkFinally: genStmts(p, finallyStmt.sons[0]) @@ -384,7 +384,7 @@ proc genReturnStmt(p: BProc, t: PNode) = if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0]) blockLeaveActions(p, howManyTrys = p.nestedTryStmts.len, - howManyExcepts = p.inExceptBlock) + howManyExcepts = p.inExceptBlockLen) if (p.finallySafePoints.len > 0): # If we're in a finally block, and we came here by exception # consume it before we return. @@ -567,15 +567,15 @@ proc genBreakStmt(p: BProc, t: PNode) = let label = assignLabel(p.blocks[idx]) blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts, - p.inExceptBlock - p.blocks[idx].nestedExceptStmts) + p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts) genLineDir(p, t) lineF(p, cpsStmts, "goto $1;$n", [label]) proc genRaiseStmt(p: BProc, t: PNode) = - if p.inExceptBlock > 0 and p.inExceptBlock == p.nestedTryStmts.len: + if p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept: # if the current try stmt have a finally block, # we must execute it before reraising - var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon + var finallyBlock = p.nestedTryStmts[^1].n[^1] if finallyBlock.kind == nkFinally: genSimpleBlock(p, finallyBlock.sons[0]) if t.sons[0].kind != nkEmpty: @@ -812,14 +812,14 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = let end_label = getLabel(p) discard cgsym(p.module, "Exception") - add(p.nestedTryStmts, t) + add(p.nestedTryStmts, (t, false)) startBlock(p, "try {$n") expr(p, t[0], d) endBlock(p) var catchAllPresent = false - inc p.inExceptBlock + p.nestedTryStmts[^1].inExcept = true for i in 1.. Date: Thu, 29 Mar 2018 11:57:53 +0100 Subject: [PATCH 7/8] Fixes #7433. --- lib/pure/json.nim | 10 ++++++++++ tests/stdlib/tjsonmacro.nim | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 2b58d154e4..912cd68379 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -964,6 +964,16 @@ proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode = return nil result = result.fields.getOrDefault(key) +proc `{}`*(node: JsonNode, index: varargs[int]): JsonNode = + ## Traverses the node and gets the given value. If any of the + ## indexes do not exist, returns ``nil``. Also returns ``nil`` if one of the + ## intermediate data structures is not an array. + result = node + for i in index: + if isNil(result) or result.kind != JArray or i >= node.len: + return nil + result = result.elems[i] + proc getOrDefault*(node: JsonNode, key: string): JsonNode = ## Gets a field from a `node`. If `node` is nil or not an object or ## value at `key` does not exist, returns nil diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim index a69b034264..e8740c591e 100644 --- a/tests/stdlib/tjsonmacro.nim +++ b/tests/stdlib/tjsonmacro.nim @@ -315,6 +315,21 @@ when isMainModule: doAssert noYearDeser.year.isNone doAssert noYearDeser.engine.name == "V8" + # Issue #7433 + type + Obj2 = object + n1: int + n2: Option[string] + n3: bool + + var j = %*[ { "n1": 4, "n2": "ABC", "n3": true }, + { "n1": 1, "n3": false }, + { "n1": 1, "n2": "XYZ", "n3": false } ] + + let jDeser = j.to(seq[Obj2]) + doAssert jDeser[0].n2.get() == "ABC" + doAssert jDeser[1].n2.isNone() + # Table[T, Y] support. block: type From 577025c3190ad17750900b2014f5e0996191bd7f Mon Sep 17 00:00:00 2001 From: treeform Date: Thu, 29 Mar 2018 05:31:19 -0700 Subject: [PATCH 8/8] Add some missing things to dom.nim Add window.performance, window.performance.now(), window.devicePixelRatio, window.scrollX and Y, style.overflowX and Y, node.getBoundingRect. --- lib/js/dom.nim | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 55692d47dd..cd76097290 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -45,6 +45,7 @@ type location*: Location closed*: bool defaultStatus*: cstring + devicePixelRatio*: float innerHeight*, innerWidth*: int locationbar*: ref TLocationBar menubar*: ref TMenuBar @@ -53,11 +54,14 @@ type pageXOffset*, pageYOffset*: int personalbar*: ref TPersonalBar scrollbars*: ref TScrollBars + scrollX*: float + scrollY*: float statusbar*: ref TStatusBar status*: cstring toolbar*: ref TToolBar frames*: seq[TFrame] screen*: Screen + performance*: Performance Frame* = ref FrameObj FrameObj {.importc.} = object of WindowObj @@ -253,6 +257,8 @@ type minHeight*: cstring minWidth*: cstring overflow*: cstring + overflowX*: cstring + overflowY*: cstring padding*: cstring paddingBottom*: cstring paddingLeft*: cstring @@ -400,6 +406,40 @@ type once*: bool passive*: bool + BoundingRect* {.importc.} = ref object + top*, bottom*, left*, right*, x*, y*, width*, height*: float + + PerformanceMemory* {.importc.} = ref object + jsHeapSizeLimit*: float + totalJSHeapSize*: float + usedJSHeapSize*: float + + PerformanceTiming* {.importc.} = ref object + connectStart*: float + domComplete*: float + domContentLoadedEventEnd*: float + domContentLoadedEventStart*: float + domInteractive*: float + domLoading*: float + domainLookupEnd*: float + domainLookupStart*: float + fetchStart*: float + loadEventEnd*: float + loadEventStart*: float + navigationStart*: float + redirectEnd*: float + redirectStart*: float + requestStart*: float + responseEnd*: float + responseStart*: float + secureConnectionStart*: float + unloadEventEnd*: float + unloadEventStart*: float + + Performance* {.importc.} = ref object + memory*: PerformanceMemory + timing*: PerformanceTiming + {.push importcpp.} # EventTarget "methods" @@ -451,6 +491,7 @@ proc cloneNode*(n: Node, copyContent: bool): Node proc deleteData*(n: Node, start, len: int) proc getAttribute*(n: Node, attr: cstring): cstring proc getAttributeNode*(n: Node, attr: cstring): Node +proc getBoundingClientRect*(e: Node): BoundingRect proc hasChildNodes*(n: Node): bool proc insertBefore*(n, newNode, before: Node) proc insertData*(n: Node, position: int, data: cstring) @@ -530,6 +571,9 @@ proc preventDefault*(ev: Event) proc identifiedTouch*(list: TouchList): Touch proc item*(list: TouchList, i: int): Touch +# Performance "methods" +proc now*(p: Performance): float + {.pop.} var