mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-02 03:43:41 +00:00
cgen: no [] on a PNode outside tree construction
Completes the vocabulary migration started with `BNode`: every child READ in
the cgen files now goes through an accessor that a `.bif` `Cursor` can also
serve, so flipping `newIcBackend` is a matter of implementing the vocabulary
rather than rewriting call sites.
* constant indices -> `firstSon` / `secondSon` / `lastSon` / `son(n, k)`,
including the `namePos`/`paramsPos`/`bodyPos`/... slot reads;
* indexed loops -> `sons` / `sonsFrom` / `sonsButLast` and the index-yielding
`isons` / `isonsButLast`. `for i in 0..<n.len: n[i]` is quadratic once
`BNode` is a `Cursor`, because reaching child `i` costs one `skip` per
preceding SUBTREE;
* `n.len == 0` / `> 0` on a node -> `hasSons`, which does not count.
`astdef` gains `sonsButLast(n, count)` and `isonsButLast` — the
`nkOfBranch`/`nkExceptBranch` shape, whose last child is the branch body, and
with `count = 2` the `nkVarTuple`/`nkIdentDefs` shape.
Three places needed more than a rename:
* the C++/goto/setjmp try generators re-subscripted `t[i]` up to ten times
per iteration of their `while i < t.len` walk; the branch node is now
hoisted once per step;
* `genParams` scans the arguments BACKWARDS to decide which need a temporary,
which a `Cursor` cannot do at all. It materializes them in one forward pass
and indexes that — the same order of work, since `needTmp` already
allocates per call;
* loops that stop at a computed position (`casePos`, `until`, `splitPoint`)
walk forward and break instead of counting up to the bound.
What is left is exactly what a `Cursor` backend will not do: writes that build
a fresh `nkProcDef`, and subscripts of a `PType`, `string`, `seq` or `Table`.
`bnode.nim` records the invariant and the `PType` trap — `ast.sons(t: PType)`
is a proc returning `var TTypeSeq`, not the iterator of the same name — which
the type checker enforces, since the `firstSon`/`secondSon`/`lastSon`/`son`
family exists for `PNode` only.
Pure refactor, verified as one: all 216 generated `.c` files byte-identical to
the parent commit; metamorphic IC 16/16; icSuite 19/19 fragments; categories
gc 78, arc 140, destructor 97, closure 23, iter 71, trmacros 6, cpp 50,
exception 47, casestmt 16 with one pre-existing environmental failure
(tests/cpp/tasync_cpp.nim: `cannot open file: jester`).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FMyRHByv7hhaQJ4Pa1bHbE
This commit is contained in:
@@ -977,6 +977,23 @@ iterator sonsFrom*(n: PNode; start: int): PNode =
|
||||
## over a case/try statement's selector or a call's callee.
|
||||
for i in start..<n.safeLen: yield n[i]
|
||||
|
||||
iterator sonsButLast*(n: PNode; count = 1): PNode =
|
||||
## `sons` without the last `count` children. Replaces `for i in 0..<n.len-1:
|
||||
## ... n[i] ...`, which is what an `nkOfBranch`/`nkExceptBranch` walk looks
|
||||
## like: the last child is the branch BODY, the ones before it are the labels
|
||||
## it matches. `count = 2` is the `nkVarTuple`/`nkIdentDefs` shape, whose last
|
||||
## two children are the type and the value. A `Cursor` can serve this with a
|
||||
## single pass and `count` nodes of lookahead; the indexed form has to re-walk
|
||||
## the children for every label.
|
||||
##
|
||||
## Use `isonsButLast` instead when the index is still needed.
|
||||
for i in 0 ..< n.safeLen - count: yield n[i]
|
||||
|
||||
iterator isonsButLast*(n: PNode; count = 1): tuple[i: int, n: PNode] =
|
||||
## Like `sonsButLast` but also yields the child index — for a tuple field
|
||||
## position, a parallel index into the tuple's `PType`, and so on.
|
||||
for i in 0 ..< n.safeLen - count: yield (i, n[i])
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = -1 # 2322968
|
||||
var gNodeId: int
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
## below one area at a time and the compiler keeps building throughout, because
|
||||
## on the `PNode` side the vocabulary is what `ast`/`astdef` already provide —
|
||||
## `kind`, `len`, `safeLen`, `sym`, `typ`, `info`, `firstSon`, `secondSon`,
|
||||
## `lastSon` and the `sons`/`isons`/`sonsFrom` iterators all exist. This module
|
||||
## deliberately does
|
||||
## NOT redefine them for `PNode`: an identical second overload would make every
|
||||
## call site ambiguous. It adds only what the AST lacks (`son`, `hasSons`), and
|
||||
## supplies the whole vocabulary on the `Cursor` side.
|
||||
## `lastSon` and the `sons`/`isons`/`sonsFrom`/`sonsButLast`/`isonsButLast`
|
||||
## iterators all exist. This module deliberately does NOT redefine them for
|
||||
## `PNode`: an identical second overload would make every call site ambiguous.
|
||||
## It adds only what the AST lacks (`son`, `hasSons`), and supplies the whole
|
||||
## vocabulary on the `Cursor` side.
|
||||
##
|
||||
## THE COST MODEL DIFFERS, and that is what the vocabulary is shaped around. A
|
||||
## `Cursor` is a copyable position in a token buffer, so a child is reached by
|
||||
@@ -32,14 +32,27 @@
|
||||
## whole subtree. Reading child `i` is therefore O(size of children 0..<i):
|
||||
##
|
||||
## * `firstSon` / `secondSon` / `son(n, k)` with small constant `k` — cheap, and
|
||||
## already how most structural access reads (344 of 777 indexed accesses in
|
||||
## the cgen files use a constant or a `*Pos` index).
|
||||
## * `for x in sons(n)` / `sonsFrom(n, k)` — one linear pass. ALWAYS migrate an
|
||||
## indexed loop to these: `for i in 0..<n.len: n[i]` is O(n^2) once `BNode` is
|
||||
## a `Cursor`, and ~196 such accesses remain.
|
||||
## * `lastSon(n)` — O(len). Fine once, a trap inside a loop; 28 `n[^1]` uses.
|
||||
## how nearly all structural access in the cgen files now reads.
|
||||
## * `for x in sons(n)` / `sonsFrom(n, k)` / `sonsButLast(n, k)`, and the
|
||||
## index-yielding `isons` / `isonsButLast` — one linear pass. ALWAYS use these
|
||||
## for a loop: `for i in 0..<n.len: n[i]` is O(n^2) once `BNode` is a `Cursor`.
|
||||
## A loop that stops at a computed position walks forward and breaks
|
||||
## (`for i, it in isons(n): if i >= casePos: break`) rather than counting up to
|
||||
## the bound.
|
||||
## * `lastSon(n)` — O(len). Fine once, a trap inside a loop.
|
||||
## * `len(n)` — O(len) on a `Cursor`, which has to count. Do not put it in a loop
|
||||
## condition; use `sons`/`sonsFrom`, or `hasSons` for an emptiness test.
|
||||
##
|
||||
## The cgen files hold to one invariant, which is what makes the eventual flip
|
||||
## mechanical: NO `[]` ON A `PNode` OUTSIDE OF TREE CONSTRUCTION. Every read is
|
||||
## `firstSon`/`secondSon`/`lastSon`/`son(n, k)` or one of the iterators; the
|
||||
## remaining subscripts are writes that build a fresh `nkProcDef`
|
||||
## (`theProc[namePos] = ...`), which a `Cursor` backend will not do at all, and
|
||||
## accesses to a `PType`, a `string`, a `seq` or a `Table`, none of which are
|
||||
## `BNode`s. `PType` is the trap to watch for: `ast.sons(t: PType)` is a `proc`
|
||||
## returning `var TTypeSeq`, NOT the iterator of the same name, so `t[i]` there
|
||||
## means something else entirely. The `firstSon`/`secondSon`/`lastSon`/`son`
|
||||
## family is defined for `PNode` only, so a mistaken base does not compile.
|
||||
|
||||
import ast, lineinfos
|
||||
|
||||
@@ -70,6 +83,9 @@ when defined(newIcBackend):
|
||||
proc info*(n: BNode): TLineInfo {.error: "BNode.info: not implemented for Cursor yet".} = discard
|
||||
iterator sons*(n: BNode): BNode {.error: "BNode.sons: not implemented for Cursor yet".} = discard
|
||||
iterator sonsFrom*(n: BNode; start: int): BNode {.error: "BNode.sonsFrom: not implemented for Cursor yet".} = discard
|
||||
iterator sonsButLast*(n: BNode; count = 1): BNode {.error: "BNode.sonsButLast: not implemented for Cursor yet (one pass with `count` nodes of lookahead)".} = discard
|
||||
iterator isons*(n: BNode; start = 0): tuple[i: int, n: BNode] {.error: "BNode.isons: not implemented for Cursor yet".} = discard
|
||||
iterator isonsButLast*(n: BNode; count = 1): tuple[i: int, n: BNode] {.error: "BNode.isonsButLast: not implemented for Cursor yet".} = discard
|
||||
else:
|
||||
type BNode* = PNode
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
|
||||
nkCheckedFieldExpr:
|
||||
n = n.firstSon
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
n = n[1]
|
||||
n = n.secondSon
|
||||
else:
|
||||
# cannot analyse the location; assume the worst
|
||||
return true
|
||||
@@ -184,7 +184,7 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} =
|
||||
of {nkAddr, nkHiddenAddr, nkHiddenDeref}:
|
||||
x = x.firstSon
|
||||
of nkHiddenStdConv:
|
||||
x = x[1]
|
||||
x = x.secondSon
|
||||
else:
|
||||
break
|
||||
if x.kind == nkSym and x.sym.kind == skParam:
|
||||
@@ -193,9 +193,9 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} =
|
||||
result = true
|
||||
|
||||
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
|
||||
var a = initLocExpr(p, q[1])
|
||||
var b = initLocExpr(p, q[2])
|
||||
var c = initLocExpr(p, q[3])
|
||||
var a = initLocExpr(p, q.secondSon)
|
||||
var b = initLocExpr(p, son(q, 2))
|
||||
var c = initLocExpr(p, son(q, 3))
|
||||
# bug #23321: In the function mapType, ptrs (tyPtr, tyVar, tyLent, tyRef)
|
||||
# are mapped into ctPtrToArray, the dereference of which is skipped
|
||||
# in the `genDeref`. We need to skip these ptrs here
|
||||
@@ -221,7 +221,7 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
|
||||
let lit = cIntLiteral(first)
|
||||
result = (cCast(ptrType(dest), cOp(Add, NimInt, ra, cOp(Sub, NimInt, rb, lit))), lengthExpr)
|
||||
of tyOpenArray, tyVarargs:
|
||||
let data = if reifiedOpenArray(q[1]): dotField(ra, "Field0") else: ra
|
||||
let data = if reifiedOpenArray(q.secondSon): dotField(ra, "Field0") else: ra
|
||||
result = (cCast(ptrType(dest), cOp(Add, NimInt, data, rb)), lengthExpr)
|
||||
of tyUncheckedArray, tyCstring:
|
||||
result = (cCast(ptrType(dest), cOp(Add, NimInt, ra, rb)), lengthExpr)
|
||||
@@ -258,23 +258,23 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
|
||||
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Builder) =
|
||||
var q = skipConv(n)
|
||||
var skipped = false
|
||||
while q.kind == nkStmtListExpr and q.len > 0:
|
||||
while q.kind == nkStmtListExpr and q.hasSons:
|
||||
skipped = true
|
||||
q = q.lastSon
|
||||
if getMagic(q) == mSlice:
|
||||
# magic: pass slice to openArray:
|
||||
if skipped:
|
||||
q = skipConv(n)
|
||||
while q.kind == nkStmtListExpr and q.len > 0:
|
||||
for i in 0..<q.len-1:
|
||||
genStmts(p, q[i])
|
||||
while q.kind == nkStmtListExpr and q.hasSons:
|
||||
for it in sonsButLast(q):
|
||||
genStmts(p, it)
|
||||
q = q.lastSon
|
||||
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ.elementType)
|
||||
result.add(x)
|
||||
result.addArgumentSeparator()
|
||||
result.add(y)
|
||||
else:
|
||||
var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
|
||||
var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n.secondSon else: n)
|
||||
case skipTypes(a.t, abstractVar+{tyStatic}).kind
|
||||
of tyOpenArray, tyVarargs:
|
||||
let ra = rdLoc(a)
|
||||
@@ -439,7 +439,7 @@ proc skipTrivialIndirections(n: PNode): PNode =
|
||||
of nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv:
|
||||
result = result.firstSon
|
||||
of nkHiddenStdConv, nkHiddenSubConv:
|
||||
result = result[1]
|
||||
result = result.secondSon
|
||||
else: break
|
||||
|
||||
proc getPotentialReads(n: PNode; result: var seq[PNode]) =
|
||||
@@ -453,29 +453,35 @@ proc getPotentialReads(n: PNode; result: var seq[PNode]) =
|
||||
proc genParams(p: BProc, ri: PNode, typ: PType; result: var Builder, argBuilder: var CallBuilder) =
|
||||
# We must generate temporaries in cases like #14396
|
||||
# to keep the strict Left-To-Right evaluation
|
||||
var needTmp = newSeq[bool](ri.len - 1)
|
||||
# The arguments are walked BACKWARDS below, which a `Cursor` cannot do and
|
||||
# which costs a re-walk per step even on a `PNode`. Materialize them in one
|
||||
# forward pass and index that; `needTmp` already allocates per call, so this
|
||||
# is the same order of work.
|
||||
var args: seq[PNode] = @[]
|
||||
for it in sonsFrom(ri, 1): args.add it
|
||||
var needTmp = newSeq[bool](args.len)
|
||||
var potentialWrites: seq[PNode] = @[]
|
||||
for i in countdown(ri.len - 1, 1):
|
||||
if ri[i].skipTrivialIndirections.kind == nkSym:
|
||||
needTmp[i - 1] = potentialAlias(ri[i], potentialWrites)
|
||||
for i in countdown(args.high, 0):
|
||||
if args[i].skipTrivialIndirections.kind == nkSym:
|
||||
needTmp[i] = potentialAlias(args[i], potentialWrites)
|
||||
else:
|
||||
#if not ri[i].typ.isCompileTimeOnly:
|
||||
#if not args[i].typ.isCompileTimeOnly:
|
||||
var potentialReads: seq[PNode] = @[]
|
||||
getPotentialReads(ri[i], potentialReads)
|
||||
getPotentialReads(args[i], potentialReads)
|
||||
for n in potentialReads:
|
||||
if not needTmp[i - 1]:
|
||||
needTmp[i - 1] = potentialAlias(n, potentialWrites)
|
||||
getPotentialWrites(ri[i], false, potentialWrites)
|
||||
if not needTmp[i]:
|
||||
needTmp[i] = potentialAlias(n, potentialWrites)
|
||||
getPotentialWrites(args[i], false, potentialWrites)
|
||||
when false:
|
||||
# this optimization is wrong, see bug #23748
|
||||
if ri[i].kind in {nkHiddenAddr, nkAddr}:
|
||||
if args[i].kind in {nkHiddenAddr, nkAddr}:
|
||||
# Optimization: don't use a temp, if we would only take the address anyway
|
||||
needTmp[i - 1] = false
|
||||
needTmp[i] = false
|
||||
|
||||
for i, it in isons(ri, 1):
|
||||
if i < typ.n.len:
|
||||
assert(typ.n[i].kind == nkSym)
|
||||
let paramType = typ.n[i]
|
||||
assert(son(typ.n, i).kind == nkSym)
|
||||
let paramType = son(typ.n, i)
|
||||
if not paramType.typ.isCompileTimeOnly:
|
||||
var arg = newBuilder("")
|
||||
genArg(p, it, paramType.sym, ri, arg, needTmp[i-1])
|
||||
@@ -611,22 +617,22 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder;
|
||||
if i < typ.n.len:
|
||||
# 'var T' is 'T&' in C++. This means we ignore the request of
|
||||
# any nkHiddenAddr when it's a 'var T'.
|
||||
let paramType = typ.n[i]
|
||||
let paramType = son(typ.n, i)
|
||||
assert(paramType.kind == nkSym)
|
||||
if paramType.typ.isCompileTimeOnly:
|
||||
discard
|
||||
elif paramType.typ.kind in {tyVar} and ri[i].kind == nkHiddenAddr:
|
||||
elif paramType.typ.kind in {tyVar} and son(ri, i).kind == nkHiddenAddr:
|
||||
result.addArgument(argBuilder):
|
||||
genArgNoParam(p, ri[i].firstSon, result)
|
||||
genArgNoParam(p, son(ri, i).firstSon, result)
|
||||
else:
|
||||
result.addArgument(argBuilder):
|
||||
genArgNoParam(p, ri[i], result) #, typ.n[i].sym)
|
||||
genArgNoParam(p, son(ri, i), result) #, son(typ.n, i).sym)
|
||||
else:
|
||||
if tfVarargs notin typ.flags:
|
||||
localError(p.config, ri.info, "wrong argument count")
|
||||
else:
|
||||
result.addArgument(argBuilder):
|
||||
genArgNoParam(p, ri[i], result)
|
||||
genArgNoParam(p, son(ri, i), result)
|
||||
|
||||
discard """
|
||||
Dot call syntax in C++
|
||||
@@ -688,10 +694,10 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder) =
|
||||
# However manual wrappers may also use 'ptr T'. In any case we support both
|
||||
# for convenience.
|
||||
internalAssert p.config, i < typ.n.len
|
||||
assert(typ.n[i].kind == nkSym)
|
||||
assert(son(typ.n, i).kind == nkSym)
|
||||
# if the parameter is lying (tyVar) and thus we required an additional deref,
|
||||
# skip the deref:
|
||||
var ri = ri[i]
|
||||
var ri = son(ri, i)
|
||||
while ri.kind == nkObjDownConv: ri = ri.firstSon
|
||||
let t = typ[i].skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
if t.kind in {tyVar}:
|
||||
@@ -715,7 +721,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder) =
|
||||
else:
|
||||
ri = skipAddrDeref(ri)
|
||||
if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri.firstSon
|
||||
genArgNoParam(p, ri, result) #, typ.n[i].sym)
|
||||
genArgNoParam(p, ri, result) #, son(typ.n, i).sym)
|
||||
result.add(".")
|
||||
|
||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Builder) =
|
||||
@@ -730,7 +736,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
|
||||
inc i
|
||||
of '#':
|
||||
if i+1 < pat.len and pat[i+1] in {'+', '@'}:
|
||||
let ri = ri[j]
|
||||
let ri = son(ri, j)
|
||||
if ri.kind in nkCallKinds:
|
||||
let typ = skipTypes(ri.firstSon.typ, abstractInst)
|
||||
if pat[i+1] == '+': genArgNoParam(p, ri.firstSon, result)
|
||||
@@ -738,7 +744,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
|
||||
if 1 < ri.len:
|
||||
var callBuilder: CallBuilder = default(CallBuilder)
|
||||
genOtherArg(p, ri, 1, typ, result, callBuilder)
|
||||
for k in j+1..<ri.len:
|
||||
for k, _ in isons(ri, j+1):
|
||||
var callBuilder: CallBuilder = default(CallBuilder)
|
||||
genOtherArg(p, ri, k, typ, result, callBuilder)
|
||||
result.add(")")
|
||||
@@ -749,7 +755,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
|
||||
genThisArg(p, ri, j, typ, result)
|
||||
inc i
|
||||
elif i+1 < pat.len and pat[i+1] == '[':
|
||||
var arg = ri[j].skipAddrDeref
|
||||
var arg = son(ri, j).skipAddrDeref
|
||||
while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg.firstSon
|
||||
genArgNoParam(p, arg, result)
|
||||
#result.add debugTree(arg, 0, 10)
|
||||
@@ -830,21 +836,21 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
pl.add(op.snippet)
|
||||
if ri.len > 1:
|
||||
pl.add(": ")
|
||||
genArg(p, ri[1], typ.n[1].sym, ri, pl)
|
||||
genArg(p, ri.secondSon, typ.n.secondSon.sym, ri, pl)
|
||||
start = 2
|
||||
else:
|
||||
if ri.len > 1:
|
||||
genArg(p, ri[1], typ.n[1].sym, ri, pl)
|
||||
genArg(p, ri.secondSon, typ.n.secondSon.sym, ri, pl)
|
||||
pl.add(" ")
|
||||
pl.add(op.snippet)
|
||||
if ri.len > 2:
|
||||
pl.add(": ")
|
||||
genArg(p, ri[2], typ.n[2].sym, ri, pl)
|
||||
genArg(p, son(ri, 2), son(typ.n, 2).sym, ri, pl)
|
||||
for i, it in isons(ri, start):
|
||||
if i >= typ.n.len:
|
||||
internalError(p.config, ri.info, "varargs for objective C method?")
|
||||
assert(typ.n[i].kind == nkSym)
|
||||
var param = typ.n[i].sym
|
||||
assert(son(typ.n, i).kind == nkSym)
|
||||
var param = son(typ.n, i).sym
|
||||
pl.add(" ")
|
||||
pl.add(param.name.s)
|
||||
pl.add(": ")
|
||||
@@ -902,7 +908,7 @@ proc isInactiveDestructorCall(p: BProc, e: PNode): bool =
|
||||
the 'let args = ...' statement. We exploit this to generate better
|
||||
code for 'return'. ]#
|
||||
result = e.len == 2 and e.firstSon.kind == nkSym and
|
||||
e.firstSon.sym.name.s == "=destroy" and notYetAlive(e[1].skipAddr)
|
||||
e.firstSon.sym.name.s == "=destroy" and notYetAlive(e.secondSon.skipAddr)
|
||||
|
||||
proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, ri):
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,8 +22,8 @@ proc specializeResetN(p: BProc, accessor: Rope, n: PNode;
|
||||
for it in sons(n):
|
||||
specializeResetN(p, accessor, it, typ)
|
||||
of nkRecCase:
|
||||
if (n[0].kind != nkSym): internalError(p.config, n.info, "specializeResetN")
|
||||
let disc = n[0].sym
|
||||
if (n.firstSon.kind != nkSym): internalError(p.config, n.info, "specializeResetN")
|
||||
let disc = n.firstSon.sym
|
||||
if disc.loc.snippet == "": fillObjectFields(p.module, typ)
|
||||
if disc.loc.t == nil:
|
||||
internalError(p.config, n.info, "specializeResetN()")
|
||||
|
||||
@@ -98,8 +98,8 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
|
||||
|
||||
# if we have a something that's been captured, use the lowering instead:
|
||||
for i in 0..<n.len-2:
|
||||
if n[i].kind != nkSym:
|
||||
for it in sonsButLast(n, 2):
|
||||
if it.kind != nkSym:
|
||||
genStmts(p, lowerTupleUnpacking(p.module.g.graph, n, p.module.idgen, p.prc))
|
||||
return
|
||||
|
||||
@@ -120,10 +120,9 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
initElifBranch(p.s(cpsStmts), hcrIf, hcrCond)
|
||||
|
||||
genLineDir(p, n)
|
||||
var tup = initLocExpr(p, n[^1])
|
||||
var tup = initLocExpr(p, n.lastSon)
|
||||
var t = tup.t.skipTypes(abstractInst)
|
||||
for i in 0..<n.len-2:
|
||||
let vn = n[i]
|
||||
for i, vn in isonsButLast(n, 2):
|
||||
let v = vn.sym
|
||||
if sfCompileTime in v.flags: continue
|
||||
backendEnsureMutable v
|
||||
@@ -133,7 +132,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
registerTraverseProc(p, v)
|
||||
else:
|
||||
assignLocalVar(p, vn)
|
||||
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
|
||||
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n.lastSon))
|
||||
var field = initLoc(locExpr, vn, tup.storage)
|
||||
let rtup = rdLoc(tup)
|
||||
let fieldName =
|
||||
@@ -278,9 +277,9 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||
howManyExcepts = p.inExceptBlockLen)
|
||||
p.s(cpsStmts).addGoto("BeforeRet_")
|
||||
var statesCounter = lastOrd(p.config, n.firstSon.typ)
|
||||
if n.len >= 2 and n[1].kind == nkIntLit:
|
||||
statesCounter = getInt(n[1])
|
||||
let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
|
||||
if n.len >= 2 and n.secondSon.kind == nkIntLit:
|
||||
statesCounter = getInt(n.secondSon)
|
||||
let prefix = if n.len == 3 and son(n, 2).kind == nkStrLit: son(n, 2).strVal.rope
|
||||
else: rope"STATE"
|
||||
for i in 0i64..toInt64(statesCounter):
|
||||
p.s(cpsStmts).addSingleSwitchCase(cIntValue(i)):
|
||||
@@ -291,7 +290,7 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
|
||||
d = initLoc(locExpr, n, OnUnknown)
|
||||
|
||||
if n.firstSon.kind == nkClosure:
|
||||
a = initLocExpr(p, n.firstSon[1])
|
||||
a = initLocExpr(p, n.firstSon.secondSon)
|
||||
let ra = a.rdLoc
|
||||
d.snippet = cOp(LessThan,
|
||||
subscript(
|
||||
@@ -478,15 +477,15 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
discard
|
||||
else:
|
||||
return
|
||||
genSingleVar(p, v, a.firstSon, a[2])
|
||||
genSingleVar(p, v, a.firstSon, son(a, 2))
|
||||
|
||||
proc genClosureVar(p: BProc, a: PNode) =
|
||||
var immediateAsgn = a[2].kind != nkEmpty
|
||||
var immediateAsgn = son(a, 2).kind != nkEmpty
|
||||
var v: TLoc = initLocExpr(p, a.firstSon)
|
||||
genLineDir(p, a)
|
||||
if immediateAsgn:
|
||||
loadInto(p, a.firstSon, a[2], v)
|
||||
elif sfNoInit notin a.firstSon[1].sym.flags:
|
||||
loadInto(p, a.firstSon, son(a, 2), v)
|
||||
elif sfNoInit notin a.firstSon.secondSon.sym.flags:
|
||||
constructLoc(p, v)
|
||||
|
||||
proc genVarStmt(p: BProc, n: PNode) =
|
||||
@@ -538,9 +537,9 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
if p.module.compileToCpp:
|
||||
# avoid "jump to label crosses initialization" error:
|
||||
p.s(cpsStmts).addScope():
|
||||
expr(p, it[1], d)
|
||||
expr(p, it.secondSon, d)
|
||||
else:
|
||||
expr(p, it[1], d)
|
||||
expr(p, it.secondSon, d)
|
||||
endSimpleBlock(p, scope)
|
||||
if n.len > 1:
|
||||
p.s(cpsStmts).addGoto(lend)
|
||||
@@ -578,11 +577,11 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) =
|
||||
var scope: ScopeBuilder
|
||||
startSimpleBlock(p, scope)
|
||||
let it = child
|
||||
for j in 0..<it.len-1:
|
||||
if it[j].kind == nkRange:
|
||||
for label in sonsButLast(it):
|
||||
if label.kind == nkRange:
|
||||
localError(p.config, it.info, "range notation not available for computed goto")
|
||||
return
|
||||
let val = getOrdValue(it[j])
|
||||
let val = getOrdValue(label)
|
||||
p.s(cpsStmts).addLabel("NIMSTATE_" & $val)
|
||||
genStmts(p, it.lastSon)
|
||||
endSimpleBlock(p, scope)
|
||||
@@ -592,9 +591,8 @@ iterator fieldValuePairs(n: PNode): tuple[memberSym, valueSym: PNode] =
|
||||
assert(n.kind in {nkLetSection, nkVarSection})
|
||||
for identDefs in n:
|
||||
if identDefs.kind == nkIdentDefs:
|
||||
let valueSym = identDefs[^1]
|
||||
for i in 0..<identDefs.len-2:
|
||||
let memberSym = identDefs[i]
|
||||
let valueSym = identDefs.lastSon
|
||||
for memberSym in sonsButLast(identDefs, 2):
|
||||
yield((memberSym: memberSym, valueSym: valueSym))
|
||||
|
||||
proc genComputedGoto(p: BProc; n: PNode) =
|
||||
@@ -637,10 +635,11 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
p.s(cpsStmts).addField(labelsInit, ""):
|
||||
p.s(cpsStmts).add(cLabelAddr("TMP" & $(id+i) & "_"))
|
||||
|
||||
for j in 0..<casePos:
|
||||
genStmts(p, n[j])
|
||||
for j, it in isons(n):
|
||||
if j >= casePos: break
|
||||
genStmts(p, it)
|
||||
|
||||
let caseStmt = n[casePos]
|
||||
let caseStmt = son(n, casePos)
|
||||
var a: TLoc = initLocExpr(p, caseStmt.firstSon)
|
||||
let ra = a.rdLoc
|
||||
# first goto:
|
||||
@@ -650,43 +649,43 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
var scope: ScopeBuilder
|
||||
startSimpleBlock(p, scope)
|
||||
let it = child
|
||||
for j in 0..<it.len-1:
|
||||
if it[j].kind == nkRange:
|
||||
for label in sonsButLast(it):
|
||||
if label.kind == nkRange:
|
||||
localError(p.config, it.info, "range notation not available for computed goto")
|
||||
return
|
||||
|
||||
let val = getOrdValue(it[j])
|
||||
let val = getOrdValue(label)
|
||||
let lit = cIntLiteral(toInt64(val)+id+1)
|
||||
p.s(cpsStmts).addLabel("TMP" & lit & "_")
|
||||
|
||||
genStmts(p, it.lastSon)
|
||||
|
||||
for j in casePos+1..<n.len:
|
||||
genStmts(p, n[j])
|
||||
for after in sonsFrom(n, casePos+1):
|
||||
genStmts(p, after)
|
||||
|
||||
for j in 0..<casePos:
|
||||
for j, before in isons(n):
|
||||
if j >= casePos: break
|
||||
# prevent new local declarations
|
||||
# compile declarations as assignments
|
||||
let it = n[j]
|
||||
if it.kind in {nkLetSection, nkVarSection}:
|
||||
let asgn = copyNode(it)
|
||||
if before.kind in {nkLetSection, nkVarSection}:
|
||||
let asgn = copyNode(before)
|
||||
asgn.transitionSonsKind(nkAsgn)
|
||||
asgn.sons.setLen 2
|
||||
for sym, value in it.fieldValuePairs:
|
||||
for sym, value in before.fieldValuePairs:
|
||||
if value.kind != nkEmpty:
|
||||
asgn[0] = sym
|
||||
asgn[1] = value
|
||||
asgn.secondSon = value
|
||||
genStmts(p, asgn)
|
||||
else:
|
||||
genStmts(p, it)
|
||||
genStmts(p, before)
|
||||
|
||||
var a: TLoc = initLocExpr(p, caseStmt.firstSon)
|
||||
let ra = a.rdLoc
|
||||
p.s(cpsStmts).addComputedGoto(subscript(tmp, ra))
|
||||
endSimpleBlock(p, scope)
|
||||
|
||||
for j in casePos+1..<n.len:
|
||||
genStmts(p, n[j])
|
||||
for it in sonsFrom(n, casePos+1):
|
||||
genStmts(p, it)
|
||||
|
||||
|
||||
proc genWhileStmt(p: BProc, t: PNode) =
|
||||
@@ -699,12 +698,12 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||
genLineDir(p, t)
|
||||
|
||||
preserveBreakIdx:
|
||||
var loopBody = t[1]
|
||||
var loopBody = t.secondSon
|
||||
if loopBody.stmtsContainPragma(wComputedGoto) and
|
||||
hasComputedGoto in CC[p.config.cCompiler].props:
|
||||
# for closure support weird loop bodies are generated:
|
||||
if loopBody.len == 2 and loopBody.firstSon.kind == nkEmpty:
|
||||
loopBody = loopBody[1]
|
||||
loopBody = loopBody.secondSon
|
||||
genComputedGoto(p, loopBody)
|
||||
else:
|
||||
var stmt: WhileBuilder
|
||||
@@ -746,7 +745,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
|
||||
sym.locImpl.k = locOther
|
||||
sym.positionImpl = p.breakIdx+1
|
||||
# ^ IC: review this
|
||||
expr(p, n[1], d)
|
||||
expr(p, n.secondSon, d)
|
||||
endSimpleBlock(p, scope)
|
||||
|
||||
proc genParForStmt(p: BProc, t: PNode) =
|
||||
@@ -759,21 +758,21 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
assignLocalVar(p, t.firstSon)
|
||||
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
|
||||
#discard mangleName(forLoopVar)
|
||||
let call = t[1]
|
||||
let call = t.secondSon
|
||||
assert(call.len == 4 or call.len == 5)
|
||||
var rangeA = initLocExpr(p, call[1])
|
||||
var rangeB = initLocExpr(p, call[2])
|
||||
var rangeA = initLocExpr(p, call.secondSon)
|
||||
var rangeB = initLocExpr(p, son(call, 2))
|
||||
|
||||
var stepNode: PNode = nil
|
||||
# $n at the beginning because of #9710
|
||||
if call.len == 4: # procName(a, b, annotation)
|
||||
if call.firstSon.sym.name.s == "||": # `||`(a, b, annotation)
|
||||
p.s(cpsStmts).addCPragma("omp " & call[3].getStr)
|
||||
p.s(cpsStmts).addCPragma("omp " & son(call, 3).getStr)
|
||||
else:
|
||||
p.s(cpsStmts).addCPragma(call[3].getStr)
|
||||
p.s(cpsStmts).addCPragma(son(call, 3).getStr)
|
||||
else: # `||`(a, b, step, annotation)
|
||||
stepNode = call[3]
|
||||
p.s(cpsStmts).addCPragma("omp " & call[4].getStr)
|
||||
stepNode = son(call, 3)
|
||||
p.s(cpsStmts).addCPragma("omp " & son(call, 4).getStr)
|
||||
|
||||
p.breakIdx = startBlockWith(p):
|
||||
if stepNode == nil:
|
||||
@@ -782,7 +781,7 @@ proc genParForStmt(p: BProc, t: PNode) =
|
||||
var step: TLoc = initLocExpr(p, stepNode)
|
||||
initForStep(p.s(cpsStmts), forLoopVar.loc.rdLoc, rangeA.rdLoc, rangeB.rdLoc, step.rdLoc, true)
|
||||
p.blocks[p.breakIdx].isLoop = true
|
||||
genStmts(p, t[2])
|
||||
genStmts(p, son(t, 2))
|
||||
endBlockWith(p):
|
||||
finishFor(p.s(cpsStmts))
|
||||
|
||||
@@ -909,17 +908,17 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
rangeFormat, eqFormat: untyped) =
|
||||
var x, y: TLoc
|
||||
for i in 0..<b.len - 1:
|
||||
for it in sonsButLast(b):
|
||||
let rlabel {.inject.} = labl
|
||||
if b[i].kind == nkRange:
|
||||
x = initLocExpr(p, b[i].firstSon)
|
||||
y = initLocExpr(p, b[i][1])
|
||||
if it.kind == nkRange:
|
||||
x = initLocExpr(p, it.firstSon)
|
||||
y = initLocExpr(p, it.secondSon)
|
||||
let ra {.inject.} = rdCharLoc(e)
|
||||
let rb {.inject.} = rdCharLoc(x)
|
||||
let rc {.inject.} = rdCharLoc(y)
|
||||
rangeFormat
|
||||
else:
|
||||
x = initLocExpr(p, b[i])
|
||||
x = initLocExpr(p, it)
|
||||
let ra {.inject.} = rdCharLoc(e)
|
||||
let rb {.inject.} = rdCharLoc(x)
|
||||
eqFormat
|
||||
@@ -927,15 +926,16 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
labId, until: int): TLabel =
|
||||
var lend = getLabel(p)
|
||||
for i in 1..until:
|
||||
for i, branch in isons(t, 1):
|
||||
if i > until: break
|
||||
# bug #4230: avoid false sharing between branches:
|
||||
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
||||
p.s(cpsStmts).addLabel("LA" & $(labId + i) & "_")
|
||||
if t[i].kind == nkOfBranch:
|
||||
exprBlock(p, t[i][^1], d)
|
||||
if branch.kind == nkOfBranch:
|
||||
exprBlock(p, branch.lastSon, d)
|
||||
p.s(cpsStmts).addGoto(lend)
|
||||
else:
|
||||
exprBlock(p, t[i].firstSon, d)
|
||||
exprBlock(p, branch.firstSon, d)
|
||||
result = lend
|
||||
|
||||
template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
@@ -944,11 +944,12 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
# generate a C-if statement for a Nim case statement
|
||||
var res: TLabel
|
||||
var labId = p.labels
|
||||
for i in 1..until:
|
||||
for i, branch in isons(t, 1):
|
||||
if i > until: break
|
||||
inc(p.labels)
|
||||
let lab = "LA" & $p.labels & "_"
|
||||
if t[i].kind == nkOfBranch: # else statement
|
||||
genCaseGenericBranch(p, t[i], a, lab, rangeFormat, eqFormat)
|
||||
if branch.kind == nkOfBranch: # else statement
|
||||
genCaseGenericBranch(p, branch, a, lab, rangeFormat, eqFormat)
|
||||
else:
|
||||
p.s(cpsStmts).addGoto(lab)
|
||||
if until < t.len-1:
|
||||
@@ -971,13 +972,13 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
stringKind: TTypeKind,
|
||||
branches: var openArray[Builder]) =
|
||||
var x: TLoc
|
||||
for i in 0..<b.len - 1:
|
||||
assert(b[i].kind != nkRange)
|
||||
x = initLocExpr(p, b[i])
|
||||
for it in sonsButLast(b):
|
||||
assert(it.kind != nkRange)
|
||||
x = initLocExpr(p, it)
|
||||
var j: int = 0
|
||||
case b[i].kind
|
||||
case it.kind
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
j = int(hashString(p.config, b[i].strVal) and high(branches))
|
||||
j = int(hashString(p.config, it.strVal) and high(branches))
|
||||
of nkNilLit: j = 0
|
||||
else:
|
||||
assert false, "invalid string case branch node kind"
|
||||
@@ -1022,7 +1023,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
p.s(cpsStmts).add(extract(branches[j]))
|
||||
p.s(cpsStmts).addBreak()
|
||||
# else statement:
|
||||
if t[^1].kind != nkOfBranch:
|
||||
if t.lastSon.kind != nkOfBranch:
|
||||
p.s(cpsStmts).addGoto("LA" & rope(p.labels) & "_")
|
||||
# third pass: generate statements
|
||||
var lend = genCaseSecondPass(p, t, d, labId, t.len-1)
|
||||
@@ -1043,7 +1044,7 @@ proc branchHasTooBigRange(b: PNode): bool =
|
||||
for it in b:
|
||||
# last son is block
|
||||
if (it.kind == nkRange) and
|
||||
it[1].intVal - it.firstSon.intVal > RangeExpandLimit:
|
||||
it.secondSon.intVal - it.firstSon.intVal > RangeExpandLimit:
|
||||
return true
|
||||
|
||||
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
|
||||
@@ -1057,24 +1058,24 @@ proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
|
||||
result = i
|
||||
|
||||
proc genCaseRange(p: BProc, branch: PNode, info: var SwitchCaseBuilder) =
|
||||
for j in 0..<branch.len-1:
|
||||
if branch[j].kind == nkRange:
|
||||
for it in sonsButLast(branch):
|
||||
if it.kind == nkRange:
|
||||
if hasSwitchRange in CC[p.config.cCompiler].props:
|
||||
var litA = newBuilder("")
|
||||
var litB = newBuilder("")
|
||||
genLiteral(p, branch[j].firstSon, litA)
|
||||
genLiteral(p, branch[j][1], litB)
|
||||
genLiteral(p, it.firstSon, litA)
|
||||
genLiteral(p, it.secondSon, litB)
|
||||
p.s(cpsStmts).addCaseRange(info, extract(litA), extract(litB))
|
||||
else:
|
||||
var v = copyNode(branch[j].firstSon)
|
||||
while v.intVal <= branch[j][1].intVal:
|
||||
var v = copyNode(it.firstSon)
|
||||
while v.intVal <= it.secondSon.intVal:
|
||||
var litA = newBuilder("")
|
||||
genLiteral(p, v, litA)
|
||||
p.s(cpsStmts).addCase(info, extract(litA))
|
||||
inc(v.intVal)
|
||||
else:
|
||||
var litA = newBuilder("")
|
||||
genLiteral(p, branch[j], litA)
|
||||
genLiteral(p, it, litA)
|
||||
p.s(cpsStmts).addCase(info, extract(litA))
|
||||
|
||||
proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
@@ -1100,10 +1101,9 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
|
||||
let rca = rdCharLoc(a)
|
||||
p.s(cpsStmts).addSwitchStmt(rca):
|
||||
var hasDefault = false
|
||||
for i in splitPoint+1..<n.len:
|
||||
for branch in sonsFrom(n, splitPoint+1):
|
||||
# bug #4230: avoid false sharing between branches:
|
||||
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
|
||||
var branch = n[i]
|
||||
var caseBuilder: SwitchCaseBuilder
|
||||
p.s(cpsStmts).addSwitchCase(caseBuilder):
|
||||
if branch.kind == nkOfBranch:
|
||||
@@ -1196,7 +1196,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
#init on locals, fixes #23306
|
||||
lineCg(p, cpsLocals, "std::exception_ptr T$1_;$n", [etmp])
|
||||
|
||||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
let fin = if t.lastSon.kind == nkFinally: t.lastSon else: nil
|
||||
p.nestedTryStmts.add((fin, false, t.kind == nkHiddenTryStmt, 0.Natural))
|
||||
|
||||
if t.kind == nkHiddenTryStmt:
|
||||
@@ -1221,10 +1221,11 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
var ifStmt = default(IfBuilder)
|
||||
var hasIf = false
|
||||
var hasElse = false
|
||||
while (i < t.len) and (t[i].kind == nkExceptBranch):
|
||||
while i < t.len and son(t, i).kind == nkExceptBranch:
|
||||
let exceptBranch = son(t, i)
|
||||
# bug #4230: avoid false sharing between branches:
|
||||
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
||||
if t[i].len == 1:
|
||||
if exceptBranch.len == 1:
|
||||
hasImportedCppExceptions = true
|
||||
hasElse = true
|
||||
# general except section:
|
||||
@@ -1236,7 +1237,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
scope = initScope(p.s(cpsStmts))
|
||||
# we handled the error:
|
||||
linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp])
|
||||
expr(p, t[i].firstSon, d)
|
||||
expr(p, exceptBranch.firstSon, d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
endBlockWith(p):
|
||||
if hasIf:
|
||||
@@ -1246,11 +1247,11 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
else:
|
||||
var orExpr = newRopeAppender()
|
||||
var exvar = PNode(nil)
|
||||
for j in 0..<t[i].len - 1:
|
||||
var typeNode = t[i][j]
|
||||
if t[i][j].isInfixAs():
|
||||
typeNode = t[i][j][1]
|
||||
exvar = t[i][j][2] # ex1 in `except ExceptType as ex1:`
|
||||
for label in sonsButLast(exceptBranch):
|
||||
var typeNode = label
|
||||
if label.isInfixAs():
|
||||
typeNode = label.secondSon
|
||||
exvar = son(label, 2) # ex1 in `except ExceptType as ex1:`
|
||||
assert(typeNode.kind == nkType)
|
||||
if isImportedException(typeNode.typ, p.config):
|
||||
hasImportedCppExceptions = true
|
||||
@@ -1278,7 +1279,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
rdLoc(exvar.sym.loc), rope(etmp+1)])
|
||||
# we handled the error:
|
||||
linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp])
|
||||
expr(p, t[i][^1], d)
|
||||
expr(p, exceptBranch.lastSon, d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
endBlockWith(p):
|
||||
finishBranch(p.s(cpsStmts), ifStmt)
|
||||
@@ -1314,31 +1315,31 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
p.s(cpsStmts).add("}\n")
|
||||
catchAllPresent = true
|
||||
else:
|
||||
for j in 0..<it.len-1:
|
||||
var typeNode = it[j]
|
||||
if it[j].isInfixAs():
|
||||
typeNode = it[j][1]
|
||||
for label in sonsButLast(it):
|
||||
var typeNode = label
|
||||
if label.isInfixAs():
|
||||
typeNode = label.secondSon
|
||||
if isImportedException(typeNode.typ, p.config):
|
||||
let exvar = it[j][2] # ex1 in `except ExceptType as ex1:`
|
||||
let exvar = son(label, 2) # ex1 in `except ExceptType as ex1:`
|
||||
fillLocalName(p, exvar.sym)
|
||||
backendEnsureMutable exvar.sym
|
||||
fillLoc(exvar.sym.locImpl, locTemp, exvar, OnStack)
|
||||
startBlockWith(p):
|
||||
lineCg(p, cpsStmts, "catch ($1& $2) {$n", [getTypeDesc(p.module, typeNode.typ), rdLoc(exvar.sym.loc)])
|
||||
genExceptBranchBody(it[^1]) # exception handler body will duplicated for every type
|
||||
genExceptBranchBody(it.lastSon) # exception handler body will duplicated for every type
|
||||
endBlockWith(p):
|
||||
p.s(cpsStmts).add("}\n")
|
||||
elif isImportedException(typeNode.typ, p.config):
|
||||
startBlockWith(p):
|
||||
lineCg(p, cpsStmts, "catch ($1&) {$n", [getTypeDesc(p.module, it[j].typ)])
|
||||
genExceptBranchBody(it[^1]) # exception handler body will duplicated for every type
|
||||
lineCg(p, cpsStmts, "catch ($1&) {$n", [getTypeDesc(p.module, label.typ)])
|
||||
genExceptBranchBody(it.lastSon) # exception handler body will duplicated for every type
|
||||
endBlockWith(p):
|
||||
p.s(cpsStmts).add("}\n")
|
||||
|
||||
excl p.flags, noSafePoints
|
||||
discard pop(p.nestedTryStmts)
|
||||
# general finally block:
|
||||
if t.len > 0 and t[^1].kind == nkFinally:
|
||||
if t.hasSons and t.lastSon.kind == nkFinally:
|
||||
if not catchAllPresent:
|
||||
startBlockWith(p):
|
||||
p.s(cpsStmts).add("catch (...) {\n")
|
||||
@@ -1349,7 +1350,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
|
||||
var scope: ScopeBuilder
|
||||
startSimpleBlock(p, scope)
|
||||
genStmts(p, t[^1].firstSon)
|
||||
genStmts(p, t.lastSon.firstSon)
|
||||
linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);$n", [etmp])
|
||||
endSimpleBlock(p, scope)
|
||||
|
||||
@@ -1372,10 +1373,10 @@ proc bodyCanRaise(p: BProc; n: PNode): bool =
|
||||
result = false
|
||||
|
||||
proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
let fin = if t.lastSon.kind == nkFinally: t.lastSon else: nil
|
||||
inc p.labels
|
||||
let lab = p.labels
|
||||
let hasExcept = t[1].kind == nkExceptBranch
|
||||
let hasExcept = t.secondSon.kind == nkExceptBranch
|
||||
if hasExcept: inc p.withinTryWithExcept
|
||||
p.nestedTryStmts.add((fin, false, t.kind == nkHiddenTryStmt, Natural lab))
|
||||
|
||||
@@ -1389,7 +1390,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
var ifStmt = default(IfBuilder)
|
||||
var scope = default(ScopeBuilder)
|
||||
var isIf = false
|
||||
if 1 < t.len and t[1].kind == nkExceptBranch:
|
||||
if 1 < t.len and t.secondSon.kind == nkExceptBranch:
|
||||
startBlockWith(p):
|
||||
isIf = true
|
||||
ifStmt = initIfStmt(p.s(cpsStmts))
|
||||
@@ -1404,7 +1405,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
var innerIfStmt = default(IfBuilder)
|
||||
var innerScope = default(ScopeBuilder)
|
||||
var innerIsIf = false
|
||||
while (i < t.len) and (t[i].kind == nkExceptBranch):
|
||||
while i < t.len and son(t, i).kind == nkExceptBranch:
|
||||
let exceptBranch = son(t, i)
|
||||
|
||||
inc p.labels
|
||||
let nextExcept = p.labels
|
||||
@@ -1413,7 +1415,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
var isScope = false
|
||||
# bug #4230: avoid false sharing between branches:
|
||||
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
||||
if t[i].len == 1:
|
||||
if exceptBranch.len == 1:
|
||||
# general except section:
|
||||
startBlockWith(p):
|
||||
if innerIsIf:
|
||||
@@ -1423,14 +1425,14 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
innerScope = initScope(p.s(cpsStmts))
|
||||
# we handled the exception, remember this:
|
||||
p.s(cpsStmts).addAssignment(cDeref("nimErr_"), NimFalse)
|
||||
expr(p, t[i].firstSon, d)
|
||||
expr(p, exceptBranch.firstSon, d)
|
||||
else:
|
||||
if not innerIsIf:
|
||||
innerIsIf = true
|
||||
innerIfStmt = initIfStmt(p.s(cpsStmts))
|
||||
var orExpr: Snippet = ""
|
||||
for j in 0..<t[i].len - 1:
|
||||
assert(t[i][j].kind == nkType)
|
||||
for label in sonsButLast(exceptBranch):
|
||||
assert(label.kind == nkType)
|
||||
var excVal = cCall(cgsymValue(p.module, "nimBorrowCurrentException"))
|
||||
let member =
|
||||
if p.module.compileToCpp:
|
||||
@@ -1439,13 +1441,13 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
dotField(derefField(excVal, "Sup"), "m_type")
|
||||
var branch: Snippet = ""
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(t[i][j].typ)
|
||||
let checkFor = $getObjDepth(label.typ)
|
||||
branch = cCall(cgsymValue(p.module, "isObjDisplayCheck"),
|
||||
member,
|
||||
checkFor,
|
||||
$genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config))))
|
||||
$genDisplayElem(MD5Digest(hashType(label.typ, p.config))))
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
|
||||
let checkFor = genTypeInfoV1(p.module, label.typ, label.info)
|
||||
branch = cCall(cgsymValue(p.module, "isObj"),
|
||||
member,
|
||||
checkFor)
|
||||
@@ -1458,7 +1460,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
initElifBranch(p.s(cpsStmts), innerIfStmt, orExpr)
|
||||
# we handled the exception, remember this:
|
||||
p.s(cpsStmts).addAssignment(cDeref("nimErr_"), NimFalse)
|
||||
expr(p, t[i][^1], d)
|
||||
expr(p, exceptBranch.lastSon, d)
|
||||
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
|
||||
p.s(cpsStmts).addLabel("LA" & $nextExcept & "_")
|
||||
@@ -1479,19 +1481,20 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
else:
|
||||
finishScope(p.s(cpsStmts), scope)
|
||||
|
||||
if i < t.len and t[i].kind == nkFinally:
|
||||
if i < t.len and son(t, i).kind == nkFinally:
|
||||
let finallyBranch = son(t, i)
|
||||
var finallyScope: ScopeBuilder
|
||||
startSimpleBlock(p, finallyScope)
|
||||
if not bodyCanRaise(p, t[i].firstSon):
|
||||
if not bodyCanRaise(p, finallyBranch.firstSon):
|
||||
# this is an important optimization; most destroy blocks are detected not to raise an
|
||||
# exception and so we help the C optimizer by not mutating nimErr_ pointlessly:
|
||||
genStmts(p, t[i].firstSon)
|
||||
genStmts(p, finallyBranch.firstSon)
|
||||
else:
|
||||
# pretend we did handle the error for the safe execution of the 'finally' section:
|
||||
p.procSec(cpsLocals).addVar(kind = Local, name = "oldNimErrFin" & $lab & "_", typ = NimBool)
|
||||
p.s(cpsStmts).addAssignment("oldNimErrFin" & $lab & "_", cDeref("nimErr_"))
|
||||
p.s(cpsStmts).addAssignment(cDeref("nimErr_"), NimFalse)
|
||||
genStmts(p, t[i].firstSon)
|
||||
genStmts(p, finallyBranch.firstSon)
|
||||
# this is correct for all these cases:
|
||||
# 1. finally is run during ordinary control flow
|
||||
# 2. finally is run after 'except' block handling: these however set the
|
||||
@@ -1582,7 +1585,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
nonQuirkyIf = initIfStmt(p.s(cpsStmts))
|
||||
initElifBranch(p.s(cpsStmts), nonQuirkyIf, removeSinglePar(
|
||||
cOp(Equal, dotField(safePoint, "status"), cIntValue(0))))
|
||||
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
|
||||
let fin = if t.lastSon.kind == nkFinally: t.lastSon else: nil
|
||||
p.nestedTryStmts.add((fin, quirkyExceptions, t.kind == nkHiddenTryStmt, 0.Natural))
|
||||
expr(p, t.firstSon, d)
|
||||
var quirkyIf = default(IfBuilder)
|
||||
@@ -1595,7 +1598,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
initElseBranch(p.s(cpsStmts), nonQuirkyIf)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popSafePoint"))
|
||||
genRestoreFrameAfterException(p)
|
||||
elif 1 < t.len and t[1].kind == nkExceptBranch:
|
||||
elif 1 < t.len and t.secondSon.kind == nkExceptBranch:
|
||||
startBlockWith(p):
|
||||
quirkyIf = initIfStmt(p.s(cpsStmts))
|
||||
initElifBranch(p.s(cpsStmts), quirkyIf,
|
||||
@@ -1608,10 +1611,11 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
var i = 1
|
||||
var exceptIf = default(IfBuilder)
|
||||
var exceptIfInited = false
|
||||
while (i < t.len) and (t[i].kind == nkExceptBranch):
|
||||
while i < t.len and son(t, i).kind == nkExceptBranch:
|
||||
let exceptBranch = son(t, i)
|
||||
# bug #4230: avoid false sharing between branches:
|
||||
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
||||
if t[i].len == 1:
|
||||
if exceptBranch.len == 1:
|
||||
# general except section:
|
||||
var scope = default(ScopeBuilder)
|
||||
startBlockWith(p):
|
||||
@@ -1621,7 +1625,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
scope = initScope(p.s(cpsStmts))
|
||||
if not quirkyExceptions:
|
||||
p.s(cpsStmts).addFieldAssignment(safePoint, "status", cIntValue(0))
|
||||
expr(p, t[i].firstSon, d)
|
||||
expr(p, exceptBranch.firstSon, d)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
|
||||
endBlockWith(p):
|
||||
if exceptIfInited:
|
||||
@@ -1630,8 +1634,8 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
finishScope(p.s(cpsStmts), scope)
|
||||
else:
|
||||
var orExpr: Snippet = ""
|
||||
for j in 0..<t[i].len - 1:
|
||||
assert(t[i][j].kind == nkType)
|
||||
for label in sonsButLast(exceptBranch):
|
||||
assert(label.kind == nkType)
|
||||
var excVal = cCall(cgsymValue(p.module, "nimBorrowCurrentException"))
|
||||
let member =
|
||||
if p.module.compileToCpp:
|
||||
@@ -1640,13 +1644,13 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
dotField(derefField(excVal, "Sup"), "m_type")
|
||||
var branch: Snippet = ""
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(t[i][j].typ)
|
||||
let checkFor = $getObjDepth(label.typ)
|
||||
branch = cCall(cgsymValue(p.module, "isObjDisplayCheck"),
|
||||
member,
|
||||
checkFor,
|
||||
$genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config))))
|
||||
$genDisplayElem(MD5Digest(hashType(label.typ, p.config))))
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
|
||||
let checkFor = genTypeInfoV1(p.module, label.typ, label.info)
|
||||
branch = cCall(cgsymValue(p.module, "isObj"),
|
||||
member,
|
||||
checkFor)
|
||||
@@ -1662,7 +1666,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
initElifBranch(p.s(cpsStmts), exceptIf, orExpr)
|
||||
if not quirkyExceptions:
|
||||
p.s(cpsStmts).addFieldAssignment(safePoint, "status", cIntValue(0))
|
||||
expr(p, t[i][^1], d)
|
||||
expr(p, exceptBranch.lastSon, d)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
|
||||
endBlockWith(p):
|
||||
finishBranch(p.s(cpsStmts), exceptIf)
|
||||
@@ -1680,11 +1684,12 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
else:
|
||||
finishBranch(p.s(cpsStmts), quirkyIf)
|
||||
finishIfStmt(p.s(cpsStmts), quirkyIf)
|
||||
if i < t.len and t[i].kind == nkFinally:
|
||||
if i < t.len and son(t, i).kind == nkFinally:
|
||||
let finallyBranch = son(t, i)
|
||||
p.finallySafePoints.add(safePoint)
|
||||
var finallyScope: ScopeBuilder
|
||||
startSimpleBlock(p, finallyScope)
|
||||
genStmts(p, t[i].firstSon)
|
||||
genStmts(p, finallyBranch.firstSon)
|
||||
# pretend we handled the exception in a 'finally' so that we don't
|
||||
# re-raise the unhandled one but instead keep the old one (it was
|
||||
# not popped either):
|
||||
@@ -1758,7 +1763,7 @@ proc genAsmStmt(p: BProc, t: PNode) =
|
||||
if (let p = t.firstSon; p.kind == nkPragma):
|
||||
for i in p:
|
||||
if whichPragma(i) == wAsmSyntax:
|
||||
asmSyntax = i[1].strVal
|
||||
asmSyntax = i.secondSon.strVal
|
||||
|
||||
if asmSyntax != "" and
|
||||
not (
|
||||
@@ -1789,10 +1794,10 @@ proc determineSection(n: PNode): TCFileSection =
|
||||
|
||||
proc genEmit(p: BProc, t: PNode) =
|
||||
var s = newRopeAppender()
|
||||
genAsmOrEmitStmt(p, t[1], false, s)
|
||||
genAsmOrEmitStmt(p, t.secondSon, false, s)
|
||||
if p.prc == nil:
|
||||
# top level emit pragma?
|
||||
let section = determineSection(t[1])
|
||||
let section = determineSection(t.secondSon)
|
||||
genCLineDir(p.module.s[section], t.info, p.config)
|
||||
p.module.s[section].add(s)
|
||||
else:
|
||||
@@ -1835,9 +1840,9 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.firstSon
|
||||
var a = initLocExpr(p, e.firstSon)
|
||||
var tmp: TLoc = getTemp(p, a.t)
|
||||
expr(p, e[1], tmp)
|
||||
expr(p, e.secondSon, tmp)
|
||||
if p.inUncheckedAssignSection == 0:
|
||||
let field = dotExpr[1].sym
|
||||
let field = dotExpr.secondSon.sym
|
||||
genDiscriminantCheck(p, a, tmp, dotExpr.firstSon.typ, field)
|
||||
message(p.config, e.info, warnCaseTransition)
|
||||
genAssignment(p, a, tmp, {})
|
||||
@@ -1845,7 +1850,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
if e.firstSon.kind == nkSym and sfGoto in e.firstSon.sym.flags:
|
||||
genLineDir(p, e)
|
||||
genGotoVar(p, e[1])
|
||||
genGotoVar(p, e.secondSon)
|
||||
elif optFieldCheck in p.options and isDiscriminantField(e.firstSon):
|
||||
genLineDir(p, e)
|
||||
asgnFieldDiscriminant(p, e)
|
||||
@@ -1854,13 +1859,13 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
# nimsso: s[i] = c → nimStrPutV3(&s, i, c) (handles COW internally)
|
||||
genLineDir(p, e)
|
||||
var base = initLocExpr(p, e.firstSon.firstSon)
|
||||
var idx = initLocExpr(p, e.firstSon[1])
|
||||
var rhs = initLocExpr(p, e[1])
|
||||
var idx = initLocExpr(p, e.firstSon.secondSon)
|
||||
var rhs = initLocExpr(p, e.secondSon)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimStrPutV3"),
|
||||
byRefLoc(p, base), rdLoc(idx), rdCharLoc(rhs))
|
||||
else:
|
||||
let le = e.firstSon
|
||||
let ri = e[1]
|
||||
let ri = e.secondSon
|
||||
var a: TLoc = initLoc(locNone, le, OnUnknown)
|
||||
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar)
|
||||
a.flags.incl(lfEnforceDeref)
|
||||
|
||||
@@ -34,9 +34,9 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
|
||||
for it in sons(n):
|
||||
genTraverseProc(c, accessor, it, typ)
|
||||
of nkRecCase:
|
||||
if (n[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
|
||||
if (n.firstSon.kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
|
||||
var p = c.p
|
||||
let disc = n[0].sym
|
||||
let disc = n.firstSon.sym
|
||||
if disc.loc.snippet == "": fillObjectFields(c.p.module, typ)
|
||||
if disc.loc.t == nil:
|
||||
internalError(c.p.config, n.info, "genTraverseProc()")
|
||||
|
||||
@@ -598,10 +598,10 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
|
||||
rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t.returnType, check, dkResult)])
|
||||
var types, names, args: seq[string] = @[]
|
||||
if not isCtor:
|
||||
var this = t.n[1].sym
|
||||
var this = t.n.secondSon.sym
|
||||
backendEnsureMutable this
|
||||
fillParamName(m, this)
|
||||
fillLoc(this.locImpl, locParam, t.n[1],
|
||||
fillLoc(this.locImpl, locParam, t.n.secondSon,
|
||||
this.paramStorageLoc)
|
||||
if this.typ.kind == tyPtr:
|
||||
this.locImpl.snippet = "this"
|
||||
@@ -1267,7 +1267,7 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Builder; asPtr: bool
|
||||
var check = initIntSet()
|
||||
fillBackendName(m, prc)
|
||||
backendEnsureMutable prc
|
||||
fillLoc(prc.locImpl, locProc, prc.ast[namePos], OnUnknown)
|
||||
fillLoc(prc.locImpl, locProc, son(prc.ast, namePos), OnUnknown)
|
||||
var memberOp = "#." #only virtual
|
||||
var typ: PType
|
||||
if isCtor:
|
||||
@@ -1321,7 +1321,7 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Builder; visibility: var D
|
||||
var check = initIntSet()
|
||||
fillBackendName(m, prc)
|
||||
backendEnsureMutable prc
|
||||
fillLoc(prc.locImpl, locProc, prc.ast[namePos], OnUnknown)
|
||||
fillLoc(prc.locImpl, locProc, son(prc.ast, namePos), OnUnknown)
|
||||
var rettype: Snippet = ""
|
||||
var desc = newBuilder("")
|
||||
genProcParams(m, prc.typ, rettype, desc, check, true, false)
|
||||
@@ -1559,15 +1559,15 @@ proc genObjectFields(m: BModule; typ, origType: PType, n: PNode, expr: Rope;
|
||||
of nkOfBranch:
|
||||
if b.len < 2:
|
||||
internalError(m.config, b.info, "genObjectFields; nkOfBranch broken")
|
||||
for j in 0..<b.len - 1:
|
||||
if b[j].kind == nkRange:
|
||||
var x = toInt(getOrdValue(b[j].firstSon))
|
||||
var y = toInt(getOrdValue(b[j][1]))
|
||||
for label in sonsButLast(b):
|
||||
if label.kind == nkRange:
|
||||
var x = toInt(getOrdValue(label.firstSon))
|
||||
var y = toInt(getOrdValue(label.secondSon))
|
||||
while x <= y:
|
||||
m.s[cfsTypeInit3].addSubscriptAssignment(tmp, cIntValue(x), cAddr(tmp2))
|
||||
inc(x)
|
||||
else:
|
||||
m.s[cfsTypeInit3].addSubscriptAssignment(tmp, cIntValue(getOrdValue(b[j])), cAddr(tmp2))
|
||||
m.s[cfsTypeInit3].addSubscriptAssignment(tmp, cIntValue(getOrdValue(label)), cAddr(tmp2))
|
||||
of nkElse:
|
||||
m.s[cfsTypeInit3].addSubscriptAssignment(tmp, cIntValue(L), cAddr(tmp2))
|
||||
else: internalError(m.config, n.info, "genObjectFields(nkRecCase)")
|
||||
@@ -2289,7 +2289,7 @@ proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rop
|
||||
|
||||
proc retrieveSym(n: PNode): PSym =
|
||||
case n.kind
|
||||
of nkPostfix: result = retrieveSym(n[1])
|
||||
of nkPostfix: result = retrieveSym(n.secondSon)
|
||||
of nkPragmaExpr, nkTypeDef: result = retrieveSym(n.firstSon)
|
||||
of nkSym: result = n.sym
|
||||
else: result = nil
|
||||
|
||||
@@ -172,12 +172,12 @@ proc encodeType*(m: BModule; t: PType; staticLists: var string): string =
|
||||
raiseAssert "unreachable"
|
||||
of tyRange:
|
||||
var val = "range_"
|
||||
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
|
||||
val.addFloat t.n[0].floatVal
|
||||
if t.n.firstSon.typ.kind in {tyFloat..tyFloat128}:
|
||||
val.addFloat t.n.firstSon.floatVal
|
||||
val.add "_"
|
||||
val.addFloat t.n[1].floatVal
|
||||
val.addFloat t.n.secondSon.floatVal
|
||||
else:
|
||||
val.add $t.n[0].intVal & "_" & $t.n[1].intVal
|
||||
val.add $t.n.firstSon.intVal & "_" & $t.n.secondSon.intVal
|
||||
result = encodeName(val)
|
||||
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
|
||||
result = encodeName(kindName)
|
||||
|
||||
@@ -187,7 +187,7 @@ proc ownsRuntimeRoutine*(s: PSym; modPos: int): bool =
|
||||
{sfForward, sfImportc, sfCompileTime, sfError} * s.flags == {} and
|
||||
s.typ != nil and not signatureHasMetaType(s.typ) and
|
||||
s.ast != nil and s.ast.safeLen > bodyPos and
|
||||
s.ast[genericParamsPos].kind == nkEmpty
|
||||
son(s.ast, genericParamsPos).kind == nkEmpty
|
||||
# NOTE: an `nkEmpty` body is NOT a disqualifier. A concrete, owned, non-
|
||||
# forward/-importc/-magic routine whose body folds to nothing is still a real
|
||||
# definition the owner must emit (`void f(void){}`), exactly as whole-program
|
||||
@@ -1207,7 +1207,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
cCast(getTypeDesc(m, sym.typ, dkVar),
|
||||
cCall(callee, params)))
|
||||
var last = lastSon(n)
|
||||
if last.kind == nkHiddenStdConv: last = last[1]
|
||||
if last.kind == nkHiddenStdConv: last = last.secondSon
|
||||
internalAssert(m.config, last.kind == nkStrLit)
|
||||
let idx = last.strVal
|
||||
if idx.len == 0:
|
||||
@@ -1312,14 +1312,14 @@ proc closeNamespaceNim(result: var Builder) =
|
||||
|
||||
proc closureSetup(p: BProc, prc: PSym) =
|
||||
if tfCapturesEnv notin prc.typ.flags: return
|
||||
# prc.ast[paramsPos].last contains the type we're after — BUT a closure loaded
|
||||
# The `paramsPos` child of `prc.ast` has the type we're after — BUT a closure loaded
|
||||
# from a `.t.bif` (a lambda-lifted nested proc / generic instance the `lower`
|
||||
# stage transformed) can arrive with an EMPTY AST param node: the lifted hidden
|
||||
# `:env` param lives in `typ.n`, the authoritative signature (`genProc` already
|
||||
# reads `typ.n`, not the AST). The two param nodes diverge across the NIF
|
||||
# boundary; fall back to `typ.n` so the env param resolves instead of indexing
|
||||
# an empty container.
|
||||
var params = prc.ast[paramsPos]
|
||||
var params = son(prc.ast, paramsPos)
|
||||
if params.safeLen == 0 and prc.typ.n != nil and prc.typ.n.kind == nkFormalParams:
|
||||
params = prc.typ.n
|
||||
var ls = lastSon(params)
|
||||
@@ -1352,7 +1352,7 @@ proc containsResult(n: BNode): bool =
|
||||
of nkReturnStmt:
|
||||
for ni in n.sons:
|
||||
if containsResult(ni): return true
|
||||
result = n.len > 0 and n.firstSon.kind == nkEmpty
|
||||
result = n.hasSons and n.firstSon.kind == nkEmpty
|
||||
of nkSym:
|
||||
if n.sym.kind == skResult:
|
||||
result = true
|
||||
@@ -1368,11 +1368,11 @@ proc easyResultAsgn(n: PNode): PNode =
|
||||
while i < n.len and n[i].kind in harmless: inc i
|
||||
if i < n.len: result = easyResultAsgn(n[i])
|
||||
of nkAsgn, nkFastAsgn, nkSinkAsgn:
|
||||
if n.firstSon.kind == nkSym and n.firstSon.sym.kind == skResult and not containsResult(n[1]):
|
||||
if n.firstSon.kind == nkSym and n.firstSon.sym.kind == skResult and not containsResult(n.secondSon):
|
||||
incl n.flags, nfPreventCg
|
||||
return n[1]
|
||||
return n.secondSon
|
||||
of nkReturnStmt:
|
||||
if n.len > 0:
|
||||
if n.hasSons:
|
||||
result = easyResultAsgn(n.firstSon)
|
||||
if result != nil: incl n.flags, nfPreventCg
|
||||
else: discard
|
||||
@@ -1414,8 +1414,8 @@ proc allPathsAsgnResult(p: BProc; n: BNode): InitResultEnum =
|
||||
if result != Unknown: return result
|
||||
of nkAsgn, nkFastAsgn, nkSinkAsgn:
|
||||
if n.firstSon.kind == nkSym and n.firstSon.sym.kind == skResult:
|
||||
if not containsResult(n[1]):
|
||||
if allPathsAsgnResult(p, n[1]) == InitRequired:
|
||||
if not containsResult(n.secondSon):
|
||||
if allPathsAsgnResult(p, n.secondSon) == InitRequired:
|
||||
result = InitRequired
|
||||
else:
|
||||
result = InitSkippable
|
||||
@@ -1423,9 +1423,9 @@ proc allPathsAsgnResult(p: BProc; n: BNode): InitResultEnum =
|
||||
elif containsResult(n):
|
||||
result = InitRequired
|
||||
else:
|
||||
result = allPathsAsgnResult(p, n[1])
|
||||
result = allPathsAsgnResult(p, n.secondSon)
|
||||
of nkReturnStmt:
|
||||
if n.len > 0:
|
||||
if n.hasSons:
|
||||
if n.firstSon.kind == nkEmpty and result != InitSkippable:
|
||||
# This is a bare `return` statement, if `result` was not initialized
|
||||
# anywhere else (or if we're not sure about this) let's require it to be
|
||||
@@ -1459,7 +1459,7 @@ proc allPathsAsgnResult(p: BProc; n: BNode): InitResultEnum =
|
||||
# condition and that would be fine. Everything else isn't:
|
||||
result = allPathsAsgnResult(p, n.firstSon)
|
||||
if result == Unknown:
|
||||
result = allPathsAsgnResult(p, n[1])
|
||||
result = allPathsAsgnResult(p, n.secondSon)
|
||||
# we cannot assume that the 'while' loop is really executed at least once:
|
||||
if result == InitSkippable: result = Unknown
|
||||
of harmless:
|
||||
@@ -1592,7 +1592,7 @@ proc genProcLvl3*(m: BModule, prc: PSym) =
|
||||
if sfPure notin prc.flags and prc.typ.returnType != nil:
|
||||
if resultPos >= prc.ast.len:
|
||||
internalError(m.config, prc.info, "proc has no result symbol")
|
||||
let resNode = prc.ast[resultPos]
|
||||
let resNode = son(prc.ast, resultPos)
|
||||
let res = resNode.sym # get result symbol
|
||||
if not isInvalidReturnType(m.config, prc.typ) and sfConstructor notin prc.flags:
|
||||
if sfNoInit in prc.flags: incl(res, sfNoInit)
|
||||
@@ -1832,17 +1832,17 @@ include inliner
|
||||
|
||||
proc genProcLvl2(m: BModule, prc: PSym) =
|
||||
if lfImportCompilerProc in prc.loc.flags:
|
||||
fillProcLoc(m, prc.ast[namePos])
|
||||
fillProcLoc(m, son(prc.ast, namePos))
|
||||
useHeader(m, prc)
|
||||
# dependency to a compilerproc:
|
||||
cgsym(m, prc.name.s)
|
||||
return
|
||||
if lfNoDecl in prc.loc.flags:
|
||||
fillProcLoc(m, prc.ast[namePos])
|
||||
fillProcLoc(m, son(prc.ast, namePos))
|
||||
genProcPrototype(m, prc)
|
||||
elif lfDynamicLib in prc.loc.flags:
|
||||
var q = findPendingModule(m, prc)
|
||||
fillProcLoc(q, prc.ast[namePos])
|
||||
fillProcLoc(q, son(prc.ast, namePos))
|
||||
genProcPrototype(m, prc)
|
||||
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
|
||||
symInDynamicLib(q, prc)
|
||||
@@ -1869,13 +1869,13 @@ proc genProcLvl2(m: BModule, prc: PSym) =
|
||||
# not on the first module that uses it
|
||||
if m.module.itemId.module != prc.itemId.module and optCompress in m.config.globalOptions:
|
||||
let prcCopy = prc # copyInlineProc(prc, m.idgen)
|
||||
fillProcLoc(m, prcCopy.ast[namePos])
|
||||
fillProcLoc(m, son(prcCopy.ast, namePos))
|
||||
genProcPrototype(m, prcCopy)
|
||||
genProcLvl3(m, prcCopy)
|
||||
else:
|
||||
let m2 = if m.config.symbolFiles != disabledSf: m
|
||||
else: findPendingModule(m, prc)
|
||||
fillProcLoc(m2, prc.ast[namePos])
|
||||
fillProcLoc(m2, son(prc.ast, namePos))
|
||||
#elif {sfExportc, sfImportc} * prc.flags == {}:
|
||||
# # reset name to restore consistency in case of hashing collisions:
|
||||
# #echo "resetting ", prc.id, " by ", m.module.name.s
|
||||
@@ -1885,7 +1885,7 @@ proc genProcLvl2(m: BModule, prc: PSym) =
|
||||
genProcLvl3(m, prc)
|
||||
elif sfImportc notin prc.flags:
|
||||
var q = findPendingModule(m, prc)
|
||||
fillProcLoc(q, prc.ast[namePos])
|
||||
fillProcLoc(q, son(prc.ast, namePos))
|
||||
# generate a getProc call to initialize the pointer for this
|
||||
# externally-to-the-current-module defined proc, also important
|
||||
# to do the declaredProtos check before the call to genProcPrototype
|
||||
@@ -1906,7 +1906,7 @@ proc genProcLvl2(m: BModule, prc: PSym) =
|
||||
if emitsBodyInThisModule(m, prc):
|
||||
genProcLvl3(q, prc)
|
||||
else:
|
||||
fillProcLoc(m, prc.ast[namePos])
|
||||
fillProcLoc(m, son(prc.ast, namePos))
|
||||
useHeader(m, prc)
|
||||
if sfInfixCall notin prc.flags: genProcPrototype(m, prc)
|
||||
|
||||
@@ -1928,7 +1928,7 @@ proc genProc(m: BModule, prc: PSym) =
|
||||
if sfBorrow in prc.flags or not isActivated(prc): return
|
||||
if sfForward in prc.flags:
|
||||
addForwardedProc(m, prc)
|
||||
fillProcLoc(m, prc.ast[namePos])
|
||||
fillProcLoc(m, son(prc.ast, namePos))
|
||||
else:
|
||||
genProcLvl2(m, prc)
|
||||
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
|
||||
@@ -2468,7 +2468,7 @@ proc genDatInitCode(m: BModule) =
|
||||
proc hcrGetProcLoadCode(builder: var Builder, m: BModule, sym, prefix, handle, getProcFunc: string) =
|
||||
let prc = magicsys.getCompilerProc(m.g.graph, sym)
|
||||
assert prc != nil
|
||||
fillProcLoc(m, prc.ast[namePos])
|
||||
fillProcLoc(m, son(prc.ast, namePos))
|
||||
|
||||
var tmp = mangleDynLibProc(prc)
|
||||
backendEnsureMutable prc
|
||||
|
||||
Reference in New Issue
Block a user