GC: get rid of pathological behaviour for stack marking
This commit is contained in:
parent
e390d8ec4a
commit
c40aac8e20
5 changed files with 326 additions and 323 deletions
|
|
@ -10,15 +10,15 @@
|
||||||
# This module implements the passes functionality. A pass must implement the
|
# This module implements the passes functionality. A pass must implement the
|
||||||
# `TPass` interface.
|
# `TPass` interface.
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
|
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
|
||||||
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
|
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
|
||||||
nimsets, syntaxes, times, rodread, idgen
|
nimsets, syntaxes, times, rodread, idgen
|
||||||
|
|
||||||
type
|
type
|
||||||
TPassContext* = object of RootObj # the pass's context
|
TPassContext* = object of RootObj # the pass's context
|
||||||
fromCache*: bool # true if created by "openCached"
|
fromCache*: bool # true if created by "openCached"
|
||||||
|
|
||||||
PPassContext* = ref TPassContext
|
PPassContext* = ref TPassContext
|
||||||
|
|
||||||
TPassOpen* = proc (module: PSym): PPassContext {.nimcall.}
|
TPassOpen* = proc (module: PSym): PPassContext {.nimcall.}
|
||||||
|
|
@ -33,8 +33,8 @@ type
|
||||||
TPassData* = tuple[input: PNode, closeOutput: PNode]
|
TPassData* = tuple[input: PNode, closeOutput: PNode]
|
||||||
TPasses* = openArray[TPass]
|
TPasses* = openArray[TPass]
|
||||||
|
|
||||||
# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
|
# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
|
||||||
# nodes. These are passed to the other close procedures.
|
# nodes. These are passed to the other close procedures.
|
||||||
# This mechanism used to be used for the instantiation of generics.
|
# This mechanism used to be used for the instantiation of generics.
|
||||||
|
|
||||||
proc makePass*(open: TPassOpen = nil,
|
proc makePass*(open: TPassOpen = nil,
|
||||||
|
|
@ -53,46 +53,46 @@ proc makePass*(open: TPassOpen = nil,
|
||||||
proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader)
|
proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader)
|
||||||
|
|
||||||
# the semantic checker needs these:
|
# the semantic checker needs these:
|
||||||
var
|
var
|
||||||
gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.}
|
gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.}
|
||||||
gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.}
|
gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.}
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc skipCodegen*(n: PNode): bool {.inline.} =
|
proc skipCodegen*(n: PNode): bool {.inline.} =
|
||||||
# can be used by codegen passes to determine whether they should do
|
# can be used by codegen passes to determine whether they should do
|
||||||
# something with `n`. Currently, this ignores `n` and uses the global
|
# something with `n`. Currently, this ignores `n` and uses the global
|
||||||
# error count instead.
|
# error count instead.
|
||||||
result = msgs.gErrorCounter > 0
|
result = msgs.gErrorCounter > 0
|
||||||
|
|
||||||
proc astNeeded*(s: PSym): bool =
|
proc astNeeded*(s: PSym): bool =
|
||||||
# The ``rodwrite`` module uses this to determine if the body of a proc
|
# The ``rodwrite`` module uses this to determine if the body of a proc
|
||||||
# needs to be stored. The passes manager frees s.sons[codePos] when
|
# needs to be stored. The passes manager frees s.sons[codePos] when
|
||||||
# appropriate to free the procedure body's memory. This is important
|
# appropriate to free the procedure body's memory. This is important
|
||||||
# to keep memory usage down.
|
# to keep memory usage down.
|
||||||
if (s.kind in {skMethod, skProc}) and
|
if (s.kind in {skMethod, skProc}) and
|
||||||
({sfCompilerProc, sfCompileTime} * s.flags == {}) and
|
({sfCompilerProc, sfCompileTime} * s.flags == {}) and
|
||||||
(s.typ.callConv != ccInline) and
|
(s.typ.callConv != ccInline) and
|
||||||
(s.ast.sons[genericParamsPos].kind == nkEmpty):
|
(s.ast.sons[genericParamsPos].kind == nkEmpty):
|
||||||
result = false
|
result = false
|
||||||
# XXX this doesn't really make sense with excessive CTFE
|
# XXX this doesn't really make sense with excessive CTFE
|
||||||
else:
|
else:
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
const
|
const
|
||||||
maxPasses = 10
|
maxPasses = 10
|
||||||
|
|
||||||
type
|
type
|
||||||
TPassContextArray = array[0..maxPasses - 1, PPassContext]
|
TPassContextArray = array[0..maxPasses - 1, PPassContext]
|
||||||
|
|
||||||
var
|
var
|
||||||
gPasses: array[0..maxPasses - 1, TPass]
|
gPasses: array[0..maxPasses - 1, TPass]
|
||||||
gPassesLen*: int
|
gPassesLen*: int
|
||||||
|
|
||||||
proc clearPasses* =
|
proc clearPasses* =
|
||||||
gPassesLen = 0
|
gPassesLen = 0
|
||||||
|
|
||||||
proc registerPass*(p: TPass) =
|
proc registerPass*(p: TPass) =
|
||||||
gPasses[gPassesLen] = p
|
gPasses[gPassesLen] = p
|
||||||
inc(gPassesLen)
|
inc(gPassesLen)
|
||||||
|
|
||||||
|
|
@ -109,48 +109,48 @@ proc carryPasses*(nodes: PNode, module: PSym, passes: TPasses) =
|
||||||
passdata = carryPass(pass, module, passdata)
|
passdata = carryPass(pass, module, passdata)
|
||||||
|
|
||||||
proc openPasses(a: var TPassContextArray, module: PSym) =
|
proc openPasses(a: var TPassContextArray, module: PSym) =
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].open):
|
if not isNil(gPasses[i].open):
|
||||||
a[i] = gPasses[i].open(module)
|
a[i] = gPasses[i].open(module)
|
||||||
else: a[i] = nil
|
else: a[i] = nil
|
||||||
|
|
||||||
proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
|
proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].openCached):
|
if not isNil(gPasses[i].openCached):
|
||||||
a[i] = gPasses[i].openCached(module, rd)
|
a[i] = gPasses[i].openCached(module, rd)
|
||||||
if a[i] != nil:
|
if a[i] != nil:
|
||||||
a[i].fromCache = true
|
a[i].fromCache = true
|
||||||
else:
|
else:
|
||||||
a[i] = nil
|
a[i] = nil
|
||||||
|
|
||||||
proc closePasses(a: var TPassContextArray) =
|
proc closePasses(a: var TPassContextArray) =
|
||||||
var m: PNode = nil
|
var m: PNode = nil
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m)
|
if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m)
|
||||||
a[i] = nil # free the memory here
|
a[i] = nil # free the memory here
|
||||||
|
|
||||||
proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool =
|
proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool =
|
||||||
# this implements the code transformation pipeline
|
# this implements the code transformation pipeline
|
||||||
var m = n
|
var m = n
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].process):
|
if not isNil(gPasses[i].process):
|
||||||
m = gPasses[i].process(a[i], m)
|
m = gPasses[i].process(a[i], m)
|
||||||
if isNil(m): return false
|
if isNil(m): return false
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
|
proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
|
||||||
# this implements the code transformation pipeline
|
# this implements the code transformation pipeline
|
||||||
var m = n
|
var m = n
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m)
|
if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m)
|
||||||
|
|
||||||
proc closePassesCached(a: var TPassContextArray) =
|
proc closePassesCached(a: var TPassContextArray) =
|
||||||
var m: PNode = nil
|
var m: PNode = nil
|
||||||
for i in countup(0, gPassesLen - 1):
|
for i in countup(0, gPassesLen - 1):
|
||||||
if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
|
if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
|
||||||
m = gPasses[i].close(a[i], m)
|
m = gPasses[i].close(a[i], m)
|
||||||
a[i] = nil # free the memory here
|
a[i] = nil # free the memory here
|
||||||
|
|
||||||
proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
|
proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
|
||||||
a: var TPassContextArray) =
|
a: var TPassContextArray) =
|
||||||
for module in items(implicits):
|
for module in items(implicits):
|
||||||
|
|
@ -159,45 +159,45 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
|
||||||
str.info = gCmdLineInfo
|
str.info = gCmdLineInfo
|
||||||
importStmt.addSon str
|
importStmt.addSon str
|
||||||
if not processTopLevelStmt(importStmt, a): break
|
if not processTopLevelStmt(importStmt, a): break
|
||||||
|
|
||||||
proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
||||||
var
|
var
|
||||||
p: TParsers
|
p: TParsers
|
||||||
a: TPassContextArray
|
a: TPassContextArray
|
||||||
s: PLLStream
|
s: PLLStream
|
||||||
fileIdx = module.fileIdx
|
fileIdx = module.fileIdx
|
||||||
if rd == nil:
|
if rd == nil:
|
||||||
openPasses(a, module)
|
openPasses(a, module)
|
||||||
if stream == nil:
|
if stream == nil:
|
||||||
let filename = fileIdx.toFullPathConsiderDirty
|
let filename = fileIdx.toFullPathConsiderDirty
|
||||||
if module.name.s == "-":
|
if module.name.s == "-":
|
||||||
module.name.s = "stdinfile"
|
module.name.s = "stdinfile"
|
||||||
s = llStreamOpen(stdin)
|
s = llStreamOpen(stdin)
|
||||||
else:
|
else:
|
||||||
s = llStreamOpen(filename, fmRead)
|
s = llStreamOpen(filename, fmRead)
|
||||||
if s == nil:
|
if s == nil:
|
||||||
rawMessage(errCannotOpenFile, filename)
|
rawMessage(errCannotOpenFile, filename)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
s = stream
|
s = stream
|
||||||
while true:
|
while true:
|
||||||
openParsers(p, fileIdx, s)
|
openParsers(p, fileIdx, s)
|
||||||
|
|
||||||
if sfSystemModule notin module.flags:
|
if sfSystemModule notin module.flags:
|
||||||
# XXX what about caching? no processing then? what if I change the
|
# XXX what about caching? no processing then? what if I change the
|
||||||
# modules to include between compilation runs? we'd need to track that
|
# modules to include between compilation runs? we'd need to track that
|
||||||
# in ROD files. I think we should enable this feature only
|
# in ROD files. I think we should enable this feature only
|
||||||
# for the interactive mode.
|
# for the interactive mode.
|
||||||
processImplicits implicitImports, nkImportStmt, a
|
processImplicits implicitImports, nkImportStmt, a
|
||||||
processImplicits implicitIncludes, nkIncludeStmt, a
|
processImplicits implicitIncludes, nkIncludeStmt, a
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
var n = parseTopLevelStmt(p)
|
var n = parseTopLevelStmt(p)
|
||||||
if n.kind == nkEmpty: break
|
if n.kind == nkEmpty: break
|
||||||
if not processTopLevelStmt(n, a): break
|
if not processTopLevelStmt(n, a): break
|
||||||
|
|
||||||
closeParsers(p)
|
closeParsers(p)
|
||||||
if s.kind != llsStdIn: break
|
if s.kind != llsStdIn: break
|
||||||
closePasses(a)
|
closePasses(a)
|
||||||
# id synchronization point for more consistent code generation:
|
# id synchronization point for more consistent code generation:
|
||||||
idSynchronizationPoint(1000)
|
idSynchronizationPoint(1000)
|
||||||
|
|
|
||||||
|
|
@ -17,27 +17,27 @@
|
||||||
# * introduces method dispatchers
|
# * introduces method dispatchers
|
||||||
# * performs lambda lifting for closure support
|
# * performs lambda lifting for closure support
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
|
||||||
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
|
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
|
||||||
lambdalifting, sempass2, lowerings
|
lambdalifting, sempass2, lowerings
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
type
|
type
|
||||||
PTransNode* = distinct PNode
|
PTransNode* = distinct PNode
|
||||||
|
|
||||||
PTransCon = ref TTransCon
|
PTransCon = ref TTransCon
|
||||||
TTransCon{.final.} = object # part of TContext; stackable
|
TTransCon{.final.} = object # part of TContext; stackable
|
||||||
mapping: TIdNodeTable # mapping from symbols to nodes
|
mapping: TIdNodeTable # mapping from symbols to nodes
|
||||||
owner: PSym # current owner
|
owner: PSym # current owner
|
||||||
forStmt: PNode # current for stmt
|
forStmt: PNode # current for stmt
|
||||||
forLoopBody: PTransNode # transformed for loop body
|
forLoopBody: PTransNode # transformed for loop body
|
||||||
yieldStmts: int # we count the number of yield statements,
|
yieldStmts: int # we count the number of yield statements,
|
||||||
# because we need to introduce new variables
|
# because we need to introduce new variables
|
||||||
# if we encounter the 2nd yield statement
|
# if we encounter the 2nd yield statement
|
||||||
next: PTransCon # for stacking
|
next: PTransCon # for stacking
|
||||||
|
|
||||||
TTransfContext = object of passes.TPassContext
|
TTransfContext = object of passes.TPassContext
|
||||||
module: PSym
|
module: PSym
|
||||||
transCon: PTransCon # top of a TransCon stack
|
transCon: PTransCon # top of a TransCon stack
|
||||||
|
|
@ -46,52 +46,52 @@ type
|
||||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||||
PTransf = ref TTransfContext
|
PTransf = ref TTransfContext
|
||||||
|
|
||||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||||
result = PTransNode(shallowCopy(a))
|
result = PTransNode(shallowCopy(a))
|
||||||
|
|
||||||
proc newTransNode(kind: TNodeKind, info: TLineInfo,
|
proc newTransNode(kind: TNodeKind, info: TLineInfo,
|
||||||
sons: int): PTransNode {.inline.} =
|
sons: int): PTransNode {.inline.} =
|
||||||
var x = newNodeI(kind, info)
|
var x = newNodeI(kind, info)
|
||||||
newSeq(x.sons, sons)
|
newSeq(x.sons, sons)
|
||||||
result = x.PTransNode
|
result = x.PTransNode
|
||||||
|
|
||||||
proc newTransNode(kind: TNodeKind, n: PNode,
|
proc newTransNode(kind: TNodeKind, n: PNode,
|
||||||
sons: int): PTransNode {.inline.} =
|
sons: int): PTransNode {.inline.} =
|
||||||
var x = newNodeIT(kind, n.info, n.typ)
|
var x = newNodeIT(kind, n.info, n.typ)
|
||||||
newSeq(x.sons, sons)
|
newSeq(x.sons, sons)
|
||||||
x.typ = n.typ
|
x.typ = n.typ
|
||||||
result = x.PTransNode
|
result = x.PTransNode
|
||||||
|
|
||||||
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
|
proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
|
||||||
var n = PNode(a)
|
var n = PNode(a)
|
||||||
n.sons[i] = PNode(x)
|
n.sons[i] = PNode(x)
|
||||||
|
|
||||||
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
|
proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
|
||||||
var n = PNode(a)
|
var n = PNode(a)
|
||||||
result = n.sons[i].PTransNode
|
result = n.sons[i].PTransNode
|
||||||
|
|
||||||
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
|
proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
|
||||||
proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
|
proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
|
||||||
|
|
||||||
proc newTransCon(owner: PSym): PTransCon =
|
proc newTransCon(owner: PSym): PTransCon =
|
||||||
assert owner != nil
|
assert owner != nil
|
||||||
new(result)
|
new(result)
|
||||||
initIdNodeTable(result.mapping)
|
initIdNodeTable(result.mapping)
|
||||||
result.owner = owner
|
result.owner = owner
|
||||||
|
|
||||||
proc pushTransCon(c: PTransf, t: PTransCon) =
|
proc pushTransCon(c: PTransf, t: PTransCon) =
|
||||||
t.next = c.transCon
|
t.next = c.transCon
|
||||||
c.transCon = t
|
c.transCon = t
|
||||||
|
|
||||||
proc popTransCon(c: PTransf) =
|
proc popTransCon(c: PTransf) =
|
||||||
if (c.transCon == nil): internalError("popTransCon")
|
if (c.transCon == nil): internalError("popTransCon")
|
||||||
c.transCon = c.transCon.next
|
c.transCon = c.transCon.next
|
||||||
|
|
||||||
proc getCurrOwner(c: PTransf): PSym =
|
proc getCurrOwner(c: PTransf): PSym =
|
||||||
if c.transCon != nil: result = c.transCon.owner
|
if c.transCon != nil: result = c.transCon.owner
|
||||||
else: result = c.module
|
else: result = c.module
|
||||||
|
|
||||||
proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
|
proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
|
||||||
result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
|
result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
|
||||||
result.typ = skipTypes(typ, {tyGenericInst})
|
result.typ = skipTypes(typ, {tyGenericInst})
|
||||||
incl(result.flags, sfFromGeneric)
|
incl(result.flags, sfFromGeneric)
|
||||||
|
|
@ -100,10 +100,10 @@ proc transform(c: PTransf, n: PNode): PTransNode
|
||||||
|
|
||||||
proc transformSons(c: PTransf, n: PNode): PTransNode =
|
proc transformSons(c: PTransf, n: PNode): PTransNode =
|
||||||
result = newTransNode(n)
|
result = newTransNode(n)
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
result[i] = transform(c, n.sons[i])
|
result[i] = transform(c, n.sons[i])
|
||||||
|
|
||||||
proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
|
proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
|
||||||
result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
|
result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
|
||||||
result[0] = PTransNode(le)
|
result[0] = PTransNode(le)
|
||||||
result[1] = ri
|
result[1] = ri
|
||||||
|
|
@ -113,30 +113,30 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||||
# return liftIterSym(n)
|
# return liftIterSym(n)
|
||||||
var b: PNode
|
var b: PNode
|
||||||
var tc = c.transCon
|
var tc = c.transCon
|
||||||
if sfBorrow in n.sym.flags:
|
if sfBorrow in n.sym.flags:
|
||||||
# simply exchange the symbol:
|
# simply exchange the symbol:
|
||||||
b = n.sym.getBody
|
b = n.sym.getBody
|
||||||
if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
|
if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
|
||||||
b = newSymNode(b.sym)
|
b = newSymNode(b.sym)
|
||||||
b.info = n.info
|
b.info = n.info
|
||||||
else:
|
else:
|
||||||
b = n
|
b = n
|
||||||
while tc != nil:
|
while tc != nil:
|
||||||
result = idNodeTableGet(tc.mapping, b.sym)
|
result = idNodeTableGet(tc.mapping, b.sym)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
tc = tc.next
|
tc = tc.next
|
||||||
result = b
|
result = b
|
||||||
|
|
||||||
proc transformSym(c: PTransf, n: PNode): PTransNode =
|
proc transformSym(c: PTransf, n: PNode): PTransNode =
|
||||||
result = PTransNode(transformSymAux(c, n))
|
result = PTransNode(transformSymAux(c, n))
|
||||||
|
|
||||||
proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
||||||
result = newTransNode(v)
|
result = newTransNode(v)
|
||||||
for i in countup(0, sonsLen(v)-1):
|
for i in countup(0, sonsLen(v)-1):
|
||||||
var it = v.sons[i]
|
var it = v.sons[i]
|
||||||
if it.kind == nkCommentStmt:
|
if it.kind == nkCommentStmt:
|
||||||
result[i] = PTransNode(it)
|
result[i] = PTransNode(it)
|
||||||
elif it.kind == nkIdentDefs:
|
elif it.kind == nkIdentDefs:
|
||||||
if it.sons[0].kind != nkSym: internalError(it.info, "transformVarSection")
|
if it.sons[0].kind != nkSym: internalError(it.info, "transformVarSection")
|
||||||
internalAssert(it.len == 3)
|
internalAssert(it.len == 3)
|
||||||
var newVar = copySym(it.sons[0].sym)
|
var newVar = copySym(it.sons[0].sym)
|
||||||
|
|
@ -153,12 +153,12 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
||||||
defs[1] = it.sons[1].PTransNode
|
defs[1] = it.sons[1].PTransNode
|
||||||
defs[2] = transform(c, it.sons[2])
|
defs[2] = transform(c, it.sons[2])
|
||||||
result[i] = defs
|
result[i] = defs
|
||||||
else:
|
else:
|
||||||
if it.kind != nkVarTuple:
|
if it.kind != nkVarTuple:
|
||||||
internalError(it.info, "transformVarSection: not nkVarTuple")
|
internalError(it.info, "transformVarSection: not nkVarTuple")
|
||||||
var L = sonsLen(it)
|
var L = sonsLen(it)
|
||||||
var defs = newTransNode(it.kind, it.info, L)
|
var defs = newTransNode(it.kind, it.info, L)
|
||||||
for j in countup(0, L-3):
|
for j in countup(0, L-3):
|
||||||
var newVar = copySym(it.sons[j].sym)
|
var newVar = copySym(it.sons[j].sym)
|
||||||
incl(newVar.flags, sfFromGeneric)
|
incl(newVar.flags, sfFromGeneric)
|
||||||
newVar.owner = getCurrOwner(c)
|
newVar.owner = getCurrOwner(c)
|
||||||
|
|
@ -188,12 +188,12 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
|
||||||
else:
|
else:
|
||||||
result[i] = PTransNode(it)
|
result[i] = PTransNode(it)
|
||||||
|
|
||||||
proc hasContinue(n: PNode): bool =
|
proc hasContinue(n: PNode): bool =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
|
of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
|
||||||
of nkContinueStmt: result = true
|
of nkContinueStmt: result = true
|
||||||
else:
|
else:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if hasContinue(n.sons[i]): return true
|
if hasContinue(n.sons[i]): return true
|
||||||
|
|
||||||
proc newLabel(c: PTransf, n: PNode): PSym =
|
proc newLabel(c: PTransf, n: PNode): PSym =
|
||||||
|
|
@ -224,10 +224,10 @@ proc transformBlock(c: PTransf, n: PNode): PTransNode =
|
||||||
discard c.breakSyms.pop
|
discard c.breakSyms.pop
|
||||||
result[0] = newSymNode(labl).PTransNode
|
result[0] = newSymNode(labl).PTransNode
|
||||||
|
|
||||||
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||||
# What if it contains "continue" and "break"? "break" needs
|
# What if it contains "continue" and "break"? "break" needs
|
||||||
# an explicit label too, but not the same!
|
# an explicit label too, but not the same!
|
||||||
|
|
||||||
# We fix this here by making every 'break' belong to its enclosing loop
|
# We fix this here by making every 'break' belong to its enclosing loop
|
||||||
# and changing all breaks that belong to a 'block' by annotating it with
|
# and changing all breaks that belong to a 'block' by annotating it with
|
||||||
# a label (if it hasn't one already).
|
# a label (if it hasn't one already).
|
||||||
|
|
@ -239,7 +239,7 @@ proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
|
||||||
result[0] = newSymNode(labl).PTransNode
|
result[0] = newSymNode(labl).PTransNode
|
||||||
result[1] = transform(c, n)
|
result[1] = transform(c, n)
|
||||||
discard c.contSyms.pop()
|
discard c.contSyms.pop()
|
||||||
else:
|
else:
|
||||||
result = transform(c, n)
|
result = transform(c, n)
|
||||||
|
|
||||||
proc transformWhile(c: PTransf; n: PNode): PTransNode =
|
proc transformWhile(c: PTransf; n: PNode): PTransNode =
|
||||||
|
|
@ -273,27 +273,27 @@ proc transformBreak(c: PTransf, n: PNode): PTransNode =
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
result[0] = newSymNode(labl).PTransNode
|
result[0] = newSymNode(labl).PTransNode
|
||||||
|
|
||||||
proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
||||||
# XXX: BUG: what if `n` is an expression with side-effects?
|
# XXX: BUG: what if `n` is an expression with side-effects?
|
||||||
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
||||||
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||||
transform(c, newTupleAccess(n, i))))
|
transform(c, newTupleAccess(n, i))))
|
||||||
|
|
||||||
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = transformSym(c, n)
|
result = transformSym(c, n)
|
||||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||||
# nothing to be done for leaves:
|
# nothing to be done for leaves:
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
of nkVarSection, nkLetSection:
|
of nkVarSection, nkLetSection:
|
||||||
result = transformVarSection(c, n)
|
result = transformVarSection(c, n)
|
||||||
else:
|
else:
|
||||||
result = newTransNode(n)
|
result = newTransNode(n)
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
result[i] = introduceNewLocalVars(c, n.sons[i])
|
result[i] = introduceNewLocalVars(c, n.sons[i])
|
||||||
|
|
||||||
proc transformYield(c: PTransf, n: PNode): PTransNode =
|
proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||||
result = newTransNode(nkStmtList, n.info, 0)
|
result = newTransNode(nkStmtList, n.info, 0)
|
||||||
var e = n.sons[0]
|
var e = n.sons[0]
|
||||||
# c.transCon.forStmt.len == 3 means that there is one for loop variable
|
# c.transCon.forStmt.len == 3 means that there is one for loop variable
|
||||||
|
|
@ -301,21 +301,21 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||||
if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple and
|
if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple and
|
||||||
c.transCon.forStmt.len != 3:
|
c.transCon.forStmt.len != 3:
|
||||||
e = skipConv(e)
|
e = skipConv(e)
|
||||||
if e.kind == nkPar:
|
if e.kind == nkPar:
|
||||||
for i in countup(0, sonsLen(e) - 1):
|
for i in countup(0, sonsLen(e) - 1):
|
||||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||||
transform(c, e.sons[i])))
|
transform(c, e.sons[i])))
|
||||||
else:
|
else:
|
||||||
unpackTuple(c, e, result)
|
unpackTuple(c, e, result)
|
||||||
else:
|
else:
|
||||||
var x = transform(c, e)
|
var x = transform(c, e)
|
||||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
|
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
|
||||||
|
|
||||||
inc(c.transCon.yieldStmts)
|
inc(c.transCon.yieldStmts)
|
||||||
if c.transCon.yieldStmts <= 1:
|
if c.transCon.yieldStmts <= 1:
|
||||||
# common case
|
# common case
|
||||||
add(result, c.transCon.forLoopBody)
|
add(result, c.transCon.forLoopBody)
|
||||||
else:
|
else:
|
||||||
# we need to introduce new local variables:
|
# we need to introduce new local variables:
|
||||||
add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
|
add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
|
||||||
|
|
||||||
|
|
@ -340,25 +340,25 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
||||||
if n.sons[0].kind == a or n.sons[0].kind == b:
|
if n.sons[0].kind == a or n.sons[0].kind == b:
|
||||||
# addr ( deref ( x )) --> x
|
# addr ( deref ( x )) --> x
|
||||||
result = PTransNode(n.sons[0].sons[0])
|
result = PTransNode(n.sons[0].sons[0])
|
||||||
|
|
||||||
proc transformConv(c: PTransf, n: PNode): PTransNode =
|
proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
# numeric types need range checks:
|
# numeric types need range checks:
|
||||||
var dest = skipTypes(n.typ, abstractVarRange)
|
var dest = skipTypes(n.typ, abstractVarRange)
|
||||||
var source = skipTypes(n.sons[1].typ, abstractVarRange)
|
var source = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||||
case dest.kind
|
case dest.kind
|
||||||
of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
|
of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
|
||||||
# we don't include uint and uint64 here as these are no ordinal types ;-)
|
# we don't include uint and uint64 here as these are no ordinal types ;-)
|
||||||
if not isOrdinalType(source):
|
if not isOrdinalType(source):
|
||||||
# float -> int conversions. ugh.
|
# float -> int conversions. ugh.
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
|
elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
|
||||||
lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
|
lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
|
||||||
# BUGFIX: simply leave n as it is; we need a nkConv node,
|
# BUGFIX: simply leave n as it is; we need a nkConv node,
|
||||||
# but no range check:
|
# but no range check:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
else:
|
else:
|
||||||
# generate a range check:
|
# generate a range check:
|
||||||
if dest.kind == tyInt64 or source.kind == tyInt64:
|
if dest.kind == tyInt64 or source.kind == tyInt64:
|
||||||
result = newTransNode(nkChckRange64, n, 3)
|
result = newTransNode(nkChckRange64, n, 3)
|
||||||
else:
|
else:
|
||||||
result = newTransNode(nkChckRange, n, 3)
|
result = newTransNode(nkChckRange, n, 3)
|
||||||
|
|
@ -368,7 +368,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
|
result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
|
||||||
of tyFloat..tyFloat128:
|
of tyFloat..tyFloat128:
|
||||||
# XXX int64 -> float conversion?
|
# XXX int64 -> float conversion?
|
||||||
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
if skipTypes(n.typ, abstractVar).kind == tyRange:
|
||||||
result = newTransNode(nkChckRangeF, n, 3)
|
result = newTransNode(nkChckRangeF, n, 3)
|
||||||
dest = skipTypes(n.typ, abstractVar)
|
dest = skipTypes(n.typ, abstractVar)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
|
|
@ -378,81 +378,81 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of tyOpenArray, tyVarargs:
|
of tyOpenArray, tyVarargs:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
of tyCString:
|
of tyCString:
|
||||||
if source.kind == tyString:
|
if source.kind == tyString:
|
||||||
result = newTransNode(nkStringToCString, n, 1)
|
result = newTransNode(nkStringToCString, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of tyString:
|
of tyString:
|
||||||
if source.kind == tyCString:
|
if source.kind == tyCString:
|
||||||
result = newTransNode(nkCStringToString, n, 1)
|
result = newTransNode(nkCStringToString, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of tyRef, tyPtr:
|
of tyRef, tyPtr:
|
||||||
dest = skipTypes(dest, abstractPtrs)
|
dest = skipTypes(dest, abstractPtrs)
|
||||||
source = skipTypes(source, abstractPtrs)
|
source = skipTypes(source, abstractPtrs)
|
||||||
if source.kind == tyObject:
|
if source.kind == tyObject:
|
||||||
var diff = inheritanceDiff(dest, source)
|
var diff = inheritanceDiff(dest, source)
|
||||||
if diff < 0:
|
if diff < 0:
|
||||||
result = newTransNode(nkObjUpConv, n, 1)
|
result = newTransNode(nkObjUpConv, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
elif diff > 0:
|
elif diff > 0:
|
||||||
result = newTransNode(nkObjDownConv, n, 1)
|
result = newTransNode(nkObjDownConv, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of tyObject:
|
of tyObject:
|
||||||
var diff = inheritanceDiff(dest, source)
|
var diff = inheritanceDiff(dest, source)
|
||||||
if diff < 0:
|
if diff < 0:
|
||||||
result = newTransNode(nkObjUpConv, n, 1)
|
result = newTransNode(nkObjUpConv, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
elif diff > 0:
|
elif diff > 0:
|
||||||
result = newTransNode(nkObjDownConv, n, 1)
|
result = newTransNode(nkObjDownConv, n, 1)
|
||||||
result[0] = transform(c, n.sons[1])
|
result[0] = transform(c, n.sons[1])
|
||||||
else:
|
else:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
of tyGenericParam, tyOrdinal:
|
of tyGenericParam, tyOrdinal:
|
||||||
result = transform(c, n.sons[1])
|
result = transform(c, n.sons[1])
|
||||||
# happens sometimes for generated assignments, etc.
|
# happens sometimes for generated assignments, etc.
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
|
|
||||||
type
|
type
|
||||||
TPutArgInto = enum
|
TPutArgInto = enum
|
||||||
paDirectMapping, paFastAsgn, paVarAsgn
|
paDirectMapping, paFastAsgn, paVarAsgn
|
||||||
|
|
||||||
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
||||||
# This analyses how to treat the mapping "formal <-> arg" in an
|
# This analyses how to treat the mapping "formal <-> arg" in an
|
||||||
# inline context.
|
# inline context.
|
||||||
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
|
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||||
return paDirectMapping # XXX really correct?
|
return paDirectMapping # XXX really correct?
|
||||||
# what if ``arg`` has side-effects?
|
# what if ``arg`` has side-effects?
|
||||||
case arg.kind
|
case arg.kind
|
||||||
of nkEmpty..nkNilLit:
|
of nkEmpty..nkNilLit:
|
||||||
result = paDirectMapping
|
result = paDirectMapping
|
||||||
of nkPar, nkCurly, nkBracket:
|
of nkPar, nkCurly, nkBracket:
|
||||||
result = paFastAsgn
|
result = paFastAsgn
|
||||||
for i in countup(0, sonsLen(arg) - 1):
|
for i in countup(0, sonsLen(arg) - 1):
|
||||||
if putArgInto(arg.sons[i], formal) != paDirectMapping: return
|
if putArgInto(arg.sons[i], formal) != paDirectMapping: return
|
||||||
result = paDirectMapping
|
result = paDirectMapping
|
||||||
else:
|
else:
|
||||||
if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
|
if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
|
||||||
else: result = paFastAsgn
|
else: result = paFastAsgn
|
||||||
|
|
||||||
proc findWrongOwners(c: PTransf, n: PNode) =
|
proc findWrongOwners(c: PTransf, n: PNode) =
|
||||||
if n.kind == nkVarSection:
|
if n.kind == nkVarSection:
|
||||||
let x = n.sons[0].sons[0]
|
let x = n.sons[0].sons[0]
|
||||||
if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
|
if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
|
||||||
internalError(x.info, "bah " & x.sym.name.s & " " &
|
internalError(x.info, "bah " & x.sym.name.s & " " &
|
||||||
x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
|
x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
|
||||||
else:
|
else:
|
||||||
for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
|
for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
|
||||||
|
|
||||||
proc transformFor(c: PTransf, n: PNode): PTransNode =
|
proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
# generate access statements for the parameters (unless they are constant)
|
# generate access statements for the parameters (unless they are constant)
|
||||||
# put mapping from formal parameters to actual parameters
|
# put mapping from formal parameters to actual parameters
|
||||||
if n.kind != nkForStmt: internalError(n.info, "transformFor")
|
if n.kind != nkForStmt: internalError(n.info, "transformFor")
|
||||||
|
|
@ -466,26 +466,26 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
result[0] = newSymNode(labl).PTransNode
|
result[0] = newSymNode(labl).PTransNode
|
||||||
|
|
||||||
if call.typ.kind != tyIter and
|
if call.typ.kind != tyIter and
|
||||||
(call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
(call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
|
||||||
call.sons[0].sym.kind != skIterator):
|
call.sons[0].sym.kind != skIterator):
|
||||||
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
||||||
result[1] = lambdalifting.liftForLoop(n).PTransNode
|
result[1] = lambdalifting.liftForLoop(n).PTransNode
|
||||||
discard c.breakSyms.pop
|
discard c.breakSyms.pop
|
||||||
return result
|
return result
|
||||||
|
|
||||||
#echo "transforming: ", renderTree(n)
|
#echo "transforming: ", renderTree(n)
|
||||||
var stmtList = newTransNode(nkStmtList, n.info, 0)
|
var stmtList = newTransNode(nkStmtList, n.info, 0)
|
||||||
|
|
||||||
var loopBody = transformLoopBody(c, n.sons[length-1])
|
var loopBody = transformLoopBody(c, n.sons[length-1])
|
||||||
|
|
||||||
result[1] = stmtList
|
result[1] = stmtList
|
||||||
discard c.breakSyms.pop
|
discard c.breakSyms.pop
|
||||||
|
|
||||||
var v = newNodeI(nkVarSection, n.info)
|
var v = newNodeI(nkVarSection, n.info)
|
||||||
for i in countup(0, length - 3):
|
for i in countup(0, length - 3):
|
||||||
addVar(v, copyTree(n.sons[i])) # declare new vars
|
addVar(v, copyTree(n.sons[i])) # declare new vars
|
||||||
add(stmtList, v.PTransNode)
|
add(stmtList, v.PTransNode)
|
||||||
|
|
||||||
# Bugfix: inlined locals belong to the invoking routine, not to the invoked
|
# Bugfix: inlined locals belong to the invoking routine, not to the invoked
|
||||||
# iterator!
|
# iterator!
|
||||||
let iter = call.sons[0].sym
|
let iter = call.sons[0].sym
|
||||||
|
|
@ -496,9 +496,9 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
if iter.kind != skIterator: return result
|
if iter.kind != skIterator: return result
|
||||||
# generate access statements for the parameters (unless they are constant)
|
# generate access statements for the parameters (unless they are constant)
|
||||||
pushTransCon(c, newC)
|
pushTransCon(c, newC)
|
||||||
for i in countup(1, sonsLen(call) - 1):
|
for i in countup(1, sonsLen(call) - 1):
|
||||||
var arg = transform(c, call.sons[i]).PNode
|
var arg = transform(c, call.sons[i]).PNode
|
||||||
var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
|
var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
|
||||||
if arg.typ.kind == tyIter: continue
|
if arg.typ.kind == tyIter: continue
|
||||||
case putArgInto(arg, formal.typ)
|
case putArgInto(arg, formal.typ)
|
||||||
of paDirectMapping:
|
of paDirectMapping:
|
||||||
|
|
@ -527,20 +527,20 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
popTransCon(c)
|
popTransCon(c)
|
||||||
# echo "transformed: ", stmtList.PNode.renderTree
|
# echo "transformed: ", stmtList.PNode.renderTree
|
||||||
|
|
||||||
proc getMagicOp(call: PNode): TMagic =
|
proc getMagicOp(call: PNode): TMagic =
|
||||||
if call.sons[0].kind == nkSym and
|
if call.sons[0].kind == nkSym and
|
||||||
call.sons[0].sym.kind in {skProc, skMethod, skConverter}:
|
call.sons[0].sym.kind in {skProc, skMethod, skConverter}:
|
||||||
result = call.sons[0].sym.magic
|
result = call.sons[0].sym.magic
|
||||||
else:
|
else:
|
||||||
result = mNone
|
result = mNone
|
||||||
|
|
||||||
proc transformCase(c: PTransf, n: PNode): PTransNode =
|
proc transformCase(c: PTransf, n: PNode): PTransNode =
|
||||||
# removes `elif` branches of a case stmt
|
# removes `elif` branches of a case stmt
|
||||||
# adds ``else: nil`` if needed for the code generator
|
# adds ``else: nil`` if needed for the code generator
|
||||||
result = newTransNode(nkCaseStmt, n, 0)
|
result = newTransNode(nkCaseStmt, n, 0)
|
||||||
var ifs = PTransNode(nil)
|
var ifs = PTransNode(nil)
|
||||||
for i in 0 .. sonsLen(n)-1:
|
for i in 0 .. sonsLen(n)-1:
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
var e = transform(c, it)
|
var e = transform(c, it)
|
||||||
case it.kind
|
case it.kind
|
||||||
|
|
@ -564,8 +564,8 @@ proc transformCase(c: PTransf, n: PNode): PTransNode =
|
||||||
var elseBranch = newTransNode(nkElse, n.info, 1)
|
var elseBranch = newTransNode(nkElse, n.info, 1)
|
||||||
elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
|
elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
|
||||||
add(result, elseBranch)
|
add(result, elseBranch)
|
||||||
|
|
||||||
proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
|
proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
|
||||||
# XXX this is really bad; transf should use a proper AST visitor
|
# XXX this is really bad; transf should use a proper AST visitor
|
||||||
if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
|
if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
|
||||||
result = n.PTransNode
|
result = n.PTransNode
|
||||||
|
|
@ -573,45 +573,45 @@ proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
|
||||||
result = newTransNode(n)
|
result = newTransNode(n)
|
||||||
for i in 0 .. < n.len:
|
for i in 0 .. < n.len:
|
||||||
result[i] = transform(c, skipConv(n.sons[i]))
|
result[i] = transform(c, skipConv(n.sons[i]))
|
||||||
|
|
||||||
proc getMergeOp(n: PNode): PSym =
|
proc getMergeOp(n: PNode): PSym =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||||
nkCallStrLit:
|
nkCallStrLit:
|
||||||
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skProc) and
|
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skProc) and
|
||||||
(sfMerge in n.sons[0].sym.flags):
|
(sfMerge in n.sons[0].sym.flags):
|
||||||
result = n.sons[0].sym
|
result = n.sons[0].sym
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
||||||
let op2 = getMergeOp(a)
|
let op2 = getMergeOp(a)
|
||||||
if op2 != nil and
|
if op2 != nil and
|
||||||
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
|
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
|
||||||
for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
|
for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
|
||||||
else:
|
else:
|
||||||
addSon(d, copyTree(a))
|
addSon(d, copyTree(a))
|
||||||
|
|
||||||
proc flattenTree(root: PNode): PNode =
|
proc flattenTree(root: PNode): PNode =
|
||||||
let op = getMergeOp(root)
|
let op = getMergeOp(root)
|
||||||
if op != nil:
|
if op != nil:
|
||||||
result = copyNode(root)
|
result = copyNode(root)
|
||||||
addSon(result, copyTree(root.sons[0]))
|
addSon(result, copyTree(root.sons[0]))
|
||||||
flattenTreeAux(result, root, op)
|
flattenTreeAux(result, root, op)
|
||||||
else:
|
else:
|
||||||
result = root
|
result = root
|
||||||
|
|
||||||
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||||
var n = flattenTree(n)
|
var n = flattenTree(n)
|
||||||
let op = getMergeOp(n)
|
let op = getMergeOp(n)
|
||||||
let magic = getMagic(n)
|
let magic = getMagic(n)
|
||||||
if op != nil and op.magic != mNone and n.len >= 3:
|
if op != nil and op.magic != mNone and n.len >= 3:
|
||||||
result = newTransNode(nkCall, n, 0)
|
result = newTransNode(nkCall, n, 0)
|
||||||
add(result, transform(c, n.sons[0]))
|
add(result, transform(c, n.sons[0]))
|
||||||
var j = 1
|
var j = 1
|
||||||
while j < sonsLen(n):
|
while j < sonsLen(n):
|
||||||
var a = transform(c, n.sons[j]).PNode
|
var a = transform(c, n.sons[j]).PNode
|
||||||
inc(j)
|
inc(j)
|
||||||
if isConstExpr(a):
|
if isConstExpr(a):
|
||||||
while (j < sonsLen(n)):
|
while (j < sonsLen(n)):
|
||||||
let b = transform(c, n.sons[j]).PNode
|
let b = transform(c, n.sons[j]).PNode
|
||||||
if not isConstExpr(b): break
|
if not isConstExpr(b): break
|
||||||
|
|
@ -640,7 +640,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||||
proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
|
proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
|
||||||
# symbols that expand to a complex constant (array, etc.) should not be
|
# symbols that expand to a complex constant (array, etc.) should not be
|
||||||
# inlined, unless it's the empty array:
|
# inlined, unless it's the empty array:
|
||||||
result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
|
result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
|
||||||
cnst.len != 0
|
cnst.len != 0
|
||||||
|
|
||||||
proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
||||||
|
|
@ -673,11 +673,11 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
proc transform(c: PTransf, n: PNode): PTransNode =
|
proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
result = transformSym(c, n)
|
result = transformSym(c, n)
|
||||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
|
||||||
# nothing to be done for leaves:
|
# nothing to be done for leaves:
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
of nkBracketExpr: result = transformArrayAccess(c, n)
|
of nkBracketExpr: result = transformArrayAccess(c, n)
|
||||||
|
|
@ -702,7 +702,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
n.sons[bodyPos] = PNode(transform(c, s.getBody))
|
||||||
if n.kind == nkMethodDef: methodDef(s, false)
|
if n.kind == nkMethodDef: methodDef(s, false)
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
of nkForStmt:
|
of nkForStmt:
|
||||||
result = transformFor(c, n)
|
result = transformFor(c, n)
|
||||||
of nkParForStmt:
|
of nkParForStmt:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
|
|
@ -713,14 +713,14 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
add(result, PTransNode(newSymNode(labl)))
|
add(result, PTransNode(newSymNode(labl)))
|
||||||
of nkBreakStmt: result = transformBreak(c, n)
|
of nkBreakStmt: result = transformBreak(c, n)
|
||||||
of nkWhileStmt: result = transformWhile(c, n)
|
of nkWhileStmt: result = transformWhile(c, n)
|
||||||
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
|
||||||
nkCallStrLit:
|
nkCallStrLit:
|
||||||
result = transformCall(c, n)
|
result = transformCall(c, n)
|
||||||
of nkAddr, nkHiddenAddr:
|
of nkAddr, nkHiddenAddr:
|
||||||
result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
|
result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
|
||||||
of nkDerefExpr, nkHiddenDeref:
|
of nkDerefExpr, nkHiddenDeref:
|
||||||
result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
|
result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
result = transformConv(c, n)
|
result = transformConv(c, n)
|
||||||
of nkDiscardStmt:
|
of nkDiscardStmt:
|
||||||
result = PTransNode(n)
|
result = PTransNode(n)
|
||||||
|
|
@ -730,7 +730,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
# ensure that e.g. discard "some comment" gets optimized away
|
# ensure that e.g. discard "some comment" gets optimized away
|
||||||
# completely:
|
# completely:
|
||||||
result = PTransNode(newNode(nkCommentStmt))
|
result = PTransNode(newNode(nkCommentStmt))
|
||||||
of nkCommentStmt, nkTemplateDef:
|
of nkCommentStmt, nkTemplateDef:
|
||||||
return n.PTransNode
|
return n.PTransNode
|
||||||
of nkConstSection:
|
of nkConstSection:
|
||||||
# do not replace ``const c = 3`` with ``const 3 = 3``
|
# do not replace ``const c = 3`` with ``const 3 = 3``
|
||||||
|
|
@ -744,10 +744,10 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
result = transformVarSection(c, n)
|
result = transformVarSection(c, n)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of nkYieldStmt:
|
of nkYieldStmt:
|
||||||
if c.inlining > 0:
|
if c.inlining > 0:
|
||||||
result = transformYield(c, n)
|
result = transformYield(c, n)
|
||||||
else:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
of nkBlockStmt, nkBlockExpr:
|
of nkBlockStmt, nkBlockExpr:
|
||||||
result = transformBlock(c, n)
|
result = transformBlock(c, n)
|
||||||
|
|
@ -764,7 +764,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||||
if cnst != nil and not dontInlineConstant(n, cnst):
|
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||||
result = PTransNode(cnst) # do not miss an optimization
|
result = PTransNode(cnst) # do not miss an optimization
|
||||||
|
|
||||||
proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
||||||
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
|
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
|
||||||
# this step! We have to rely that the semantic pass transforms too errornous
|
# this step! We have to rely that the semantic pass transforms too errornous
|
||||||
# nodes into an empty node.
|
# nodes into an empty node.
|
||||||
|
|
@ -774,7 +774,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
||||||
popTransCon(c)
|
popTransCon(c)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
|
|
||||||
proc openTransf(module: PSym, filename: string): PTransf =
|
proc openTransf(module: PSym, filename: string): PTransf =
|
||||||
new(result)
|
new(result)
|
||||||
result.contSyms = @[]
|
result.contSyms = @[]
|
||||||
result.breakSyms = @[]
|
result.breakSyms = @[]
|
||||||
|
|
|
||||||
204
lib/system.nim
204
lib/system.nim
|
|
@ -89,7 +89,7 @@ type
|
||||||
SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32
|
SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32
|
||||||
## type class matching all ordinal types; however this includes enums with
|
## type class matching all ordinal types; however this includes enums with
|
||||||
## holes.
|
## holes.
|
||||||
|
|
||||||
SomeReal* = float|float32|float64
|
SomeReal* = float|float32|float64
|
||||||
## type class matching all floating point number types
|
## type class matching all floating point number types
|
||||||
|
|
||||||
|
|
@ -181,7 +181,7 @@ proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
|
||||||
## freeing the object. Note: The `finalizer` refers to the type `T`, not to
|
## freeing the object. Note: The `finalizer` refers to the type `T`, not to
|
||||||
## the object! This means that for each object of type `T` the finalizer
|
## the object! This means that for each object of type `T` the finalizer
|
||||||
## will be called!
|
## will be called!
|
||||||
|
|
||||||
proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
|
proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
|
||||||
## resets an object `obj` to its initial (binary zero) value. This needs to
|
## resets an object `obj` to its initial (binary zero) value. This needs to
|
||||||
## be called before any possible `object branch transition`:idx:.
|
## be called before any possible `object branch transition`:idx:.
|
||||||
|
|
@ -348,7 +348,7 @@ type
|
||||||
## This field is filled automatically in the
|
## This field is filled automatically in the
|
||||||
## ``raise`` statement.
|
## ``raise`` statement.
|
||||||
msg* {.exportc: "message".}: string ## the exception's message. Not
|
msg* {.exportc: "message".}: string ## the exception's message. Not
|
||||||
## providing an exception message
|
## providing an exception message
|
||||||
## is bad style.
|
## is bad style.
|
||||||
trace: string
|
trace: string
|
||||||
|
|
||||||
|
|
@ -483,7 +483,7 @@ type
|
||||||
|
|
||||||
E_Base: Exception, ESystem: SystemError, EIO: IOError,
|
E_Base: Exception, ESystem: SystemError, EIO: IOError,
|
||||||
EOS: OSError, EInvalidLibrary: LibraryError,
|
EOS: OSError, EInvalidLibrary: LibraryError,
|
||||||
EResourceExhausted: ResourceExhaustedError,
|
EResourceExhausted: ResourceExhaustedError,
|
||||||
EArithmetic: ArithmeticError, EDivByZero: DivByZeroError,
|
EArithmetic: ArithmeticError, EDivByZero: DivByZeroError,
|
||||||
EOverflow: OverflowError, EAccessViolation: AccessViolationError,
|
EOverflow: OverflowError, EAccessViolation: AccessViolationError,
|
||||||
EAssertionFailed: AssertionError, EInvalidValue: ValueError,
|
EAssertionFailed: AssertionError, EInvalidValue: ValueError,
|
||||||
|
|
@ -494,7 +494,7 @@ type
|
||||||
EInvalidObjectAssignment: ObjectAssignmentError,
|
EInvalidObjectAssignment: ObjectAssignmentError,
|
||||||
EInvalidObjectConversion: ObjectConversionError,
|
EInvalidObjectConversion: ObjectConversionError,
|
||||||
EDeadThread: DeadThreadError,
|
EDeadThread: DeadThreadError,
|
||||||
EFloatInexact: FloatInexactError,
|
EFloatInexact: FloatInexactError,
|
||||||
EFloatUnderflow: FloatUnderflowError,
|
EFloatUnderflow: FloatUnderflowError,
|
||||||
EFloatingPoint: FloatingPointError,
|
EFloatingPoint: FloatingPointError,
|
||||||
EFloatInvalidOp: FloatInvalidOpError,
|
EFloatInvalidOp: FloatInvalidOpError,
|
||||||
|
|
@ -511,11 +511,11 @@ proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.}
|
||||||
|
|
||||||
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
|
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
|
||||||
## unary ``<`` that can be used for nice looking excluding ranges:
|
## unary ``<`` that can be used for nice looking excluding ranges:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## for i in 0 .. <10: echo i
|
## for i in 0 .. <10: echo i
|
||||||
##
|
##
|
||||||
## Semantically this is the same as ``pred``.
|
## Semantically this is the same as ``pred``.
|
||||||
|
|
||||||
proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
|
proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
|
||||||
## returns the ``y``-th successor of the value ``x``. ``T`` has to be
|
## returns the ``y``-th successor of the value ``x``. ``T`` has to be
|
||||||
|
|
@ -536,7 +536,7 @@ proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.
|
||||||
## decrements the ordinal ``x`` by ``y``. If such a value does not
|
## decrements the ordinal ``x`` by ``y``. If such a value does not
|
||||||
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
|
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
|
||||||
## short notation for: ``x = pred(x, y)``.
|
## short notation for: ``x = pred(x, y)``.
|
||||||
|
|
||||||
proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
|
proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
|
||||||
## creates a new sequence of type ``seq[T]`` with length ``len``.
|
## creates a new sequence of type ``seq[T]`` with length ``len``.
|
||||||
## This is equivalent to ``s = @[]; setlen(s, len)``, but more
|
## This is equivalent to ``s = @[]; setlen(s, len)``, but more
|
||||||
|
|
@ -636,7 +636,7 @@ when not defined(JS):
|
||||||
|
|
||||||
proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
|
proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
|
||||||
## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
|
## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
|
||||||
## from `x`.
|
## from `x`.
|
||||||
proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
|
proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
|
||||||
## treats `x` as unsigned and converts it to an ``int16`` by taking the last
|
## treats `x` as unsigned and converts it to an ``int16`` by taking the last
|
||||||
## 16 bits from `x`.
|
## 16 bits from `x`.
|
||||||
|
|
@ -800,7 +800,7 @@ proc `%%` *(x, y: int64): int64 {.magic: "ModU", noSideEffect.}
|
||||||
## The result is truncated to fit into the result.
|
## The result is truncated to fit into the result.
|
||||||
## This implements modulo arithmetic.
|
## This implements modulo arithmetic.
|
||||||
## No overflow errors are possible.
|
## No overflow errors are possible.
|
||||||
|
|
||||||
proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
|
proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
|
||||||
proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
|
proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
|
||||||
## treats `x` and `y` as unsigned and compares them.
|
## treats `x` and `y` as unsigned and compares them.
|
||||||
|
|
@ -889,7 +889,7 @@ template `notin` * (x, y: expr): expr {.immediate, dirty.} = not contains(y, x)
|
||||||
|
|
||||||
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
|
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
|
||||||
## Checks if T is of the same type as S
|
## Checks if T is of the same type as S
|
||||||
##
|
##
|
||||||
## .. code-block:: Nim
|
## .. code-block:: Nim
|
||||||
## proc test[T](a: T): int =
|
## proc test[T](a: T): int =
|
||||||
## when (T is int):
|
## when (T is int):
|
||||||
|
|
@ -924,7 +924,7 @@ proc cmp*(x, y: string): int {.noSideEffect, procvar.}
|
||||||
proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
|
proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
|
||||||
magic: "ArrToSeq", nosideeffect.}
|
magic: "ArrToSeq", nosideeffect.}
|
||||||
## turns an array into a sequence. This most often useful for constructing
|
## turns an array into a sequence. This most often useful for constructing
|
||||||
## sequences with the array constructor: ``@[1, 2, 3]`` has the type
|
## sequences with the array constructor: ``@[1, 2, 3]`` has the type
|
||||||
## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
|
## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
|
||||||
|
|
||||||
proc setLen*[T](s: var seq[T], newlen: int) {.
|
proc setLen*[T](s: var seq[T], newlen: int) {.
|
||||||
|
|
@ -933,14 +933,14 @@ proc setLen*[T](s: var seq[T], newlen: int) {.
|
||||||
## ``T`` may be any sequence type.
|
## ``T`` may be any sequence type.
|
||||||
## If the current length is greater than the new length,
|
## If the current length is greater than the new length,
|
||||||
## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
|
## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
|
||||||
## a size, use ``newSeq`` instead.
|
## a size, use ``newSeq`` instead.
|
||||||
|
|
||||||
proc setLen*(s: var string, newlen: int) {.
|
proc setLen*(s: var string, newlen: int) {.
|
||||||
magic: "SetLengthStr", noSideEffect.}
|
magic: "SetLengthStr", noSideEffect.}
|
||||||
## sets the length of `s` to `newlen`.
|
## sets the length of `s` to `newlen`.
|
||||||
## If the current length is greater than the new length,
|
## If the current length is greater than the new length,
|
||||||
## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
|
## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
|
||||||
## a size, use ``newString`` instead.
|
## a size, use ``newString`` instead.
|
||||||
|
|
||||||
proc newString*(len: int): string {.
|
proc newString*(len: int): string {.
|
||||||
magic: "NewString", importc: "mnewString", noSideEffect.}
|
magic: "NewString", importc: "mnewString", noSideEffect.}
|
||||||
|
|
@ -953,7 +953,7 @@ proc newString*(len: int): string {.
|
||||||
proc newStringOfCap*(cap: int): string {.
|
proc newStringOfCap*(cap: int): string {.
|
||||||
magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
|
magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
|
||||||
## returns a new string of length ``0`` but with capacity `cap`.This
|
## returns a new string of length ``0`` but with capacity `cap`.This
|
||||||
## procedure exists only for optimization purposes; the same effect can
|
## procedure exists only for optimization purposes; the same effect can
|
||||||
## be achieved with the ``&`` operator or with ``add``.
|
## be achieved with the ``&`` operator or with ``add``.
|
||||||
|
|
||||||
proc `&` * (x: string, y: char): string {.
|
proc `&` * (x: string, y: char): string {.
|
||||||
|
|
@ -982,7 +982,7 @@ proc `&` * (x: char, y: string): string {.
|
||||||
## assert('a' & "bc" == "abc")
|
## assert('a' & "bc" == "abc")
|
||||||
|
|
||||||
# implementation note: These must all have the same magic value "ConStrStr" so
|
# implementation note: These must all have the same magic value "ConStrStr" so
|
||||||
# that the merge optimization works properly.
|
# that the merge optimization works properly.
|
||||||
|
|
||||||
proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
|
proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
|
||||||
## Appends `y` to `x` in place
|
## Appends `y` to `x` in place
|
||||||
|
|
@ -1039,15 +1039,15 @@ proc compileOption*(option: string): bool {.
|
||||||
## can be used to determine an on|off compile-time option. Example:
|
## can be used to determine an on|off compile-time option. Example:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## when compileOption("floatchecks"):
|
## when compileOption("floatchecks"):
|
||||||
## echo "compiled with floating point NaN and Inf checks"
|
## echo "compiled with floating point NaN and Inf checks"
|
||||||
|
|
||||||
proc compileOption*(option, arg: string): bool {.
|
proc compileOption*(option, arg: string): bool {.
|
||||||
magic: "CompileOptionArg", noSideEffect.}
|
magic: "CompileOptionArg", noSideEffect.}
|
||||||
## can be used to determine an enum compile-time option. Example:
|
## can be used to determine an enum compile-time option. Example:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## when compileOption("opt", "size") and compileOption("gc", "boehm"):
|
## when compileOption("opt", "size") and compileOption("gc", "boehm"):
|
||||||
## echo "compiled with optimization for size and uses Boehm's GC"
|
## echo "compiled with optimization for size and uses Boehm's GC"
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -1056,16 +1056,16 @@ const
|
||||||
taintMode = compileOption("taintmode")
|
taintMode = compileOption("taintmode")
|
||||||
|
|
||||||
when taintMode:
|
when taintMode:
|
||||||
type TaintedString* = distinct string ## a distinct string type that
|
type TaintedString* = distinct string ## a distinct string type that
|
||||||
## is `tainted`:idx:. It is an alias for
|
## is `tainted`:idx:. It is an alias for
|
||||||
## ``string`` if the taint mode is not
|
## ``string`` if the taint mode is not
|
||||||
## turned on. Use the ``-d:taintMode``
|
## turned on. Use the ``-d:taintMode``
|
||||||
## command line switch to turn the taint
|
## command line switch to turn the taint
|
||||||
## mode on.
|
## mode on.
|
||||||
|
|
||||||
proc len*(s: TaintedString): int {.borrow.}
|
proc len*(s: TaintedString): int {.borrow.}
|
||||||
else:
|
else:
|
||||||
type TaintedString* = string ## a distinct string type that
|
type TaintedString* = string ## a distinct string type that
|
||||||
## is `tainted`:idx:. It is an alias for
|
## is `tainted`:idx:. It is an alias for
|
||||||
## ``string`` if the taint mode is not
|
## ``string`` if the taint mode is not
|
||||||
## turned on. Use the ``-d:taintMode``
|
## turned on. Use the ``-d:taintMode``
|
||||||
|
|
@ -1136,25 +1136,25 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
|
||||||
proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
|
proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
|
||||||
## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
|
## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
|
||||||
## only changes the semantics for sequences and strings (and types which
|
## only changes the semantics for sequences and strings (and types which
|
||||||
## contain those). Be careful with the changed semantics though! There
|
## contain those). Be careful with the changed semantics though! There
|
||||||
## is a reason why the default assignment does a deep copy of sequences
|
## is a reason why the default assignment does a deep copy of sequences
|
||||||
## and strings.
|
## and strings.
|
||||||
|
|
||||||
proc del*[T](x: var seq[T], i: int) {.noSideEffect.} =
|
proc del*[T](x: var seq[T], i: int) {.noSideEffect.} =
|
||||||
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
|
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
|
||||||
## This is an O(1) operation.
|
## This is an O(1) operation.
|
||||||
let xl = x.len
|
let xl = x.len
|
||||||
shallowCopy(x[i], x[xl-1])
|
shallowCopy(x[i], x[xl-1])
|
||||||
setLen(x, xl-1)
|
setLen(x, xl-1)
|
||||||
|
|
||||||
proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} =
|
proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} =
|
||||||
## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
|
## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
|
||||||
## This is an O(n) operation.
|
## This is an O(n) operation.
|
||||||
let xl = x.len
|
let xl = x.len
|
||||||
for j in i..xl-2: shallowCopy(x[j], x[j+1])
|
for j in i..xl-2: shallowCopy(x[j], x[j+1])
|
||||||
setLen(x, xl-1)
|
setLen(x, xl-1)
|
||||||
|
|
||||||
proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} =
|
proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} =
|
||||||
## inserts `item` into `x` at position `i`.
|
## inserts `item` into `x` at position `i`.
|
||||||
let xl = x.len
|
let xl = x.len
|
||||||
setLen(x, xl+1)
|
setLen(x, xl+1)
|
||||||
|
|
@ -1233,7 +1233,7 @@ type # these work for most platforms:
|
||||||
## This is binary compatible to the type ``char**`` in *C*. The array's
|
## This is binary compatible to the type ``char**`` in *C*. The array's
|
||||||
## high value is large enough to disable bounds checking in practice.
|
## high value is large enough to disable bounds checking in practice.
|
||||||
## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
|
## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
|
||||||
|
|
||||||
PFloat32* = ptr float32 ## an alias for ``ptr float32``
|
PFloat32* = ptr float32 ## an alias for ``ptr float32``
|
||||||
PFloat64* = ptr float64 ## an alias for ``ptr float64``
|
PFloat64* = ptr float64 ## an alias for ``ptr float64``
|
||||||
PInt64* = ptr int64 ## an alias for ``ptr int64``
|
PInt64* = ptr int64 ## an alias for ``ptr int64``
|
||||||
|
|
@ -1280,7 +1280,7 @@ proc addQuitProc*(QuitProc: proc() {.noconv.}) {.
|
||||||
proc copy*(s: string, first = 0): string {.
|
proc copy*(s: string, first = 0): string {.
|
||||||
magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.}
|
magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.}
|
||||||
proc copy*(s: string, first, last: int): string {.
|
proc copy*(s: string, first, last: int): string {.
|
||||||
magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
|
magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
|
||||||
deprecated.}
|
deprecated.}
|
||||||
## copies a slice of `s` into a new string and returns this new
|
## copies a slice of `s` into a new string and returns this new
|
||||||
## string. The bounds `first` and `last` denote the indices of
|
## string. The bounds `first` and `last` denote the indices of
|
||||||
|
|
@ -1358,7 +1358,7 @@ when not defined(nimrodVM):
|
||||||
## The allocated memory belongs to its allocating thread!
|
## The allocated memory belongs to its allocating thread!
|
||||||
## Use `createShared` to allocate from a shared heap.
|
## Use `createShared` to allocate from a shared heap.
|
||||||
cast[ptr T](alloc0(T.sizeof * size))
|
cast[ptr T](alloc0(T.sizeof * size))
|
||||||
proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [],
|
proc realloc*(p: pointer, newSize: int): pointer {.noconv, rtl, tags: [],
|
||||||
benign.}
|
benign.}
|
||||||
## grows or shrinks a given memory block. If p is **nil** then a new
|
## grows or shrinks a given memory block. If p is **nil** then a new
|
||||||
## memory block is returned. In either way the block has at least
|
## memory block is returned. In either way the block has at least
|
||||||
|
|
@ -1381,7 +1381,7 @@ when not defined(nimrodVM):
|
||||||
## ``realloc``. This procedure is dangerous! If one forgets to
|
## ``realloc``. This procedure is dangerous! If one forgets to
|
||||||
## free the memory a leak occurs; if one tries to access freed
|
## free the memory a leak occurs; if one tries to access freed
|
||||||
## memory (or just freeing it twice!) a core dump may happen
|
## memory (or just freeing it twice!) a core dump may happen
|
||||||
## or other memory may be corrupted.
|
## or other memory may be corrupted.
|
||||||
## The freed memory must belong to its allocating thread!
|
## The freed memory must belong to its allocating thread!
|
||||||
## Use `deallocShared` to deallocate from a shared heap.
|
## Use `deallocShared` to deallocate from a shared heap.
|
||||||
proc free*[T](p: ptr T) {.inline, benign.} =
|
proc free*[T](p: ptr T) {.inline, benign.} =
|
||||||
|
|
@ -1390,30 +1390,30 @@ when not defined(nimrodVM):
|
||||||
## allocates a new memory block on the shared heap with at
|
## allocates a new memory block on the shared heap with at
|
||||||
## least ``size`` bytes. The block has to be freed with
|
## least ``size`` bytes. The block has to be freed with
|
||||||
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
|
## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
|
||||||
## is not initialized, so reading from it before writing to it is
|
## is not initialized, so reading from it before writing to it is
|
||||||
## undefined behaviour!
|
## undefined behaviour!
|
||||||
proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline,
|
proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline,
|
||||||
benign.} =
|
benign.} =
|
||||||
## allocates a new memory block on the shared heap with at
|
## allocates a new memory block on the shared heap with at
|
||||||
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
||||||
## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
|
## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
|
||||||
## is not initialized, so reading from it before writing to it is
|
## is not initialized, so reading from it before writing to it is
|
||||||
## undefined behaviour!
|
## undefined behaviour!
|
||||||
cast[ptr T](allocShared(T.sizeof * size))
|
cast[ptr T](allocShared(T.sizeof * size))
|
||||||
proc allocShared0*(size: int): pointer {.noconv, rtl, benign.}
|
proc allocShared0*(size: int): pointer {.noconv, rtl, benign.}
|
||||||
## allocates a new memory block on the shared heap with at
|
## allocates a new memory block on the shared heap with at
|
||||||
## least ``size`` bytes. The block has to be freed with
|
## least ``size`` bytes. The block has to be freed with
|
||||||
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
|
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
|
||||||
## The block is initialized with all bytes
|
## The block is initialized with all bytes
|
||||||
## containing zero, so it is somewhat safer than ``allocShared``.
|
## containing zero, so it is somewhat safer than ``allocShared``.
|
||||||
proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
|
proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
|
||||||
## allocates a new memory block on the shared heap with at
|
## allocates a new memory block on the shared heap with at
|
||||||
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
## least ``T.sizeof * size`` bytes. The block has to be freed with
|
||||||
## ``resizeShared(block, 0)`` or ``freeShared(block)``.
|
## ``resizeShared(block, 0)`` or ``freeShared(block)``.
|
||||||
## The block is initialized with all bytes
|
## The block is initialized with all bytes
|
||||||
## containing zero, so it is somewhat safer than ``createSharedU``.
|
## containing zero, so it is somewhat safer than ``createSharedU``.
|
||||||
cast[ptr T](allocShared0(T.sizeof * size))
|
cast[ptr T](allocShared0(T.sizeof * size))
|
||||||
proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl,
|
proc reallocShared*(p: pointer, newSize: int): pointer {.noconv, rtl,
|
||||||
benign.}
|
benign.}
|
||||||
## grows or shrinks a given memory block on the heap. If p is **nil**
|
## grows or shrinks a given memory block on the heap. If p is **nil**
|
||||||
## then a new memory block is returned. In either way the block has at
|
## then a new memory block is returned. In either way the block has at
|
||||||
|
|
@ -1525,7 +1525,7 @@ const
|
||||||
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||||
## is the version of Nim as a string.
|
## is the version of Nim as a string.
|
||||||
|
|
||||||
{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
|
{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
|
||||||
NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
|
NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
|
||||||
|
|
||||||
# GC interface:
|
# GC interface:
|
||||||
|
|
@ -1805,7 +1805,7 @@ proc `==` *[I, T](x, y: array[I, T]): bool =
|
||||||
return
|
return
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc `@`*[T](a: openArray[T]): seq[T] =
|
proc `@`*[T](a: openArray[T]): seq[T] =
|
||||||
## turns an openarray into a sequence. This is not as efficient as turning
|
## turns an openarray into a sequence. This is not as efficient as turning
|
||||||
## a fixed length array into a sequence as it always copies every element
|
## a fixed length array into a sequence as it always copies every element
|
||||||
## of `a`.
|
## of `a`.
|
||||||
|
|
@ -1853,7 +1853,7 @@ when not defined(NimrodVM):
|
||||||
else:
|
else:
|
||||||
proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} =
|
proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} =
|
||||||
asm """return `x`"""
|
asm """return `x`"""
|
||||||
|
|
||||||
proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
|
proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
|
||||||
## Generic equals operator for sequences: relies on a equals operator for
|
## Generic equals operator for sequences: relies on a equals operator for
|
||||||
## the element type `T`.
|
## the element type `T`.
|
||||||
|
|
@ -1879,7 +1879,7 @@ proc contains*[T](a: openArray[T], item: T): bool {.inline.}=
|
||||||
## for ``find(a, item) >= 0``.
|
## for ``find(a, item) >= 0``.
|
||||||
return find(a, item) >= 0
|
return find(a, item) >= 0
|
||||||
|
|
||||||
proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
|
proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
|
||||||
## returns the last item of `s` and decreases ``s.len`` by one. This treats
|
## returns the last item of `s` and decreases ``s.len`` by one. This treats
|
||||||
## `s` as a stack and implements the common *pop* operation.
|
## `s` as a stack and implements the common *pop* operation.
|
||||||
var L = s.len-1
|
var L = s.len-1
|
||||||
|
|
@ -1941,7 +1941,7 @@ iterator fields*[T: tuple|object](x: T): RootObj {.
|
||||||
iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {.
|
iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {.
|
||||||
magic: "Fields", noSideEffect.}
|
magic: "Fields", noSideEffect.}
|
||||||
## iterates over every field of `x` and `y`.
|
## iterates over every field of `x` and `y`.
|
||||||
## Warning: This is really transforms the 'for' and unrolls the loop.
|
## Warning: This is really transforms the 'for' and unrolls the loop.
|
||||||
## The current implementation also has a bug that affects symbol binding
|
## The current implementation also has a bug that affects symbol binding
|
||||||
## in the loop body.
|
## in the loop body.
|
||||||
iterator fieldPairs*[T: tuple|object](x: T): RootObj {.
|
iterator fieldPairs*[T: tuple|object](x: T): RootObj {.
|
||||||
|
|
@ -1982,18 +1982,18 @@ iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
|
||||||
a, b: expr] {.
|
a, b: expr] {.
|
||||||
magic: "FieldPairs", noSideEffect.}
|
magic: "FieldPairs", noSideEffect.}
|
||||||
## iterates over every field of `x` and `y`.
|
## iterates over every field of `x` and `y`.
|
||||||
## Warning: This really transforms the 'for' and unrolls the loop.
|
## Warning: This really transforms the 'for' and unrolls the loop.
|
||||||
## The current implementation also has a bug that affects symbol binding
|
## The current implementation also has a bug that affects symbol binding
|
||||||
## in the loop body.
|
## in the loop body.
|
||||||
|
|
||||||
proc `==`*[T: tuple|object](x, y: T): bool =
|
proc `==`*[T: tuple|object](x, y: T): bool =
|
||||||
## generic ``==`` operator for tuples that is lifted from the components
|
## generic ``==`` operator for tuples that is lifted from the components
|
||||||
## of `x` and `y`.
|
## of `x` and `y`.
|
||||||
for a, b in fields(x, y):
|
for a, b in fields(x, y):
|
||||||
if a != b: return false
|
if a != b: return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc `<=`*[T: tuple](x, y: T): bool =
|
proc `<=`*[T: tuple](x, y: T): bool =
|
||||||
## generic ``<=`` operator for tuples that is lifted from the components
|
## generic ``<=`` operator for tuples that is lifted from the components
|
||||||
## of `x` and `y`. This implementation uses `cmp`.
|
## of `x` and `y`. This implementation uses `cmp`.
|
||||||
for a, b in fields(x, y):
|
for a, b in fields(x, y):
|
||||||
|
|
@ -2002,7 +2002,7 @@ proc `<=`*[T: tuple](x, y: T): bool =
|
||||||
if c > 0: return false
|
if c > 0: return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc `<`*[T: tuple](x, y: T): bool =
|
proc `<`*[T: tuple](x, y: T): bool =
|
||||||
## generic ``<`` operator for tuples that is lifted from the components
|
## generic ``<`` operator for tuples that is lifted from the components
|
||||||
## of `x` and `y`. This implementation uses `cmp`.
|
## of `x` and `y`. This implementation uses `cmp`.
|
||||||
for a, b in fields(x, y):
|
for a, b in fields(x, y):
|
||||||
|
|
@ -2011,7 +2011,7 @@ proc `<`*[T: tuple](x, y: T): bool =
|
||||||
if c > 0: return false
|
if c > 0: return false
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc `$`*[T: tuple|object](x: T): string =
|
proc `$`*[T: tuple|object](x: T): string =
|
||||||
## generic ``$`` operator for tuples that is lifted from the components
|
## generic ``$`` operator for tuples that is lifted from the components
|
||||||
## of `x`. Example:
|
## of `x`. Example:
|
||||||
##
|
##
|
||||||
|
|
@ -2021,13 +2021,13 @@ proc `$`*[T: tuple|object](x: T): string =
|
||||||
result = "("
|
result = "("
|
||||||
var firstElement = true
|
var firstElement = true
|
||||||
for name, value in fieldPairs(x):
|
for name, value in fieldPairs(x):
|
||||||
if not(firstElement): result.add(", ")
|
if not firstElement: result.add(", ")
|
||||||
result.add(name)
|
result.add(name)
|
||||||
result.add(": ")
|
result.add(": ")
|
||||||
result.add($value)
|
result.add($value)
|
||||||
firstElement = false
|
firstElement = false
|
||||||
result.add(")")
|
result.add(")")
|
||||||
|
|
||||||
proc collectionToString[T](x: T, b, e: string): string =
|
proc collectionToString[T](x: T, b, e: string): string =
|
||||||
result = b
|
result = b
|
||||||
var firstElement = true
|
var firstElement = true
|
||||||
|
|
@ -2037,7 +2037,7 @@ proc collectionToString[T](x: T, b, e: string): string =
|
||||||
firstElement = false
|
firstElement = false
|
||||||
result.add(e)
|
result.add(e)
|
||||||
|
|
||||||
proc `$`*[T](x: set[T]): string =
|
proc `$`*[T](x: set[T]): string =
|
||||||
## generic ``$`` operator for sets that is lifted from the components
|
## generic ``$`` operator for sets that is lifted from the components
|
||||||
## of `x`. Example:
|
## of `x`. Example:
|
||||||
##
|
##
|
||||||
|
|
@ -2045,7 +2045,7 @@ proc `$`*[T](x: set[T]): string =
|
||||||
## ${23, 45} == "{23, 45}"
|
## ${23, 45} == "{23, 45}"
|
||||||
collectionToString(x, "{", "}")
|
collectionToString(x, "{", "}")
|
||||||
|
|
||||||
proc `$`*[T](x: seq[T]): string =
|
proc `$`*[T](x: seq[T]): string =
|
||||||
## generic ``$`` operator for seqs that is lifted from the components
|
## generic ``$`` operator for seqs that is lifted from the components
|
||||||
## of `x`. Example:
|
## of `x`. Example:
|
||||||
##
|
##
|
||||||
|
|
@ -2056,7 +2056,7 @@ proc `$`*[T](x: seq[T]): string =
|
||||||
when false:
|
when false:
|
||||||
# causes bootstrapping to fail as we use array of chars and cstring should
|
# causes bootstrapping to fail as we use array of chars and cstring should
|
||||||
# match better ...
|
# match better ...
|
||||||
proc `$`*[T, IDX](x: array[IDX, T]): string =
|
proc `$`*[T, IDX](x: array[IDX, T]): string =
|
||||||
collectionToString(x, "[", "]")
|
collectionToString(x, "[", "]")
|
||||||
|
|
||||||
# ----------------- GC interface ---------------------------------------------
|
# ----------------- GC interface ---------------------------------------------
|
||||||
|
|
@ -2098,14 +2098,14 @@ when not defined(nimrodVM) and hostOS != "standalone":
|
||||||
proc GC_getStatistics*(): string {.rtl, benign.}
|
proc GC_getStatistics*(): string {.rtl, benign.}
|
||||||
## returns an informative string about the GC's activity. This may be useful
|
## returns an informative string about the GC's activity. This may be useful
|
||||||
## for tweaking.
|
## for tweaking.
|
||||||
|
|
||||||
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
|
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
|
||||||
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
|
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
|
||||||
proc GC_ref*(x: string) {.magic: "GCref", benign.}
|
proc GC_ref*(x: string) {.magic: "GCref", benign.}
|
||||||
## marks the object `x` as referenced, so that it will not be freed until
|
## marks the object `x` as referenced, so that it will not be freed until
|
||||||
## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
|
## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
|
||||||
## n calls to `GC_unref` are needed to unmark `x`.
|
## n calls to `GC_unref` are needed to unmark `x`.
|
||||||
|
|
||||||
proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
|
proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
|
||||||
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
|
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
|
||||||
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
||||||
|
|
@ -2141,19 +2141,19 @@ var
|
||||||
## application code should never set this hook! You better know what you
|
## application code should never set this hook! You better know what you
|
||||||
## do when setting this. If ``localRaiseHook`` returns false, the exception
|
## do when setting this. If ``localRaiseHook`` returns false, the exception
|
||||||
## is caught and does not propagate further through the call stack.
|
## is caught and does not propagate further through the call stack.
|
||||||
|
|
||||||
outOfMemHook*: proc () {.nimcall, tags: [], benign.}
|
outOfMemHook*: proc () {.nimcall, tags: [], benign.}
|
||||||
## set this variable to provide a procedure that should be called
|
## set this variable to provide a procedure that should be called
|
||||||
## in case of an `out of memory`:idx: event. The standard handler
|
## in case of an `out of memory`:idx: event. The standard handler
|
||||||
## writes an error message and terminates the program. `outOfMemHook` can
|
## writes an error message and terminates the program. `outOfMemHook` can
|
||||||
## be used to raise an exception in case of OOM like so:
|
## be used to raise an exception in case of OOM like so:
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
##
|
##
|
||||||
## var gOutOfMem: ref EOutOfMemory
|
## var gOutOfMem: ref EOutOfMemory
|
||||||
## new(gOutOfMem) # need to be allocated *before* OOM really happened!
|
## new(gOutOfMem) # need to be allocated *before* OOM really happened!
|
||||||
## gOutOfMem.msg = "out of memory"
|
## gOutOfMem.msg = "out of memory"
|
||||||
##
|
##
|
||||||
## proc handleOOM() =
|
## proc handleOOM() =
|
||||||
## raise gOutOfMem
|
## raise gOutOfMem
|
||||||
##
|
##
|
||||||
|
|
@ -2210,7 +2210,7 @@ proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect],
|
||||||
## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_
|
## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_
|
||||||
## instead.
|
## instead.
|
||||||
|
|
||||||
proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect,
|
proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect,
|
||||||
tags: [], raises: [].}
|
tags: [], raises: [].}
|
||||||
## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho``
|
## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho``
|
||||||
## pretends to be free of side effects, so that it can be used for debugging
|
## pretends to be free of side effects, so that it can be used for debugging
|
||||||
|
|
@ -2262,7 +2262,7 @@ proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} =
|
||||||
proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} =
|
proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} =
|
||||||
if x < 0: -x else: x
|
if x < 0: -x else: x
|
||||||
proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} =
|
proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} =
|
||||||
## returns the absolute value of `x`. If `x` is ``low(x)`` (that
|
## returns the absolute value of `x`. If `x` is ``low(x)`` (that
|
||||||
## is -MININT for its type), an overflow exception is thrown (if overflow
|
## is -MININT for its type), an overflow exception is thrown (if overflow
|
||||||
## checking is turned on).
|
## checking is turned on).
|
||||||
if x < 0: -x else: x
|
if x < 0: -x else: x
|
||||||
|
|
@ -2318,14 +2318,14 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
# we use binary mode in Windows:
|
# we use binary mode in Windows:
|
||||||
setmode(fileno(c_stdin), O_BINARY)
|
setmode(fileno(c_stdin), O_BINARY)
|
||||||
setmode(fileno(c_stdout), O_BINARY)
|
setmode(fileno(c_stdout), O_BINARY)
|
||||||
|
|
||||||
when defined(endb):
|
when defined(endb):
|
||||||
proc endbStep()
|
proc endbStep()
|
||||||
|
|
||||||
# ----------------- IO Part ------------------------------------------------
|
# ----------------- IO Part ------------------------------------------------
|
||||||
when hostOS != "standalone":
|
when hostOS != "standalone":
|
||||||
type
|
type
|
||||||
CFile {.importc: "FILE", header: "<stdio.h>",
|
CFile {.importc: "FILE", header: "<stdio.h>",
|
||||||
final, incompletestruct.} = object
|
final, incompletestruct.} = object
|
||||||
File* = ptr CFile ## The type representing a file handle.
|
File* = ptr CFile ## The type representing a file handle.
|
||||||
|
|
||||||
|
|
@ -2375,9 +2375,9 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## Creates a ``TFile`` from a `filehandle` with given `mode`.
|
## Creates a ``TFile`` from a `filehandle` with given `mode`.
|
||||||
##
|
##
|
||||||
## Default mode is readonly. Returns true iff the file could be opened.
|
## Default mode is readonly. Returns true iff the file could be opened.
|
||||||
|
|
||||||
proc open*(filename: string,
|
proc open*(filename: string,
|
||||||
mode: FileMode = fmRead, bufSize: int = -1): File =
|
mode: FileMode = fmRead, bufSize: int = -1): File =
|
||||||
## Opens a file named `filename` with given `mode`.
|
## Opens a file named `filename` with given `mode`.
|
||||||
##
|
##
|
||||||
## Default mode is readonly. Raises an ``IO`` exception if the file
|
## Default mode is readonly. Raises an ``IO`` exception if the file
|
||||||
|
|
@ -2387,7 +2387,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
|
|
||||||
proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
|
proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
|
||||||
tags: [], benign.}
|
tags: [], benign.}
|
||||||
## reopens the file `f` with given `filename` and `mode`. This
|
## reopens the file `f` with given `filename` and `mode`. This
|
||||||
## is often used to redirect the `stdin`, `stdout` or `stderr`
|
## is often used to redirect the `stdin`, `stdout` or `stderr`
|
||||||
## file variables.
|
## file variables.
|
||||||
##
|
##
|
||||||
|
|
@ -2398,7 +2398,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
|
|
||||||
proc endOfFile*(f: File): bool {.tags: [], benign.}
|
proc endOfFile*(f: File): bool {.tags: [], benign.}
|
||||||
## Returns true iff `f` is at the end.
|
## Returns true iff `f` is at the end.
|
||||||
|
|
||||||
proc readChar*(f: File): char {.
|
proc readChar*(f: File): char {.
|
||||||
importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
|
importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
|
||||||
## Reads a single character from the stream `f`.
|
## Reads a single character from the stream `f`.
|
||||||
|
|
@ -2411,7 +2411,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
##
|
##
|
||||||
## Raises an IO exception in case of an error. It is an error if the
|
## Raises an IO exception in case of an error. It is an error if the
|
||||||
## current file position is not at the beginning of the file.
|
## current file position is not at the beginning of the file.
|
||||||
|
|
||||||
proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
|
proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
|
||||||
## Opens a file named `filename` for reading.
|
## Opens a file named `filename` for reading.
|
||||||
##
|
##
|
||||||
|
|
@ -2440,8 +2440,8 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## reads a line of text from the file `f`. May throw an IO exception.
|
## reads a line of text from the file `f`. May throw an IO exception.
|
||||||
## A line of text may be delimited by ``CR``, ``LF`` or
|
## A line of text may be delimited by ``CR``, ``LF`` or
|
||||||
## ``CRLF``. The newline character(s) are not part of the returned string.
|
## ``CRLF``. The newline character(s) are not part of the returned string.
|
||||||
|
|
||||||
proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
|
proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
|
||||||
benign.}
|
benign.}
|
||||||
## reads a line of text from the file `f` into `line`. `line` must not be
|
## reads a line of text from the file `f` into `line`. `line` must not be
|
||||||
## ``nil``! May throw an IO exception.
|
## ``nil``! May throw an IO exception.
|
||||||
|
|
@ -2450,7 +2450,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## Returns ``false`` if the end of the file has been reached, ``true``
|
## Returns ``false`` if the end of the file has been reached, ``true``
|
||||||
## otherwise. If ``false`` is returned `line` contains no new data.
|
## otherwise. If ``false`` is returned `line` contains no new data.
|
||||||
|
|
||||||
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
|
||||||
tags: [WriteIOEffect], benign.}
|
tags: [WriteIOEffect], benign.}
|
||||||
## writes the values `x` to `f` and then writes "\n".
|
## writes the values `x` to `f` and then writes "\n".
|
||||||
## May throw an IO exception.
|
## May throw an IO exception.
|
||||||
|
|
@ -2544,11 +2544,11 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
dealloc(a)
|
dealloc(a)
|
||||||
|
|
||||||
when not defined(NimrodVM):
|
when not defined(NimrodVM):
|
||||||
proc atomicInc*(memLoc: var int, x: int = 1): int {.inline,
|
proc atomicInc*(memLoc: var int, x: int = 1): int {.inline,
|
||||||
discardable, benign.}
|
discardable, benign.}
|
||||||
## atomic increment of `memLoc`. Returns the value after the operation.
|
## atomic increment of `memLoc`. Returns the value after the operation.
|
||||||
|
|
||||||
proc atomicDec*(memLoc: var int, x: int = 1): int {.inline,
|
proc atomicDec*(memLoc: var int, x: int = 1): int {.inline,
|
||||||
discardable, benign.}
|
discardable, benign.}
|
||||||
## atomic decrement of `memLoc`. Returns the value after the operation.
|
## atomic decrement of `memLoc`. Returns the value after the operation.
|
||||||
|
|
||||||
|
|
@ -2562,7 +2562,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
context: C_JmpBuf
|
context: C_JmpBuf
|
||||||
hasRaiseAction: bool
|
hasRaiseAction: bool
|
||||||
raiseAction: proc (e: ref Exception): bool {.closure.}
|
raiseAction: proc (e: ref Exception): bool {.closure.}
|
||||||
|
|
||||||
when declared(initAllocator):
|
when declared(initAllocator):
|
||||||
initAllocator()
|
initAllocator()
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
|
|
@ -2576,7 +2576,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
proc setControlCHook*(hook: proc () {.noconv.} not nil)
|
proc setControlCHook*(hook: proc () {.noconv.} not nil)
|
||||||
## allows you to override the behaviour of your application when CTRL+C
|
## allows you to override the behaviour of your application when CTRL+C
|
||||||
## is pressed. Only one such hook is supported.
|
## is pressed. Only one such hook is supported.
|
||||||
|
|
||||||
proc writeStackTrace*() {.tags: [WriteIOEffect].}
|
proc writeStackTrace*() {.tags: [WriteIOEffect].}
|
||||||
## writes the current stack trace to ``stderr``. This is only works
|
## writes the current stack trace to ``stderr``. This is only works
|
||||||
## for debug builds.
|
## for debug builds.
|
||||||
|
|
@ -2587,20 +2587,20 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
proc getStackTrace*(e: ref Exception): string
|
proc getStackTrace*(e: ref Exception): string
|
||||||
## gets the stack trace associated with `e`, which is the stack that
|
## gets the stack trace associated with `e`, which is the stack that
|
||||||
## lead to the ``raise`` statement. This only works for debug builds.
|
## lead to the ``raise`` statement. This only works for debug builds.
|
||||||
|
|
||||||
{.push stack_trace: off, profiler:off.}
|
{.push stack_trace: off, profiler:off.}
|
||||||
when hostOS == "standalone":
|
when hostOS == "standalone":
|
||||||
include "system/embedded"
|
include "system/embedded"
|
||||||
else:
|
else:
|
||||||
include "system/excpt"
|
include "system/excpt"
|
||||||
include "system/chcks"
|
include "system/chcks"
|
||||||
|
|
||||||
# we cannot compile this with stack tracing on
|
# we cannot compile this with stack tracing on
|
||||||
# as it would recurse endlessly!
|
# as it would recurse endlessly!
|
||||||
include "system/arithm"
|
include "system/arithm"
|
||||||
{.pop.} # stack trace
|
{.pop.} # stack trace
|
||||||
{.pop.} # stack trace
|
{.pop.} # stack trace
|
||||||
|
|
||||||
when hostOS != "standalone" and not defined(NimrodVM):
|
when hostOS != "standalone" and not defined(NimrodVM):
|
||||||
include "system/dyncalls"
|
include "system/dyncalls"
|
||||||
when not defined(NimrodVM):
|
when not defined(NimrodVM):
|
||||||
|
|
@ -2608,7 +2608,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
|
|
||||||
const
|
const
|
||||||
GenericSeqSize = (2 * sizeof(int))
|
GenericSeqSize = (2 * sizeof(int))
|
||||||
|
|
||||||
proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
|
proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
|
||||||
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
|
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
|
||||||
var d: int
|
var d: int
|
||||||
|
|
@ -2728,7 +2728,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## process(value)
|
## process(value)
|
||||||
## else:
|
## else:
|
||||||
## echo "Value too big!"
|
## echo "Value too big!"
|
||||||
|
|
||||||
proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
|
proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
|
||||||
## Hints the optimizer that `val` is likely going to be false.
|
## Hints the optimizer that `val` is likely going to be false.
|
||||||
##
|
##
|
||||||
|
|
@ -2742,7 +2742,7 @@ when not defined(JS): #and not defined(NimrodVM):
|
||||||
## echo "Value too big!"
|
## echo "Value too big!"
|
||||||
## else:
|
## else:
|
||||||
## process(value)
|
## process(value)
|
||||||
|
|
||||||
proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
|
proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
|
||||||
## retrieves the raw proc pointer of the closure `x`. This is
|
## retrieves the raw proc pointer of the closure `x`. This is
|
||||||
## useful for interfacing closures with C.
|
## useful for interfacing closures with C.
|
||||||
|
|
@ -2774,7 +2774,7 @@ elif defined(JS):
|
||||||
proc GC_enableMarkAndSweep() = discard
|
proc GC_enableMarkAndSweep() = discard
|
||||||
proc GC_disableMarkAndSweep() = discard
|
proc GC_disableMarkAndSweep() = discard
|
||||||
proc GC_getStatistics(): string = return ""
|
proc GC_getStatistics(): string = return ""
|
||||||
|
|
||||||
proc getOccupiedMem(): int = return -1
|
proc getOccupiedMem(): int = return -1
|
||||||
proc getFreeMem(): int = return -1
|
proc getFreeMem(): int = return -1
|
||||||
proc getTotalMem(): int = return -1
|
proc getTotalMem(): int = return -1
|
||||||
|
|
@ -2797,7 +2797,7 @@ elif defined(JS):
|
||||||
if x == y: return 0
|
if x == y: return 0
|
||||||
if x < y: return -1
|
if x < y: return -1
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
when defined(nimffi):
|
when defined(nimffi):
|
||||||
include "system/sysio"
|
include "system/sysio"
|
||||||
|
|
||||||
|
|
@ -2831,14 +2831,14 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
|
||||||
# cut down:
|
# cut down:
|
||||||
setLen(s, newLen)
|
setLen(s, newLen)
|
||||||
# fill the hole:
|
# fill the hole:
|
||||||
for i in 0 .. <b.len: s[i+a] = b[i]
|
for i in 0 .. <b.len: s[i+a] = b[i]
|
||||||
|
|
||||||
when hostOS != "standalone":
|
when hostOS != "standalone":
|
||||||
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
|
proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
|
||||||
## slice operation for strings. Negative indexes are supported.
|
## slice operation for strings. Negative indexes are supported.
|
||||||
result = s.substr(x.a-|s, x.b-|s)
|
result = s.substr(x.a-|s, x.b-|s)
|
||||||
|
|
||||||
proc `[]=`*(s: var string, x: Slice[int], b: string) =
|
proc `[]=`*(s: var string, x: Slice[int], b: string) =
|
||||||
## slice assignment for strings. Negative indexes are supported. If
|
## slice assignment for strings. Negative indexes are supported. If
|
||||||
## ``b.len`` is not exactly the number of elements that are referred to
|
## ``b.len`` is not exactly the number of elements that are referred to
|
||||||
## by `x`, a `splice`:idx: is performed:
|
## by `x`, a `splice`:idx: is performed:
|
||||||
|
|
@ -2880,7 +2880,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] =
|
||||||
var L = ord(x.b) - ord(x.a) + 1
|
var L = ord(x.b) - ord(x.a) + 1
|
||||||
newSeq(result, L)
|
newSeq(result, L)
|
||||||
var j = x.a
|
var j = x.a
|
||||||
for i in 0.. <L:
|
for i in 0.. <L:
|
||||||
result[i] = a[j]
|
result[i] = a[j]
|
||||||
inc(j)
|
inc(j)
|
||||||
|
|
||||||
|
|
@ -2890,23 +2890,23 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
|
||||||
var L = ord(x.b) - ord(x.a) + 1
|
var L = ord(x.b) - ord(x.a) + 1
|
||||||
if L == b.len:
|
if L == b.len:
|
||||||
var j = x.a
|
var j = x.a
|
||||||
for i in 0 .. <L:
|
for i in 0 .. <L:
|
||||||
a[j] = b[i]
|
a[j] = b[i]
|
||||||
inc(j)
|
inc(j)
|
||||||
else:
|
else:
|
||||||
sysFatal(RangeError, "different lengths for slice assignment")
|
sysFatal(RangeError, "different lengths for slice assignment")
|
||||||
|
|
||||||
proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
|
proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
|
||||||
## slice operation for sequences. Negative indexes are supported.
|
## slice operation for sequences. Negative indexes are supported.
|
||||||
var a = x.a-|s
|
var a = x.a-|s
|
||||||
var L = x.b-|s - a + 1
|
var L = x.b-|s - a + 1
|
||||||
newSeq(result, L)
|
newSeq(result, L)
|
||||||
for i in 0.. <L: result[i] = s[i + a]
|
for i in 0.. <L: result[i] = s[i + a]
|
||||||
|
|
||||||
proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
|
proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
|
||||||
## slice assignment for sequences. Negative indexes are supported. If
|
## slice assignment for sequences. Negative indexes are supported. If
|
||||||
## ``b.len`` is not exactly the number of elements that are referred to
|
## ``b.len`` is not exactly the number of elements that are referred to
|
||||||
## by `x`, a `splice`:idx: is performed.
|
## by `x`, a `splice`:idx: is performed.
|
||||||
var a = x.a-|s
|
var a = x.a-|s
|
||||||
var L = x.b-|s - a + 1
|
var L = x.b-|s - a + 1
|
||||||
if L == b.len:
|
if L == b.len:
|
||||||
|
|
@ -2937,7 +2937,7 @@ proc staticExec*(command: string, input = ""): string {.
|
||||||
## to the executed program.
|
## to the executed program.
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
|
## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
|
||||||
## "\nCompiled on " & staticExec("uname -v")
|
## "\nCompiled on " & staticExec("uname -v")
|
||||||
##
|
##
|
||||||
## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use
|
## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use
|
||||||
|
|
@ -2979,7 +2979,7 @@ proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
|
||||||
proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
|
proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
|
||||||
## converts the AST of `x` into a string representation. This is very useful
|
## converts the AST of `x` into a string representation. This is very useful
|
||||||
## for debugging.
|
## for debugging.
|
||||||
|
|
||||||
proc instantiationInfo*(index = -1, fullPaths = false): tuple[
|
proc instantiationInfo*(index = -1, fullPaths = false): tuple[
|
||||||
filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
|
filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
|
||||||
## provides access to the compiler's instantiation stack line information.
|
## provides access to the compiler's instantiation stack line information.
|
||||||
|
|
@ -3090,16 +3090,16 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
|
||||||
## Sets an assertion failure handler that will intercept any assert
|
## Sets an assertion failure handler that will intercept any assert
|
||||||
## statements following `onFailedAssert` in the current lexical scope.
|
## statements following `onFailedAssert` in the current lexical scope.
|
||||||
## Can be defined multiple times in a single function.
|
## Can be defined multiple times in a single function.
|
||||||
##
|
##
|
||||||
## .. code-block:: nim
|
## .. code-block:: nim
|
||||||
##
|
##
|
||||||
## proc example(x: int): TErrorCode =
|
## proc example(x: int): TErrorCode =
|
||||||
## onFailedAssert(msg):
|
## onFailedAssert(msg):
|
||||||
## log msg
|
## log msg
|
||||||
## return E_FAIL
|
## return E_FAIL
|
||||||
##
|
##
|
||||||
## assert(...)
|
## assert(...)
|
||||||
##
|
##
|
||||||
## onFailedAssert(msg):
|
## onFailedAssert(msg):
|
||||||
## raise newException(EMyException, msg)
|
## raise newException(EMyException, msg)
|
||||||
##
|
##
|
||||||
|
|
@ -3111,7 +3111,7 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
|
||||||
|
|
||||||
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
|
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
|
||||||
## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
|
## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
|
||||||
## perform deep copies of `s`. This is only useful for optimization
|
## perform deep copies of `s`. This is only useful for optimization
|
||||||
## purposes.
|
## purposes.
|
||||||
when not defined(JS) and not defined(NimrodVM):
|
when not defined(JS) and not defined(NimrodVM):
|
||||||
var s = cast[PGenericSeq](s)
|
var s = cast[PGenericSeq](s)
|
||||||
|
|
@ -3119,7 +3119,7 @@ proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
|
||||||
|
|
||||||
proc shallow*(s: var string) {.noSideEffect, inline.} =
|
proc shallow*(s: var string) {.noSideEffect, inline.} =
|
||||||
## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
|
## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
|
||||||
## perform deep copies of `s`. This is only useful for optimization
|
## perform deep copies of `s`. This is only useful for optimization
|
||||||
## purposes.
|
## purposes.
|
||||||
when not defined(JS) and not defined(NimrodVM):
|
when not defined(JS) and not defined(NimrodVM):
|
||||||
var s = cast[PGenericSeq](s)
|
var s = cast[PGenericSeq](s)
|
||||||
|
|
@ -3141,13 +3141,13 @@ else:
|
||||||
when false:
|
when false:
|
||||||
template eval*(blk: stmt): stmt =
|
template eval*(blk: stmt): stmt =
|
||||||
## executes a block of code at compile time just as if it was a macro
|
## executes a block of code at compile time just as if it was a macro
|
||||||
## optionally, the block can return an AST tree that will replace the
|
## optionally, the block can return an AST tree that will replace the
|
||||||
## eval expression
|
## eval expression
|
||||||
macro payload: stmt {.gensym.} = blk
|
macro payload: stmt {.gensym.} = blk
|
||||||
payload()
|
payload()
|
||||||
|
|
||||||
when hostOS != "standalone":
|
when hostOS != "standalone":
|
||||||
proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
|
proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
|
||||||
## inserts `item` into `x` at position `i`.
|
## inserts `item` into `x` at position `i`.
|
||||||
var xl = x.len
|
var xl = x.len
|
||||||
setLen(x, xl+item.len)
|
setLen(x, xl+item.len)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nim's Runtime Library
|
# Nim's Runtime Library
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2015 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -48,7 +48,7 @@ type
|
||||||
TWalkOp = enum
|
TWalkOp = enum
|
||||||
waMarkGlobal, # part of the backup/debug mark&sweep
|
waMarkGlobal, # part of the backup/debug mark&sweep
|
||||||
waMarkPrecise, # part of the backup/debug mark&sweep
|
waMarkPrecise, # part of the backup/debug mark&sweep
|
||||||
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
|
waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
|
||||||
waCollectWhite #, waDebug
|
waCollectWhite #, waDebug
|
||||||
|
|
||||||
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
|
||||||
|
|
@ -61,9 +61,9 @@ type
|
||||||
maxThreshold: int # max threshold that has been set
|
maxThreshold: int # max threshold that has been set
|
||||||
maxStackSize: int # max stack size
|
maxStackSize: int # max stack size
|
||||||
maxStackCells: int # max stack cells in ``decStack``
|
maxStackCells: int # max stack cells in ``decStack``
|
||||||
cycleTableSize: int # max entries in cycle table
|
cycleTableSize: int # max entries in cycle table
|
||||||
maxPause: int64 # max measured GC pause in nanoseconds
|
maxPause: int64 # max measured GC pause in nanoseconds
|
||||||
|
|
||||||
TGcHeap {.final, pure.} = object # this contains the zero count and
|
TGcHeap {.final, pure.} = object # this contains the zero count and
|
||||||
# non-zero count table
|
# non-zero count table
|
||||||
stackBottom: pointer
|
stackBottom: pointer
|
||||||
|
|
@ -88,11 +88,11 @@ var
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
instantiateForRegion(gch.region)
|
instantiateForRegion(gch.region)
|
||||||
|
|
||||||
template acquire(gch: TGcHeap) =
|
template acquire(gch: TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
acquireSys(HeapLock)
|
acquireSys(HeapLock)
|
||||||
|
|
||||||
template release(gch: TGcHeap) =
|
template release(gch: TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
releaseSys(HeapLock)
|
releaseSys(HeapLock)
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ when hasThreadSupport and hasSharedHeap:
|
||||||
template `--`(x: expr): expr = atomicDec(x, rcIncrement) <% rcIncrement
|
template `--`(x: expr): expr = atomicDec(x, rcIncrement) <% rcIncrement
|
||||||
template `++`(x: expr): stmt = discard atomicInc(x, rcIncrement)
|
template `++`(x: expr): stmt = discard atomicInc(x, rcIncrement)
|
||||||
else:
|
else:
|
||||||
template `--`(x: expr): expr =
|
template `--`(x: expr): expr =
|
||||||
dec(x, rcIncrement)
|
dec(x, rcIncrement)
|
||||||
x <% rcIncrement
|
x <% rcIncrement
|
||||||
template `++`(x: expr): stmt = inc(x, rcIncrement)
|
template `++`(x: expr): stmt = inc(x, rcIncrement)
|
||||||
|
|
@ -181,7 +181,7 @@ proc prepareDealloc(cell: PCell) =
|
||||||
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
|
||||||
dec(gch.recGcLock)
|
dec(gch.recGcLock)
|
||||||
|
|
||||||
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
||||||
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
acquireSys(HeapLock)
|
acquireSys(HeapLock)
|
||||||
|
|
@ -211,7 +211,7 @@ proc decRef(c: PCell) {.inline.} =
|
||||||
rtlAddCycleRoot(c)
|
rtlAddCycleRoot(c)
|
||||||
#writeCell("decRef", c)
|
#writeCell("decRef", c)
|
||||||
|
|
||||||
proc incRef(c: PCell) {.inline.} =
|
proc incRef(c: PCell) {.inline.} =
|
||||||
gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
|
gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
|
||||||
c.refcount = c.refcount +% rcIncrement
|
c.refcount = c.refcount +% rcIncrement
|
||||||
# and not colorMask
|
# and not colorMask
|
||||||
|
|
@ -246,12 +246,12 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
|
||||||
# the code generator calls this proc if it is known at compile time that no
|
# the code generator calls this proc if it is known at compile time that no
|
||||||
# cycle is possible.
|
# cycle is possible.
|
||||||
if src != nil:
|
if src != nil:
|
||||||
var c = usrToCell(src)
|
var c = usrToCell(src)
|
||||||
++c.refcount
|
++c.refcount
|
||||||
if dest[] != nil:
|
if dest[] != nil:
|
||||||
var c = usrToCell(dest[])
|
var c = usrToCell(dest[])
|
||||||
if --c.refcount:
|
if --c.refcount:
|
||||||
rtlAddZCT(c)
|
rtlAddZCT(c)
|
||||||
|
|
@ -269,7 +269,7 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
|
||||||
if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
|
if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
|
||||||
else:
|
else:
|
||||||
# can't be an interior pointer if it's a stack location!
|
# can't be an interior pointer if it's a stack location!
|
||||||
gcAssert(interiorAllocatedPtr(gch.region, dest) == nil,
|
gcAssert(interiorAllocatedPtr(gch.region, dest) == nil,
|
||||||
"stack loc AND interior pointer")
|
"stack loc AND interior pointer")
|
||||||
dest[] = src
|
dest[] = src
|
||||||
|
|
||||||
|
|
@ -321,7 +321,7 @@ when useMarkForDebug or useBackupGc:
|
||||||
echo "[GC] cannot register global variable; too many global variables"
|
echo "[GC] cannot register global variable; too many global variables"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
proc cellsetReset(s: var TCellSet) =
|
proc cellsetReset(s: var TCellSet) =
|
||||||
deinit(s)
|
deinit(s)
|
||||||
init(s)
|
init(s)
|
||||||
|
|
||||||
|
|
@ -336,7 +336,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
|
||||||
if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
|
if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
|
||||||
doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
|
doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
|
||||||
else:
|
else:
|
||||||
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
|
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
|
||||||
n.sons[i].typ, op)
|
n.sons[i].typ, op)
|
||||||
else:
|
else:
|
||||||
forAllSlotsAux(dest, n.sons[i], op)
|
forAllSlotsAux(dest, n.sons[i], op)
|
||||||
|
|
@ -384,7 +384,7 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
|
||||||
# we check the last 8 entries (cache line) for a slot that could be reused.
|
# we check the last 8 entries (cache line) for a slot that could be reused.
|
||||||
# In 63% of all cases we succeed here! But we have to optimize the heck
|
# In 63% of all cases we succeed here! But we have to optimize the heck
|
||||||
# out of this small linear search so that ``newObj`` is not slowed down.
|
# out of this small linear search so that ``newObj`` is not slowed down.
|
||||||
#
|
#
|
||||||
# Slots to try cache hit
|
# Slots to try cache hit
|
||||||
# 1 32%
|
# 1 32%
|
||||||
# 4 59%
|
# 4 59%
|
||||||
|
|
@ -481,7 +481,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
||||||
|
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
|
sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
|
||||||
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
|
|
@ -510,7 +510,7 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
cast[PGenericSeq](result).len = len
|
cast[PGenericSeq](result).len = len
|
||||||
cast[PGenericSeq](result).reserved = len
|
cast[PGenericSeq](result).reserved = len
|
||||||
when defined(memProfiler): nimProfile(size)
|
when defined(memProfiler): nimProfile(size)
|
||||||
|
|
||||||
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
|
|
@ -522,7 +522,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
|
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
|
||||||
var elemSize = 1
|
var elemSize = 1
|
||||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||||
|
|
||||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||||
copyMem(res, ol, oldsize + sizeof(TCell))
|
copyMem(res, ol, oldsize + sizeof(TCell))
|
||||||
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
|
zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
|
||||||
|
|
@ -536,7 +536,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||||
writeCell("growObj new cell", res)
|
writeCell("growObj new cell", res)
|
||||||
gcTrace(ol, csZctFreed)
|
gcTrace(ol, csZctFreed)
|
||||||
gcTrace(res, csAllocated)
|
gcTrace(res, csAllocated)
|
||||||
when reallyDealloc:
|
when reallyDealloc:
|
||||||
sysAssert(allocInv(gch.region), "growObj before dealloc")
|
sysAssert(allocInv(gch.region), "growObj before dealloc")
|
||||||
if ol.refcount shr rcShift <=% 1:
|
if ol.refcount shr rcShift <=% 1:
|
||||||
# free immediately to save space:
|
# free immediately to save space:
|
||||||
|
|
@ -580,7 +580,7 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
|
||||||
prepareDealloc(c)
|
prepareDealloc(c)
|
||||||
gcTrace(c, csCycFreed)
|
gcTrace(c, csCycFreed)
|
||||||
when logGC: writeCell("cycle collector dealloc cell", c)
|
when logGC: writeCell("cycle collector dealloc cell", c)
|
||||||
when reallyDealloc:
|
when reallyDealloc:
|
||||||
sysAssert(allocInv(gch.region), "free cyclic cell")
|
sysAssert(allocInv(gch.region), "free cyclic cell")
|
||||||
rawDealloc(gch.region, c)
|
rawDealloc(gch.region, c)
|
||||||
else:
|
else:
|
||||||
|
|
@ -767,7 +767,7 @@ proc collectCycles(gch: var TGcHeap) =
|
||||||
gcAssert isAllocatedPtr(gch.region, c), "addBackStackRoots"
|
gcAssert isAllocatedPtr(gch.region, c), "addBackStackRoots"
|
||||||
gcAssert c.refcount >=% rcIncrement, "addBackStackRoots: dead cell"
|
gcAssert c.refcount >=% rcIncrement, "addBackStackRoots: dead cell"
|
||||||
if canBeCycleRoot(c):
|
if canBeCycleRoot(c):
|
||||||
#if c notin gch.cycleRoots:
|
#if c notin gch.cycleRoots:
|
||||||
inc cycleRootsLen
|
inc cycleRootsLen
|
||||||
incl(gch.cycleRoots, c)
|
incl(gch.cycleRoots, c)
|
||||||
gcAssert c.typ != nil, "addBackStackRoots 2"
|
gcAssert c.typ != nil, "addBackStackRoots 2"
|
||||||
|
|
@ -794,12 +794,12 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
|
||||||
add(gch.decStack, cell)
|
add(gch.decStack, cell)
|
||||||
sysAssert(allocInv(gch.region), "gcMark end")
|
sysAssert(allocInv(gch.region), "gcMark end")
|
||||||
|
|
||||||
proc markThreadStacks(gch: var TGcHeap) =
|
proc markThreadStacks(gch: var TGcHeap) =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
{.error: "not fully implemented".}
|
{.error: "not fully implemented".}
|
||||||
var it = threadList
|
var it = threadList
|
||||||
while it != nil:
|
while it != nil:
|
||||||
# mark registers:
|
# mark registers:
|
||||||
for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
|
for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
|
||||||
var sp = cast[TAddress](it.stackBottom)
|
var sp = cast[TAddress](it.stackBottom)
|
||||||
var max = cast[TAddress](it.stackTop)
|
var max = cast[TAddress](it.stackTop)
|
||||||
|
|
@ -933,7 +933,7 @@ else:
|
||||||
while sp <=% max:
|
while sp <=% max:
|
||||||
gcMark(gch, cast[PPointer](sp)[])
|
gcMark(gch, cast[PPointer](sp)[])
|
||||||
sp = sp +% sizeof(pointer)
|
sp = sp +% sizeof(pointer)
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
|
||||||
forEachStackSlot(gch, gcMark)
|
forEachStackSlot(gch, gcMark)
|
||||||
|
|
||||||
|
|
@ -946,13 +946,13 @@ when useMarkForDebug or useBackupGc:
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
proc collectZCT(gch: var TGcHeap): bool =
|
proc collectZCT(gch: var TGcHeap): bool =
|
||||||
# Note: Freeing may add child objects to the ZCT! So essentially we do
|
# Note: Freeing may add child objects to the ZCT! So essentially we do
|
||||||
# deep freeing, which is bad for incremental operation. In order to
|
# deep freeing, which is bad for incremental operation. In order to
|
||||||
# avoid a deep stack, we move objects to keep the ZCT small.
|
# avoid a deep stack, we move objects to keep the ZCT small.
|
||||||
# This is performance critical!
|
# This is performance critical!
|
||||||
const workPackage = 100
|
const workPackage = 100
|
||||||
var L = addr(gch.zct.len)
|
var L = addr(gch.zct.len)
|
||||||
|
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
var steps = workPackage
|
var steps = workPackage
|
||||||
var t0: TTicks
|
var t0: TTicks
|
||||||
|
|
@ -962,15 +962,15 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
|
sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
|
||||||
# remove from ZCT:
|
# remove from ZCT:
|
||||||
gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT")
|
gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT")
|
||||||
|
|
||||||
c.refcount = c.refcount and not ZctFlag
|
c.refcount = c.refcount and not ZctFlag
|
||||||
gch.zct.d[0] = gch.zct.d[L[] - 1]
|
gch.zct.d[0] = gch.zct.d[L[] - 1]
|
||||||
dec(L[])
|
dec(L[])
|
||||||
when withRealTime: dec steps
|
when withRealTime: dec steps
|
||||||
if c.refcount <% rcIncrement:
|
if c.refcount <% rcIncrement:
|
||||||
# It may have a RC > 0, if it is in the hardware stack or
|
# It may have a RC > 0, if it is in the hardware stack or
|
||||||
# it has not been removed yet from the ZCT. This is because
|
# it has not been removed yet from the ZCT. This is because
|
||||||
# ``incref`` does not bother to remove the cell from the ZCT
|
# ``incref`` does not bother to remove the cell from the ZCT
|
||||||
# as this might be too slow.
|
# as this might be too slow.
|
||||||
# In any case, it should be removed from the ZCT. But not
|
# In any case, it should be removed from the ZCT. But not
|
||||||
# freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
|
# freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
|
||||||
|
|
@ -983,7 +983,7 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
# access invalid memory. This is done by prepareDealloc():
|
# access invalid memory. This is done by prepareDealloc():
|
||||||
prepareDealloc(c)
|
prepareDealloc(c)
|
||||||
forAllChildren(c, waZctDecRef)
|
forAllChildren(c, waZctDecRef)
|
||||||
when reallyDealloc:
|
when reallyDealloc:
|
||||||
sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
|
sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
|
||||||
rawDealloc(gch.region, c)
|
rawDealloc(gch.region, c)
|
||||||
else:
|
else:
|
||||||
|
|
@ -994,7 +994,7 @@ proc collectZCT(gch: var TGcHeap): bool =
|
||||||
steps = workPackage
|
steps = workPackage
|
||||||
if gch.maxPause > 0:
|
if gch.maxPause > 0:
|
||||||
let duration = getticks() - t0
|
let duration = getticks() - t0
|
||||||
# the GC's measuring is not accurate and needs some cleanup actions
|
# the GC's measuring is not accurate and needs some cleanup actions
|
||||||
# (stack unmarking), so subtract some short amount of time in
|
# (stack unmarking), so subtract some short amount of time in
|
||||||
# order to miss deadlines less often:
|
# order to miss deadlines less often:
|
||||||
if duration >= gch.maxPause - 50_000:
|
if duration >= gch.maxPause - 50_000:
|
||||||
|
|
@ -1017,7 +1017,7 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
let t0 = getticks()
|
let t0 = getticks()
|
||||||
sysAssert(allocInv(gch.region), "collectCT: begin")
|
sysAssert(allocInv(gch.region), "collectCT: begin")
|
||||||
|
|
||||||
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
|
||||||
sysAssert(gch.decStack.len == 0, "collectCT")
|
sysAssert(gch.decStack.len == 0, "collectCT")
|
||||||
prepareForInteriorPointerChecking(gch.region)
|
prepareForInteriorPointerChecking(gch.region)
|
||||||
|
|
@ -1036,7 +1036,7 @@ proc collectCTBody(gch: var TGcHeap) =
|
||||||
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
|
||||||
unmarkStackAndRegisters(gch)
|
unmarkStackAndRegisters(gch)
|
||||||
sysAssert(allocInv(gch.region), "collectCT: end")
|
sysAssert(allocInv(gch.region), "collectCT: end")
|
||||||
|
|
||||||
when withRealTime:
|
when withRealTime:
|
||||||
let duration = getticks() - t0
|
let duration = getticks() - t0
|
||||||
gch.stat.maxPause = max(gch.stat.maxPause, duration)
|
gch.stat.maxPause = max(gch.stat.maxPause, duration)
|
||||||
|
|
@ -1050,8 +1050,12 @@ when useMarkForDebug or useBackupGc:
|
||||||
markGlobals(gch)
|
markGlobals(gch)
|
||||||
|
|
||||||
proc collectCT(gch: var TGcHeap) =
|
proc collectCT(gch: var TGcHeap) =
|
||||||
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
# stackMarkCosts prevents some pathological behaviour: Stack marking
|
||||||
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
# becomes more expensive with large stacks and large stacks mean that
|
||||||
|
# cells with RC=0 are more likely to be kept alive by the stack.
|
||||||
|
let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
|
||||||
|
if (gch.zct.len >= stackMarkCosts or (cycleGC and
|
||||||
|
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
||||||
gch.recGcLock == 0:
|
gch.recGcLock == 0:
|
||||||
when useMarkForDebug:
|
when useMarkForDebug:
|
||||||
prepareForInteriorPointerChecking(gch.region)
|
prepareForInteriorPointerChecking(gch.region)
|
||||||
|
|
@ -1070,7 +1074,7 @@ when withRealTime:
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gch.maxPause = us.toNano
|
gch.maxPause = us.toNano
|
||||||
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
if (gch.zct.len >= ZctThreshold or (cycleGC and
|
||||||
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
|
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
|
||||||
strongAdvice:
|
strongAdvice:
|
||||||
collectCTBody(gch)
|
collectCTBody(gch)
|
||||||
release(gch)
|
release(gch)
|
||||||
|
|
@ -1078,13 +1082,13 @@ when withRealTime:
|
||||||
proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice)
|
proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice)
|
||||||
|
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
proc GC_disable() =
|
proc GC_disable() =
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
discard atomicInc(gch.recGcLock, 1)
|
discard atomicInc(gch.recGcLock, 1)
|
||||||
else:
|
else:
|
||||||
inc(gch.recGcLock)
|
inc(gch.recGcLock)
|
||||||
proc GC_enable() =
|
proc GC_enable() =
|
||||||
if gch.recGcLock > 0:
|
if gch.recGcLock > 0:
|
||||||
when hasThreadSupport and hasSharedHeap:
|
when hasThreadSupport and hasSharedHeap:
|
||||||
discard atomicDec(gch.recGcLock, 1)
|
discard atomicDec(gch.recGcLock, 1)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -53,7 +53,6 @@ Bugs
|
||||||
- VM: Pegs do not work at compile-time
|
- VM: Pegs do not work at compile-time
|
||||||
- VM: ptr/ref T cannot work in general
|
- VM: ptr/ref T cannot work in general
|
||||||
- scopes are still broken for generic instantiation!
|
- scopes are still broken for generic instantiation!
|
||||||
- compilation of niminst takes way too long. looks like a regression
|
|
||||||
- blocks can "export" an identifier but the CCG generates {} for them ...
|
- blocks can "export" an identifier but the CCG generates {} for them ...
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue