Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Araq 2018-03-30 02:32:29 +02:00
commit a9691aeef5
11 changed files with 205 additions and 44 deletions

View file

@ -37,6 +37,10 @@ proc isAssignedImmediately(n: PNode): bool {.inline.} =
return false return false
result = true result = true
proc inExceptBlockLen(p: BProc): int =
for x in p.nestedTryStmts:
if x.inExcept: result.inc
proc genVarTuple(p: BProc, n: PNode) = proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc var tup, field: TLoc
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple") if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
@ -96,7 +100,7 @@ proc startBlock(p: BProc, start: FormatStr = "{$n",
setLen(p.blocks, result + 1) setLen(p.blocks, result + 1)
p.blocks[result].id = p.labels p.blocks[result].id = p.labels
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16 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.} = proc assignLabel(b: var TBlock): Rope {.inline.} =
b.label = "LA" & b.id.rope b.label = "LA" & b.id.rope
@ -344,26 +348,22 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
# Called by return and break stmts. # Called by return and break stmts.
# Deals with issues faced when jumping out of try/except/finally stmts, # Deals with issues faced when jumping out of try/except/finally stmts,
var stack: seq[PNode] var stack = newSeq[tuple[n: PNode, inExcept: bool]](0)
newSeq(stack, 0)
var alreadyPoppedCnt = p.inExceptBlock
for i in countup(1, howManyTrys): for i in countup(1, howManyTrys):
let tryStmt = p.nestedTryStmts.pop
if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions: if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
# Pop safe points generated by try # Pop safe points generated by try
if alreadyPoppedCnt > 0: if not tryStmt.inExcept:
dec alreadyPoppedCnt
else:
linefmt(p, cpsStmts, "#popSafePoint();$n") linefmt(p, cpsStmts, "#popSafePoint();$n")
# Pop this try-stmt of the list of nested trys # Pop this try-stmt of the list of nested trys
# so we don't infinite recurse on it in the next step. # so we don't infinite recurse on it in the next step.
var tryStmt = p.nestedTryStmts.pop
stack.add(tryStmt) stack.add(tryStmt)
# Find finally-stmt for this try-stmt # Find finally-stmt for this try-stmt
# and generate a copy of its sons # and generate a copy of its sons
var finallyStmt = lastSon(tryStmt) var finallyStmt = lastSon(tryStmt.n)
if finallyStmt.kind == nkFinally: if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0]) 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]) if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
blockLeaveActions(p, blockLeaveActions(p,
howManyTrys = p.nestedTryStmts.len, howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlock) howManyExcepts = p.inExceptBlockLen)
if (p.finallySafePoints.len > 0): if (p.finallySafePoints.len > 0):
# If we're in a finally block, and we came here by exception # If we're in a finally block, and we came here by exception
# consume it before we return. # consume it before we return.
@ -567,15 +567,15 @@ proc genBreakStmt(p: BProc, t: PNode) =
let label = assignLabel(p.blocks[idx]) let label = assignLabel(p.blocks[idx])
blockLeaveActions(p, blockLeaveActions(p,
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
p.inExceptBlock - p.blocks[idx].nestedExceptStmts) p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts)
genLineDir(p, t) genLineDir(p, t)
lineF(p, cpsStmts, "goto $1;$n", [label]) lineF(p, cpsStmts, "goto $1;$n", [label])
proc genRaiseStmt(p: BProc, t: PNode) = 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, # if the current try stmt have a finally block,
# we must execute it before reraising # 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: if finallyBlock.kind == nkFinally:
genSimpleBlock(p, finallyBlock.sons[0]) genSimpleBlock(p, finallyBlock.sons[0])
if t.sons[0].kind != nkEmpty: if t.sons[0].kind != nkEmpty:
@ -812,14 +812,14 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
let end_label = getLabel(p) let end_label = getLabel(p)
discard cgsym(p.module, "Exception") discard cgsym(p.module, "Exception")
add(p.nestedTryStmts, t) add(p.nestedTryStmts, (t, false))
startBlock(p, "try {$n") startBlock(p, "try {$n")
expr(p, t[0], d) expr(p, t[0], d)
endBlock(p) endBlock(p)
var catchAllPresent = false var catchAllPresent = false
inc p.inExceptBlock p.nestedTryStmts[^1].inExcept = true
for i in 1..<t.len: for i in 1..<t.len:
if t[i].kind != nkExceptBranch: break if t[i].kind != nkExceptBranch: break
@ -839,6 +839,8 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type genExceptBranchBody(t[i][^1]) # exception handler body will duplicated for every type
endBlock(p) endBlock(p)
discard pop(p.nestedTryStmts)
if not catchAllPresent and t[^1].kind == nkFinally: if not catchAllPresent and t[^1].kind == nkFinally:
# finally requires catch all presence # finally requires catch all presence
startBlock(p, "catch (...) {$n") startBlock(p, "catch (...) {$n")
@ -846,9 +848,6 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
line(p, cpsStmts, ~"throw;$n") line(p, cpsStmts, ~"throw;$n")
endBlock(p) endBlock(p)
dec p.inExceptBlock
discard pop(p.nestedTryStmts)
if t[^1].kind == nkFinally: if t[^1].kind == nkFinally:
genSimpleBlock(p, t[^1][0]) genSimpleBlock(p, t[^1][0])
@ -902,7 +901,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint) linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
startBlock(p, "if ($1.status == 0) {$n", [safePoint]) startBlock(p, "if ($1.status == 0) {$n", [safePoint])
var length = sonsLen(t) var length = sonsLen(t)
add(p.nestedTryStmts, t) add(p.nestedTryStmts, (t, false))
expr(p, t.sons[0], d) expr(p, t.sons[0], d)
linefmt(p, cpsStmts, "#popSafePoint();$n") linefmt(p, cpsStmts, "#popSafePoint();$n")
endBlock(p) endBlock(p)
@ -910,7 +909,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "#popSafePoint();$n") linefmt(p, cpsStmts, "#popSafePoint();$n")
if optStackTrace in p.options: if optStackTrace in p.options:
linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n")
inc p.inExceptBlock p.nestedTryStmts[^1].inExcept = true
var i = 1 var i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch): while (i < length) and (t.sons[i].kind == nkExceptBranch):
# bug #4230: avoid false sharing between branches: # bug #4230: avoid false sharing between branches:
@ -941,7 +940,6 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "#popCurrentException();$n") linefmt(p, cpsStmts, "#popCurrentException();$n")
endBlock(p) endBlock(p)
inc(i) inc(i)
dec p.inExceptBlock
discard pop(p.nestedTryStmts) discard pop(p.nestedTryStmts)
endBlock(p) # end of else block endBlock(p) # end of else block
if i < length and t.sons[i].kind == nkFinally: if i < length and t.sons[i].kind == nkFinally:

View file

@ -70,11 +70,10 @@ type
threadVarAccessed*: bool # true if the proc already accessed some threadvar threadVarAccessed*: bool # true if the proc already accessed some threadvar
lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
currLineInfo*: TLineInfo # AST codegen will make this superfluous currLineInfo*: TLineInfo # AST codegen will make this superfluous
nestedTryStmts*: seq[PNode] # in how many nested try statements we are nestedTryStmts*: seq[tuple[n: PNode, inExcept: bool]]
# (the vars must be volatile then) # in how many nested try statements we are
inExceptBlock*: int # are we currently inside an except block? # (the vars must be volatile then)
# leaving such scopes by raise or by return must # bool is true when are in the except part of a try block
# execute any applicable finally blocks
finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
# using return in finally statements # using return in finally statements
labels*: Natural # for generating unique labels in the C proc labels*: Natural # for generating unique labels in the C proc

View file

@ -145,7 +145,7 @@ the variable has been initialized and does not rely on syntactic properties:
x = a() x = a()
else: else:
x = a() x = a()
use x # use x
let statement 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 For non ordinal types it is not possible to list every possible value and so
these always require an ``else`` part. 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 every ``of`` branch must be known at compile time. This fact is also exploited
to generate more performant code. to generate more performant code.

View file

@ -115,7 +115,7 @@ The ``nim`` executable processes configuration files in the following
directories (in this order; later files overwrite previous settings): 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. 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. 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. 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. 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.

View file

@ -45,6 +45,7 @@ type
location*: Location location*: Location
closed*: bool closed*: bool
defaultStatus*: cstring defaultStatus*: cstring
devicePixelRatio*: float
innerHeight*, innerWidth*: int innerHeight*, innerWidth*: int
locationbar*: ref TLocationBar locationbar*: ref TLocationBar
menubar*: ref TMenuBar menubar*: ref TMenuBar
@ -53,11 +54,14 @@ type
pageXOffset*, pageYOffset*: int pageXOffset*, pageYOffset*: int
personalbar*: ref TPersonalBar personalbar*: ref TPersonalBar
scrollbars*: ref TScrollBars scrollbars*: ref TScrollBars
scrollX*: float
scrollY*: float
statusbar*: ref TStatusBar statusbar*: ref TStatusBar
status*: cstring status*: cstring
toolbar*: ref TToolBar toolbar*: ref TToolBar
frames*: seq[TFrame] frames*: seq[TFrame]
screen*: Screen screen*: Screen
performance*: Performance
Frame* = ref FrameObj Frame* = ref FrameObj
FrameObj {.importc.} = object of WindowObj FrameObj {.importc.} = object of WindowObj
@ -253,6 +257,8 @@ type
minHeight*: cstring minHeight*: cstring
minWidth*: cstring minWidth*: cstring
overflow*: cstring overflow*: cstring
overflowX*: cstring
overflowY*: cstring
padding*: cstring padding*: cstring
paddingBottom*: cstring paddingBottom*: cstring
paddingLeft*: cstring paddingLeft*: cstring
@ -400,6 +406,40 @@ type
once*: bool once*: bool
passive*: 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.} {.push importcpp.}
# EventTarget "methods" # EventTarget "methods"
@ -451,6 +491,7 @@ proc cloneNode*(n: Node, copyContent: bool): Node
proc deleteData*(n: Node, start, len: int) proc deleteData*(n: Node, start, len: int)
proc getAttribute*(n: Node, attr: cstring): cstring proc getAttribute*(n: Node, attr: cstring): cstring
proc getAttributeNode*(n: Node, attr: cstring): Node proc getAttributeNode*(n: Node, attr: cstring): Node
proc getBoundingClientRect*(e: Node): BoundingRect
proc hasChildNodes*(n: Node): bool proc hasChildNodes*(n: Node): bool
proc insertBefore*(n, newNode, before: Node) proc insertBefore*(n, newNode, before: Node)
proc insertData*(n: Node, position: int, data: cstring) proc insertData*(n: Node, position: int, data: cstring)
@ -530,6 +571,9 @@ proc preventDefault*(ev: Event)
proc identifiedTouch*(list: TouchList): Touch proc identifiedTouch*(list: TouchList): Touch
proc item*(list: TouchList, i: int): Touch proc item*(list: TouchList, i: int): Touch
# Performance "methods"
proc now*(p: Performance): float
{.pop.} {.pop.}
var var

View file

@ -158,6 +158,12 @@ template getOrDefaultImpl(t, key): untyped =
var index = rawGet(t, key, hc) var index = rawGet(t, key, hc)
if index >= 0: result = t.data[index].val 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.} = proc `[]`*[A, B](t: Table[A, B], key: A): B {.deprecatedGet.} =
## retrieves the value at ``t[key]``. If `key` is not in `t`, the ## retrieves the value at ``t[key]``. If `key` is not in `t`, the
## ``KeyError`` exception is raised. One can check with ``hasKey`` whether ## ``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. ## instead.
get(t, key) 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, proc getOrDefault*[A, B](t: Table[A, B], key: A, default: B): B =
value, body: untyped) = ## 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]``. ## retrieves the value at ``t[key]``.
## `value` can be modified in the scope of the ``withValue`` call. ## `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 result.counter = 0
newSeq(result.data, initialSize) newSeq(result.data, initialSize)
proc toTable*[A, B](pairs: openArray[(A, proc toTable*[A, B](pairs: openArray[(A, B)]): Table[A, B] =
B)]): Table[A, B] =
## creates a new hash table that contains the given `pairs`. ## creates a new hash table that contains the given `pairs`.
result = initTable[A, B](rightSize(pairs.len)) result = initTable[A, B](rightSize(pairs.len))
for key, val in items(pairs): result[key] = val 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. ## Use ```[]``` instead.
t[][key] 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 = 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 ## 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) get(t, key)
proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B = 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) 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 = proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
## returns true iff `key` is in the table `t`. ## 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 result.last = -1
newSeq(result.data, initialSize) newSeq(result.data, initialSize)
proc toOrderedTable*[A, B](pairs: openArray[(A, proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] =
B)]): OrderedTable[A, B] =
## creates a new ordered hash table that contains the given `pairs`. ## creates a new ordered hash table that contains the given `pairs`.
result = initOrderedTable[A, B](rightSize(pairs.len)) result = initOrderedTable[A, B](rightSize(pairs.len))
for key, val in items(pairs): result[key] = val for key, val in items(pairs): result[key] = val
@ -657,8 +685,7 @@ proc `==`*[A, B](s, t: OrderedTable[A, B]): bool =
hs = nxts hs = nxts
return true return true
proc sort*[A, B](t: var OrderedTable[A, B], proc sort*[A, B](t: var OrderedTable[A, B], cmp: proc (x,y: (A, B)): int) =
cmp: proc (x,y: (A, B)): int) =
## sorts `t` according to `cmp`. This modifies the internal list ## sorts `t` according to `cmp`. This modifies the internal list
## that kept the insertion order, so insertion order is lost after this ## that kept the insertion order, so insertion order is lost after this
## call but key lookup and insertions remain possible after `sort` (in ## 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] result = t[][key]
proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B = 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) 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 = 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 ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
## returning a value which can be modified. ## 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 elif isNil(t): result = false
else: result = s[] == t[] else: result = s[] == t[]
proc sort*[A, B](t: OrderedTableRef[A, B], proc sort*[A, B](t: OrderedTableRef[A, B], cmp: proc (x,y: (A, B)): int) =
cmp: proc (x,y: (A, B)): int) =
## sorts `t` according to `cmp`. This modifies the internal list ## sorts `t` according to `cmp`. This modifies the internal list
## that kept the insertion order, so insertion order is lost after this ## that kept the insertion order, so insertion order is lost after this
## call but key lookup and insertions remain possible after `sort` (in ## 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) ctget(t, key)
proc getOrDefault*[A](t: CountTable[A], key: A): int = 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) var index = rawGet(t, key)
if index >= 0: result = t.data[index].val 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 = proc hasKey*[A](t: CountTable[A], key: A): bool =
## returns true iff `key` is in the table `t`. ## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0 result = rawGet(t, key) >= 0
@ -1073,8 +1115,15 @@ proc mget*[A](t: CountTableRef[A], key: A): var int {.deprecated.} =
result = t[][key] result = t[][key]
proc getOrDefault*[A](t: CountTableRef[A], key: A): int = 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) 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 = proc hasKey*[A](t: CountTableRef[A], key: A): bool =
## returns true iff `key` is in the table `t`. ## returns true iff `key` is in the table `t`.
result = t[].hasKey(key) result = t[].hasKey(key)
@ -1267,7 +1316,7 @@ when isMainModule:
#lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here #lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here
#lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode #lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode
doAssert 0 == t.getOrDefault(testKey) doAssert 0 == t.getOrDefault(testKey)
t.inc(testKey,3) t.inc(testKey, 3)
doAssert 3 == t.getOrDefault(testKey) doAssert 3 == t.getOrDefault(testKey)
block: block:
@ -1334,3 +1383,21 @@ when isMainModule:
block: # CountTable.smallest block: # CountTable.smallest
let t = toCountTable([0, 0, 5, 5, 5]) let t = toCountTable([0, 0, 5, 5, 5])
doAssert t.smallest == (0, 2) 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")

View file

@ -964,6 +964,16 @@ proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
return nil return nil
result = result.fields.getOrDefault(key) 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 = proc getOrDefault*(node: JsonNode, key: string): JsonNode =
## Gets a field from a `node`. If `node` is nil or not an object or ## Gets a field from a `node`. If `node` is nil or not an object or
## value at `key` does not exist, returns nil ## value at `key` does not exist, returns nil

View file

@ -1664,6 +1664,9 @@ proc connect*(socket: Socket, address: string, port = Port(0),
if selectWrite(s, timeout) != 1: if selectWrite(s, timeout) != 1:
raise newException(TimeoutError, "Call to 'connect' timed out.") raise newException(TimeoutError, "Call to 'connect' timed out.")
else: else:
let res = getSockOptInt(socket.fd, SOL_SOCKET, SO_ERROR)
if res != 0:
raiseOSError(OSErrorCode(res))
when defineSsl and not defined(nimdoc): when defineSsl and not defined(nimdoc):
if socket.isSSL: if socket.isSSL:
socket.fd.setBlocking(true) socket.fd.setBlocking(true)

View file

@ -150,6 +150,7 @@ var
checkpoints {.threadvar.}: seq[string] checkpoints {.threadvar.}: seq[string]
formatters {.threadvar.}: seq[OutputFormatter] formatters {.threadvar.}: seq[OutputFormatter]
testsFilters {.threadvar.}: HashSet[string] testsFilters {.threadvar.}: HashSet[string]
disabledParamFiltering {.threadvar.}: bool
when declared(stdout): when declared(stdout):
abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR") abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR")
@ -379,7 +380,7 @@ proc ensureInitialized() =
if formatters == nil: if formatters == nil:
formatters = @[OutputFormatter(defaultConsoleFormatter())] formatters = @[OutputFormatter(defaultConsoleFormatter())]
if not testsFilters.isValid: if not disabledParamFiltering and not testsFilters.isValid:
testsFilters.init() testsFilters.init()
when declared(paramCount): when declared(paramCount):
# Read tests to run from the command line. # Read tests to run from the command line.
@ -701,3 +702,7 @@ macro expect*(exceptions: varargs[typed], body: untyped): untyped =
errorTypes.add(exp[i]) errorTypes.add(exp[i])
result = getAst(expectBody(errorTypes, exp.lineinfo, body)) result = getAst(expectBody(errorTypes, exp.lineinfo, body))
proc disableParamFiltering* =
## disables filtering tests with the command line params
disabledParamFiltering = true

View file

@ -7,6 +7,11 @@ msg1
msg2 msg2
finally2 finally2
finally1 finally1
-----------
except1
finally1
except2
finally2
''' '''
""" """
# Test return in try statement: # Test return in try statement:
@ -39,4 +44,19 @@ proc nested_finally =
finally: finally:
echo "finally1" echo "finally1"
nested_finally() nested_finally()
echo "-----------"
#bug 7414
try:
try:
raise newException(Exception, "Hello")
except:
echo "except1"
raise
finally:
echo "finally1"
except:
echo "except2"
finally:
echo "finally2"

View file

@ -315,6 +315,21 @@ when isMainModule:
doAssert noYearDeser.year.isNone doAssert noYearDeser.year.isNone
doAssert noYearDeser.engine.name == "V8" 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. # Table[T, Y] support.
block: block:
type type