Merge branch 'devel' of github.com:Araq/Nim into patch2

This commit is contained in:
fowlmouth 2015-04-10 09:23:33 -05:00
commit f852988d11
87 changed files with 4950 additions and 4334 deletions

View file

@ -472,7 +472,7 @@ type
# T and I here can bind to both typedesc and static types # T and I here can bind to both typedesc and static types
# before this is determined, we'll consider them to be a # before this is determined, we'll consider them to be a
# wildcard type. # wildcard type.
tfGuarded # guarded pointer tfHasAsgn # type has overloaded assignment operator
tfBorrowDot # distinct type borrows '.' tfBorrowDot # distinct type borrows '.'
TTypeFlags* = set[TTypeFlag] TTypeFlags* = set[TTypeFlag]
@ -685,8 +685,8 @@ type
s*: TStorageLoc s*: TStorageLoc
flags*: TLocFlags # location's flags flags*: TLocFlags # location's flags
t*: PType # type of location t*: PType # type of location
r*: PRope # rope value of location (code generators) r*: Rope # rope value of location (code generators)
heapRoot*: PRope # keeps track of the enclosing heap object that heapRoot*: Rope # keeps track of the enclosing heap object that
# owns this location (required by GC algorithms # owns this location (required by GC algorithms
# employing heap snapshots or sliding views) # employing heap snapshots or sliding views)
@ -698,7 +698,7 @@ type
kind*: TLibKind kind*: TLibKind
generated*: bool # needed for the backends: generated*: bool # needed for the backends:
isOverriden*: bool isOverriden*: bool
name*: PRope name*: Rope
path*: PNode # can be a string literal! path*: PNode # can be a string literal!
TInstantiation* = object TInstantiation* = object
@ -728,7 +728,8 @@ type
typScope*: PScope typScope*: PScope
of routineKinds: of routineKinds:
procInstCache*: seq[PInstantiation] procInstCache*: seq[PInstantiation]
scope*: PScope # the scope where the proc was defined gcUnsafetyReason*: PSym # for better error messages wrt gcsafe
#scope*: PScope # the scope where the proc was defined
of skModule: of skModule:
# modules keep track of the generic symbols they use from other modules. # modules keep track of the generic symbols they use from other modules.
# this is because in incremental compilation, when a module is about to # this is because in incremental compilation, when a module is about to
@ -804,6 +805,7 @@ type
# mean that there is no destructor. # mean that there is no destructor.
# see instantiateDestructor in semdestruct.nim # see instantiateDestructor in semdestruct.nim
deepCopy*: PSym # overriden 'deepCopy' operation deepCopy*: PSym # overriden 'deepCopy' operation
assignment*: PSym # overriden '=' operator
size*: BiggestInt # the size of the type in bytes size*: BiggestInt # the size of the type in bytes
# -1 means that the size is unkwown # -1 means that the size is unkwown
align*: int16 # the type's alignment requirements align*: int16 # the type's alignment requirements
@ -1218,6 +1220,7 @@ proc assignType*(dest, src: PType) =
dest.align = src.align dest.align = src.align
dest.destructor = src.destructor dest.destructor = src.destructor
dest.deepCopy = src.deepCopy dest.deepCopy = src.deepCopy
dest.assignment = src.assignment
dest.lockLevel = src.lockLevel dest.lockLevel = src.lockLevel
# this fixes 'type TLock = TSysLock': # this fixes 'type TLock = TSysLock':
if src.sym != nil: if src.sym != nil:
@ -1334,6 +1337,13 @@ proc propagateToOwner*(owner, elem: PType) =
if elem.isMetaType: if elem.isMetaType:
owner.flags.incl tfHasMeta owner.flags.incl tfHasMeta
if tfHasAsgn in elem.flags:
let o2 = elem.skipTypes({tyGenericInst})
if o2.kind in {tyTuple, tyObject, tyArray, tyArrayConstr,
tySequence, tySet, tyDistinct}:
o2.flags.incl tfHasAsgn
owner.flags.incl tfHasAsgn
if owner.kind notin {tyProc, tyGenericInst, tyGenericBody, if owner.kind notin {tyProc, tyGenericInst, tyGenericBody,
tyGenericInvocation}: tyGenericInvocation}:
let elemB = elem.skipTypes({tyGenericInst}) let elemB = elem.skipTypes({tyGenericInst})

View file

@ -15,13 +15,13 @@ import
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
proc hashNode*(p: RootRef): THash proc hashNode*(p: RootRef): THash
proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
# Convert a tree into its YAML representation; this is used by the # Convert a tree into its YAML representation; this is used by the
# YAML code generator and it is invaluable for debugging purposes. # YAML code generator and it is invaluable for debugging purposes.
# If maxRecDepht <> -1 then it won't print the whole graph. # If maxRecDepht <> -1 then it won't print the whole graph.
proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope
proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope
proc lineInfoToStr*(info: TLineInfo): PRope proc lineInfoToStr*(info: TLineInfo): Rope
# ----------------------- node sets: --------------------------------------- # ----------------------- node sets: ---------------------------------------
proc objectSetContains*(t: TObjectSet, obj: RootRef): bool proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
@ -203,9 +203,9 @@ proc mustRehash(length, counter: int): bool =
assert(length > counter) assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4) result = (length * 2 < counter * 3) or (length - counter < 4)
proc rspaces(x: int): PRope = proc rspaces(x: int): Rope =
# returns x spaces # returns x spaces
result = toRope(spaces(x)) result = rope(spaces(x))
proc toYamlChar(c: char): string = proc toYamlChar(c: char): string =
case c case c
@ -213,7 +213,7 @@ proc toYamlChar(c: char): string =
of '\'', '\"', '\\': result = '\\' & c of '\'', '\"', '\\': result = '\\' & c
else: result = $c else: result = $c
proc makeYamlString*(s: string): PRope = proc makeYamlString*(s: string): Rope =
# We have to split long strings into many ropes. Otherwise # We have to split long strings into many ropes. Otherwise
# this could trigger InternalError(111). See the ropes module for # this could trigger InternalError(111). See the ropes module for
# further information. # further information.
@ -224,227 +224,227 @@ proc makeYamlString*(s: string): PRope =
if (i + 1) mod MaxLineLength == 0: if (i + 1) mod MaxLineLength == 0:
add(res, '\"') add(res, '\"')
add(res, "\n") add(res, "\n")
app(result, toRope(res)) add(result, rope(res))
res = "\"" # reset res = "\"" # reset
add(res, toYamlChar(s[i])) add(res, toYamlChar(s[i]))
add(res, '\"') add(res, '\"')
app(result, toRope(res)) add(result, rope(res))
proc flagsToStr[T](flags: set[T]): PRope = proc flagsToStr[T](flags: set[T]): Rope =
if flags == {}: if flags == {}:
result = toRope("[]") result = rope("[]")
else: else:
result = nil result = nil
for x in items(flags): for x in items(flags):
if result != nil: app(result, ", ") if result != nil: add(result, ", ")
app(result, makeYamlString($x)) add(result, makeYamlString($x))
result = con("[", con(result, "]")) result = "[" & result & "]"
proc lineInfoToStr(info: TLineInfo): PRope = proc lineInfoToStr(info: TLineInfo): Rope =
result = ropef("[$1, $2, $3]", [makeYamlString(toFilename(info)), result = "[$1, $2, $3]" % [makeYamlString(toFilename(info)),
toRope(toLinenumber(info)), rope(toLinenumber(info)),
toRope(toColumn(info))]) rope(toColumn(info))]
proc treeToYamlAux(n: PNode, marker: var IntSet, proc treeToYamlAux(n: PNode, marker: var IntSet,
indent, maxRecDepth: int): PRope indent, maxRecDepth: int): Rope
proc symToYamlAux(n: PSym, marker: var IntSet, proc symToYamlAux(n: PSym, marker: var IntSet,
indent, maxRecDepth: int): PRope indent, maxRecDepth: int): Rope
proc typeToYamlAux(n: PType, marker: var IntSet, proc typeToYamlAux(n: PType, marker: var IntSet,
indent, maxRecDepth: int): PRope indent, maxRecDepth: int): Rope
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int, proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
maxRecDepth: int): PRope = maxRecDepth: int): Rope =
var istr = rspaces(indent + 2) var istr = rspaces(indent + 2)
result = toRope("[") result = rope("[")
var mycount = 0 var mycount = 0
for i in countup(0, high(n.data)): for i in countup(0, high(n.data)):
if n.data[i] != nil: if n.data[i] != nil:
if mycount > 0: app(result, ",") if mycount > 0: add(result, ",")
appf(result, "$N$1$2", addf(result, "$N$1$2",
[istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)]) [istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
inc(mycount) inc(mycount)
if mycount > 0: appf(result, "$N$1", [rspaces(indent)]) if mycount > 0: addf(result, "$N$1", [rspaces(indent)])
app(result, "]") add(result, "]")
assert(mycount == n.counter) assert(mycount == n.counter)
proc ropeConstr(indent: int, c: openArray[PRope]): PRope = proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
# array of (name, value) pairs # array of (name, value) pairs
var istr = rspaces(indent + 2) var istr = rspaces(indent + 2)
result = toRope("{") result = rope("{")
var i = 0 var i = 0
while i <= high(c): while i <= high(c):
if i > 0: app(result, ",") if i > 0: add(result, ",")
appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]]) addf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
inc(i, 2) inc(i, 2)
appf(result, "$N$1}", [rspaces(indent)]) addf(result, "$N$1}", [rspaces(indent)])
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int, proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
maxRecDepth: int): PRope = maxRecDepth: int): Rope =
if n == nil: if n == nil:
result = toRope("null") result = rope("null")
elif containsOrIncl(marker, n.id): elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope( result = "\"$1 @$2\"" % [rope(n.name.s), rope(
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]) strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
else: else:
var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1) var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1)
result = ropeConstr(indent, [toRope("kind"), result = ropeConstr(indent, [rope("kind"),
makeYamlString($n.kind), makeYamlString($n.kind),
toRope("name"), makeYamlString(n.name.s), rope("name"), makeYamlString(n.name.s),
toRope("typ"), typeToYamlAux(n.typ, marker, rope("typ"), typeToYamlAux(n.typ, marker,
indent + 2, maxRecDepth - 1), indent + 2, maxRecDepth - 1),
toRope("info"), lineInfoToStr(n.info), rope("info"), lineInfoToStr(n.info),
toRope("flags"), flagsToStr(n.flags), rope("flags"), flagsToStr(n.flags),
toRope("magic"), makeYamlString($n.magic), rope("magic"), makeYamlString($n.magic),
toRope("ast"), ast, toRope("options"), rope("ast"), ast, rope("options"),
flagsToStr(n.options), toRope("position"), flagsToStr(n.options), rope("position"),
toRope(n.position)]) rope(n.position)])
proc typeToYamlAux(n: PType, marker: var IntSet, indent: int, proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
maxRecDepth: int): PRope = maxRecDepth: int): Rope =
if n == nil: if n == nil:
result = toRope("null") result = rope("null")
elif containsOrIncl(marker, n.id): elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope( result = "\"$1 @$2\"" % [rope($n.kind), rope(
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]) strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
else: else:
if sonsLen(n) > 0: if sonsLen(n) > 0:
result = toRope("[") result = rope("[")
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: app(result, ",") if i > 0: add(result, ",")
appf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i], addf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i],
marker, indent + 4, maxRecDepth - 1)]) marker, indent + 4, maxRecDepth - 1)])
appf(result, "$N$1]", [rspaces(indent + 2)]) addf(result, "$N$1]", [rspaces(indent + 2)])
else: else:
result = toRope("null") result = rope("null")
result = ropeConstr(indent, [toRope("kind"), result = ropeConstr(indent, [rope("kind"),
makeYamlString($n.kind), makeYamlString($n.kind),
toRope("sym"), symToYamlAux(n.sym, marker, rope("sym"), symToYamlAux(n.sym, marker,
indent + 2, maxRecDepth - 1), toRope("n"), treeToYamlAux(n.n, marker, indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(n.n, marker,
indent + 2, maxRecDepth - 1), toRope("flags"), flagsToStr(n.flags), indent + 2, maxRecDepth - 1), rope("flags"), flagsToStr(n.flags),
toRope("callconv"), rope("callconv"),
makeYamlString(CallingConvToStr[n.callConv]), makeYamlString(CallingConvToStr[n.callConv]),
toRope("size"), toRope(n.size), rope("size"), rope(n.size),
toRope("align"), toRope(n.align), rope("align"), rope(n.align),
toRope("sons"), result]) rope("sons"), result])
proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int, proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
maxRecDepth: int): PRope = maxRecDepth: int): Rope =
if n == nil: if n == nil:
result = toRope("null") result = rope("null")
else: else:
var istr = rspaces(indent + 2) var istr = rspaces(indent + 2)
result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)]) result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
if maxRecDepth != 0: if maxRecDepth != 0:
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
case n.kind case n.kind
of nkCharLit..nkInt64Lit: of nkCharLit..nkInt64Lit:
appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)]) addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, ",$N$1\"floatVal\": $2", addf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.toStrMaxPrecision)]) [istr, rope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if n.strVal.isNil: if n.strVal.isNil:
appf(result, ",$N$1\"strVal\": null", [istr]) addf(result, ",$N$1\"strVal\": null", [istr])
else: else:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym: of nkSym:
appf(result, ",$N$1\"sym\": $2", addf(result, ",$N$1\"sym\": $2",
[istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)]) [istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
of nkIdent: of nkIdent:
if n.ident != nil: if n.ident != nil:
appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)]) addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
else: else:
appf(result, ",$N$1\"ident\": null", [istr]) addf(result, ",$N$1\"ident\": null", [istr])
else: else:
if sonsLen(n) > 0: if sonsLen(n) > 0:
appf(result, ",$N$1\"sons\": [", [istr]) addf(result, ",$N$1\"sons\": [", [istr])
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: app(result, ",") if i > 0: add(result, ",")
appf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i], addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i],
marker, indent + 4, maxRecDepth - 1)]) marker, indent + 4, maxRecDepth - 1)])
appf(result, "$N$1]", [istr]) addf(result, "$N$1]", [istr])
appf(result, ",$N$1\"typ\": $2", addf(result, ",$N$1\"typ\": $2",
[istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)]) [istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
appf(result, "$N$1}", [rspaces(indent)]) addf(result, "$N$1}", [rspaces(indent)])
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope = proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet() var marker = initIntSet()
result = treeToYamlAux(n, marker, indent, maxRecDepth) result = treeToYamlAux(n, marker, indent, maxRecDepth)
proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope = proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet() var marker = initIntSet()
result = typeToYamlAux(n, marker, indent, maxRecDepth) result = typeToYamlAux(n, marker, indent, maxRecDepth)
proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope = proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
var marker = initIntSet() var marker = initIntSet()
result = symToYamlAux(n, marker, indent, maxRecDepth) result = symToYamlAux(n, marker, indent, maxRecDepth)
proc debugTree*(n: PNode, indent: int, maxRecDepth: int; renderType=false): PRope proc debugTree*(n: PNode, indent: int, maxRecDepth: int; renderType=false): Rope
proc debugType(n: PType, maxRecDepth=100): PRope = proc debugType(n: PType, maxRecDepth=100): Rope =
if n == nil: if n == nil:
result = toRope("null") result = rope("null")
else: else:
result = toRope($n.kind) result = rope($n.kind)
if n.sym != nil: if n.sym != nil:
app(result, " ") add(result, " ")
app(result, n.sym.name.s) add(result, n.sym.name.s)
if n.kind in IntegralTypes and n.n != nil: if n.kind in IntegralTypes and n.n != nil:
app(result, ", node: ") add(result, ", node: ")
app(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true)) add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0: if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0:
app(result, "(") add(result, "(")
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: app(result, ", ") if i > 0: add(result, ", ")
if n.sons[i] == nil: if n.sons[i] == nil:
app(result, "null") add(result, "null")
else: else:
app(result, debugType(n.sons[i], maxRecDepth-1)) add(result, debugType(n.sons[i], maxRecDepth-1))
if n.kind == tyObject and n.n != nil: if n.kind == tyObject and n.n != nil:
app(result, ", node: ") add(result, ", node: ")
app(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true)) add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
app(result, ")") add(result, ")")
proc debugTree(n: PNode, indent: int, maxRecDepth: int; proc debugTree(n: PNode, indent: int, maxRecDepth: int;
renderType=false): PRope = renderType=false): Rope =
if n == nil: if n == nil:
result = toRope("null") result = rope("null")
else: else:
var istr = rspaces(indent + 2) var istr = rspaces(indent + 2)
result = ropef("{$N$1\"kind\": $2", result = "{$N$1\"kind\": $2" %
[istr, makeYamlString($n.kind)]) [istr, makeYamlString($n.kind)]
if maxRecDepth != 0: if maxRecDepth != 0:
case n.kind case n.kind
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)]) addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, ",$N$1\"floatVal\": $2", addf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.toStrMaxPrecision)]) [istr, rope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if n.strVal.isNil: if n.strVal.isNil:
appf(result, ",$N$1\"strVal\": null", [istr]) addf(result, ",$N$1\"strVal\": null", [istr])
else: else:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym: of nkSym:
appf(result, ",$N$1\"sym\": $2_$3", addf(result, ",$N$1\"sym\": $2_$3",
[istr, toRope(n.sym.name.s), toRope(n.sym.id)]) [istr, rope(n.sym.name.s), rope(n.sym.id)])
# [istr, symToYaml(n.sym, indent, maxRecDepth), # [istr, symToYaml(n.sym, indent, maxRecDepth),
# toRope(n.sym.id)]) # rope(n.sym.id)])
if renderType and n.sym.typ != nil: if renderType and n.sym.typ != nil:
appf(result, ",$N$1\"typ\": $2", [istr, debugType(n.sym.typ, 2)]) addf(result, ",$N$1\"typ\": $2", [istr, debugType(n.sym.typ, 2)])
of nkIdent: of nkIdent:
if n.ident != nil: if n.ident != nil:
appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)]) addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
else: else:
appf(result, ",$N$1\"ident\": null", [istr]) addf(result, ",$N$1\"ident\": null", [istr])
else: else:
if sonsLen(n) > 0: if sonsLen(n) > 0:
appf(result, ",$N$1\"sons\": [", [istr]) addf(result, ",$N$1\"sons\": [", [istr])
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: app(result, ",") if i > 0: add(result, ",")
appf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i], addf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i],
indent + 4, maxRecDepth - 1, renderType)]) indent + 4, maxRecDepth - 1, renderType)])
appf(result, "$N$1]", [istr]) addf(result, "$N$1]", [istr])
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
appf(result, "$N$1}", [rspaces(indent)]) addf(result, "$N$1}", [rspaces(indent)])
proc debug(n: PSym) = proc debug(n: PSym) =
if n == nil: if n == nil:
@ -452,17 +452,16 @@ proc debug(n: PSym) =
elif n.kind == skUnknown: elif n.kind == skUnknown:
msgWriteln("skUnknown") msgWriteln("skUnknown")
else: else:
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1))) #writeln(stdout, $symToYaml(n, 0, 1))
msgWriteln("$1_$2: $3, $4, $5, $6" % [ msgWriteln("$1_$2: $3, $4, $5, $6" % [
n.name.s, $n.id, flagsToStr(n.flags).ropeToStr, n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr, $lineInfoToStr(n.info), $n.kind])
$n.kind])
proc debug(n: PType) = proc debug(n: PType) =
msgWriteln(ropeToStr(debugType(n))) msgWriteln($debugType(n))
proc debug(n: PNode) = proc debug(n: PNode) =
msgWriteln(ropeToStr(debugTree(n, 0, 100))) msgWriteln($debugTree(n, 0, 100))
const const
EmptySeq = @[] EmptySeq = @[]

View file

@ -243,24 +243,24 @@ proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
encodeNode(w, n.info, n.sons[i], result) encodeNode(w, n.info, n.sons[i], result)
add(result, ')') add(result, ')')
proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
var oldLen = result.len var oldLen = result.len
result.add('<') result.add('<')
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result) if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
if loc.s != low(loc.s): if loc.s != low(loc.s):
add(result, '*') add(result, '*')
encodeVInt(ord(loc.s), result) encodeVInt(ord(loc.s), result)
if loc.flags != {}: if loc.flags != {}:
add(result, '$') add(result, '$')
encodeVInt(cast[int32](loc.flags), result) encodeVInt(cast[int32](loc.flags), result)
if loc.t != nil: if loc.t != nil:
add(result, '^') add(result, '^')
encodeVInt(cast[int32](loc.t.id), result) encodeVInt(cast[int32](loc.t.id), result)
pushType(w, loc.t) pushType(w, loc.t)
if loc.r != nil: if loc.r != nil:
add(result, '!') add(result, '!')
encodeStr(ropeToStr(loc.r), result) encodeStr($loc.r, result)
if loc.a != 0: if loc.a != 0:
add(result, '?') add(result, '?')
encodeVInt(loc.a, result) encodeVInt(loc.a, result)
if oldLen + 1 == result.len: if oldLen + 1 == result.len:
@ -317,7 +317,7 @@ proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
add(result, '|') add(result, '|')
encodeVInt(ord(lib.kind), result) encodeVInt(ord(lib.kind), result)
add(result, '|') add(result, '|')
encodeStr(ropeToStr(lib.name), result) encodeStr($lib.name, result)
add(result, '|') add(result, '|')
encodeNode(w, info, lib.path, result) encodeNode(w, info, lib.path, result)

View file

@ -19,13 +19,13 @@ proc hasNoInit(call: PNode): bool {.inline.} =
result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
callee, params: PRope) = callee, params: Rope) =
var pl = con(callee, ~"(", params) var pl = callee & ~"(" & params
# getUniqueType() is too expensive here: # getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst) var typ = skipTypes(ri.sons[0].typ, abstractInst)
if typ.sons[0] != nil: if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]): if isInvalidReturnType(typ.sons[0]):
if params != nil: pl.app(~", ") if params != nil: pl.add(~", ")
# beware of 'result = p(result)'. We may need to allocate a temporary: # beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri): if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
# Great, we can use 'd': # Great, we can use 'd':
@ -33,18 +33,18 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri): elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var: # reset before pass as 'result' var:
resetLoc(p, d) resetLoc(p, d)
app(pl, addrLoc(d)) add(pl, addrLoc(d))
app(pl, ~");$n") add(pl, ~");$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp, needsInit=true) getTemp(p, typ.sons[0], tmp, needsInit=true)
app(pl, addrLoc(tmp)) add(pl, addrLoc(tmp))
app(pl, ~");$n") add(pl, ~");$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
app(pl, ~")") add(pl, ~")")
if p.module.compileToCpp and lfSingleUse in d.flags: if p.module.compileToCpp and lfSingleUse in d.flags:
# do not generate spurious temporaries for C++! For C we're better off # do not generate spurious temporaries for C++! For C we're better off
# with them to prevent undefined behaviour and because the codegen # with them to prevent undefined behaviour and because the codegen
@ -60,7 +60,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
list.r = pl list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
app(pl, ~");$n") add(pl, ~");$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
proc isInCurrentFrame(p: BProc, n: PNode): bool = proc isInCurrentFrame(p: BProc, n: PNode): bool =
@ -83,7 +83,7 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
result = isInCurrentFrame(p, n.sons[0]) result = isInCurrentFrame(p, n.sons[0])
else: discard else: discard
proc openArrayLoc(p: BProc, n: PNode): PRope = proc openArrayLoc(p: BProc, n: PNode): Rope =
var a: TLoc var a: TLoc
let q = skipConv(n) let q = skipConv(n)
@ -104,28 +104,28 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
else: else:
"$1->data+($2), ($3)-($2)+1" "$1->data+($2), ($3)-($2)+1"
else: (internalError("openArrayLoc: " & typeToString(a.t)); "") else: (internalError("openArrayLoc: " & typeToString(a.t)); "")
result = ropef(fmt, [rdLoc(a), rdLoc(b), rdLoc(c)]) result = fmt % [rdLoc(a), rdLoc(b), rdLoc(c)]
else: else:
initLocExpr(p, n, a) initLocExpr(p, n, a)
case skipTypes(a.t, abstractVar).kind case skipTypes(a.t, abstractVar).kind
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
result = ropef("$1, $1Len0", [rdLoc(a)]) result = "$1, $1Len0" % [rdLoc(a)]
of tyString, tySequence: of tyString, tySequence:
if skipTypes(n.typ, abstractInst).kind == tyVar and if skipTypes(n.typ, abstractInst).kind == tyVar and
not compileToCpp(p.module): not compileToCpp(p.module):
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)]) result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
else: else:
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)]) result = "$1->data, $1->$2" % [a.rdLoc, lenField(p)]
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]) result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))]
else: internalError("openArrayLoc: " & typeToString(a.t)) else: internalError("openArrayLoc: " & typeToString(a.t))
proc genArgStringToCString(p: BProc, n: PNode): PRope {.inline.} = proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
var a: TLoc var a: TLoc
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
result = ropef("$1->data", [a.rdLoc]) result = "$1->data" % [a.rdLoc]
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope = proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
var a: TLoc var a: TLoc
if n.kind == nkStringToCString: if n.kind == nkStringToCString:
result = genArgStringToCString(p, n) result = genArgStringToCString(p, n)
@ -151,7 +151,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope =
initLocExprSingleUse(p, n, a) initLocExprSingleUse(p, n, a)
result = rdLoc(a) result = rdLoc(a)
proc genArgNoParam(p: BProc, n: PNode): PRope = proc genArgNoParam(p: BProc, n: PNode): Rope =
var a: TLoc var a: TLoc
if n.kind == nkStringToCString: if n.kind == nkStringToCString:
result = genArgStringToCString(p, n) result = genArgStringToCString(p, n)
@ -163,7 +163,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc var op: TLoc
# this is a hotspot in the compiler # this is a hotspot in the compiler
initLocExpr(p, ri.sons[0], op) initLocExpr(p, ri.sons[0], op)
var params: PRope var params: Rope
# getUniqueType() is too expensive here: # getUniqueType() is too expensive here:
var typ = skipTypes(ri.sons[0].typ, abstractInst) var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
@ -171,27 +171,27 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var length = sonsLen(ri) var length = sonsLen(ri)
for i in countup(1, length - 1): for i in countup(1, length - 1):
if ri.sons[i].typ.isCompileTimeOnly: continue if ri.sons[i].typ.isCompileTimeOnly: continue
if params != nil: app(params, ~", ") if params != nil: add(params, ~", ")
if i < sonsLen(typ): if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym) assert(typ.n.sons[i].kind == nkSym)
app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri)) add(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
else: else:
app(params, genArgNoParam(p, ri.sons[i])) add(params, genArgNoParam(p, ri.sons[i]))
fixupCall(p, le, ri, d, op.r, params) fixupCall(p, le, ri, d, op.r, params)
proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc getRawProcType(p: BProc, t: PType): PRope = proc getRawProcType(p: BProc, t: PType): Rope =
result = getClosureType(p.module, t, clHalf) result = getClosureType(p.module, t, clHalf)
proc addComma(r: PRope): PRope = proc addComma(r: Rope): Rope =
result = if r == nil: r else: con(r, ~", ") result = if r == nil: r else: r & ~", "
const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)" const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
var op: TLoc var op: TLoc
initLocExpr(p, ri.sons[0], op) initLocExpr(p, ri.sons[0], op)
var pl: PRope var pl: Rope
var typ = skipTypes(ri.sons[0].typ, abstractInst) var typ = skipTypes(ri.sons[0].typ, abstractInst)
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
@ -201,19 +201,19 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if ri.sons[i].typ.isCompileTimeOnly: continue if ri.sons[i].typ.isCompileTimeOnly: continue
if i < sonsLen(typ): if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym) assert(typ.n.sons[i].kind == nkSym)
app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri)) add(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
else: else:
app(pl, genArgNoParam(p, ri.sons[i])) add(pl, genArgNoParam(p, ri.sons[i]))
if i < length - 1: app(pl, ~", ") if i < length - 1: add(pl, ~", ")
template genCallPattern {.dirty.} = template genCallPattern {.dirty.} =
lineF(p, cpsStmts, callPattern & ";$n", op.r, pl, pl.addComma, rawProc) lineF(p, cpsStmts, callPattern & ";$n", [op.r, pl, pl.addComma, rawProc])
let rawProc = getRawProcType(p, typ) let rawProc = getRawProcType(p, typ)
let callPattern = if tfIterator in typ.flags: PatIter else: PatProc let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
if typ.sons[0] != nil: if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]): if isInvalidReturnType(typ.sons[0]):
if sonsLen(ri) > 1: app(pl, ~", ") if sonsLen(ri) > 1: add(pl, ~", ")
# beware of 'result = p(result)'. We may need to allocate a temporary: # beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri): if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
# Great, we can use 'd': # Great, we can use 'd':
@ -222,12 +222,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
elif d.k notin {locExpr, locTemp} and not hasNoInit(ri): elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var: # reset before pass as 'result' var:
resetLoc(p, d) resetLoc(p, d)
app(pl, addrLoc(d)) add(pl, addrLoc(d))
genCallPattern() genCallPattern()
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp, needsInit=true) getTemp(p, typ.sons[0], tmp, needsInit=true)
app(pl, addrLoc(tmp)) add(pl, addrLoc(tmp))
genCallPattern() genCallPattern()
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
@ -235,12 +235,12 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(d.t != nil) # generate an assignment to d: assert(d.t != nil) # generate an assignment to d:
var list: TLoc var list: TLoc
initLoc(list, locCall, d.t, OnUnknown) initLoc(list, locCall, d.t, OnUnknown)
list.r = ropef(callPattern, op.r, pl, pl.addComma, rawProc) list.r = callPattern % [op.r, pl, pl.addComma, rawProc]
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
genCallPattern() genCallPattern()
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): PRope = proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
if ri.sons[i].typ.isCompileTimeOnly: if ri.sons[i].typ.isCompileTimeOnly:
result = nil result = nil
elif i < sonsLen(typ): elif i < sonsLen(typ):
@ -309,7 +309,7 @@ proc skipAddrDeref(node: PNode): PNode =
else: else:
result = node result = node
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope = proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
# for better or worse c2nim translates the 'this' argument to a 'var T'. # for better or worse c2nim translates the 'this' argument to a 'var T'.
# However manual wrappers may also use 'ptr T'. In any case we support both # However manual wrappers may also use 'ptr T'. In any case we support both
# for convenience. # for convenience.
@ -324,64 +324,64 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
let x = if ri.kind == nkHiddenAddr: ri[0] else: ri let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
if x.typ.kind == tyPtr: if x.typ.kind == tyPtr:
result = genArgNoParam(p, x) result = genArgNoParam(p, x)
result.app("->") result.add("->")
elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr: elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
result = genArgNoParam(p, x[0]) result = genArgNoParam(p, x[0])
result.app("->") result.add("->")
else: else:
result = genArgNoParam(p, x) result = genArgNoParam(p, x)
result.app(".") result.add(".")
elif t.kind == tyPtr: elif t.kind == tyPtr:
if ri.kind in {nkAddr, nkHiddenAddr}: if ri.kind in {nkAddr, nkHiddenAddr}:
result = genArgNoParam(p, ri[0]) result = genArgNoParam(p, ri[0])
result.app(".") result.add(".")
else: else:
result = genArgNoParam(p, ri) result = genArgNoParam(p, ri)
result.app("->") result.add("->")
else: else:
ri = skipAddrDeref(ri) ri = skipAddrDeref(ri)
if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0] if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0]
result = genArgNoParam(p, ri) #, typ.n.sons[i].sym) result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
result.app(".") result.add(".")
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope = proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
var i = 0 var i = 0
var j = 1 var j = 1
while i < pat.len: while i < pat.len:
case pat[i] case pat[i]
of '@': of '@':
if j < ri.len: if j < ri.len:
result.app genOtherArg(p, ri, j, typ) result.add genOtherArg(p, ri, j, typ)
for k in j+1 .. < ri.len: for k in j+1 .. < ri.len:
result.app(~", ") result.add(~", ")
result.app genOtherArg(p, ri, k, typ) result.add genOtherArg(p, ri, k, typ)
inc i inc i
of '#': of '#':
if pat[i+1] in {'+', '@'}: if pat[i+1] in {'+', '@'}:
let ri = ri[j] let ri = ri[j]
if ri.kind in nkCallKinds: if ri.kind in nkCallKinds:
let typ = skipTypes(ri.sons[0].typ, abstractInst) let typ = skipTypes(ri.sons[0].typ, abstractInst)
if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0]) if pat[i+1] == '+': result.add genArgNoParam(p, ri.sons[0])
result.app(~"(") result.add(~"(")
if 1 < ri.len: if 1 < ri.len:
result.app genOtherArg(p, ri, 1, typ) result.add genOtherArg(p, ri, 1, typ)
for k in j+1 .. < ri.len: for k in j+1 .. < ri.len:
result.app(~", ") result.add(~", ")
result.app genOtherArg(p, ri, k, typ) result.add genOtherArg(p, ri, k, typ)
result.app(~")") result.add(~")")
else: else:
localError(ri.info, "call expression expected for C++ pattern") localError(ri.info, "call expression expected for C++ pattern")
inc i inc i
elif pat[i+1] == '.': elif pat[i+1] == '.':
result.app genThisArg(p, ri, j, typ) result.add genThisArg(p, ri, j, typ)
inc i inc i
elif pat[i+1] == '[': elif pat[i+1] == '[':
var arg = ri.sons[j].skipAddrDeref var arg = ri.sons[j].skipAddrDeref
while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0] while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
result.app genArgNoParam(p, arg) result.add genArgNoParam(p, arg)
#result.app debugTree(arg, 0, 10) #result.add debugTree(arg, 0, 10)
else: else:
result.app genOtherArg(p, ri, j, typ) result.add genOtherArg(p, ri, j, typ)
inc j inc j
inc i inc i
of '\'': of '\'':
@ -394,8 +394,8 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
for k in 1..i-stars: for k in 1..i-stars:
if t != nil and t.len > 0: if t != nil and t.len > 0:
t = if t.kind == tyGenericInst: t.sons[1] else: t.elemType t = if t.kind == tyGenericInst: t.sons[1] else: t.elemType
if t == nil: result.app(~"void") if t == nil: result.add(~"void")
else: result.app(getTypeDesc(p.module, t)) else: result.add(getTypeDesc(p.module, t))
inc i inc i
else: else:
let start = i let start = i
@ -403,7 +403,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
if pat[i] notin {'@', '#', '\''}: inc(i) if pat[i] notin {'@', '#', '\''}: inc(i)
else: break else: break
if i - 1 >= start: if i - 1 >= start:
app(result, substr(pat, start, i - 1)) add(result, substr(pat, start, i - 1))
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op, a: TLoc var op, a: TLoc
@ -413,7 +413,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
var length = sonsLen(ri) var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n)) assert(sonsLen(typ) == sonsLen(typ.n))
# don't call 'ropeToStr' here for efficiency: # don't call '$' here for efficiency:
let pat = ri.sons[0].sym.loc.r.data let pat = ri.sons[0].sym.loc.r.data
internalAssert pat != nil internalAssert pat != nil
if pat.contains({'#', '(', '@', '\''}): if pat.contains({'#', '(', '@', '\''}):
@ -436,19 +436,19 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
list.r = pl list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
app(pl, ~";$n") add(pl, ~";$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
else: else:
var pl: PRope = nil var pl: Rope = nil
#var param = typ.n.sons[1].sym #var param = typ.n.sons[1].sym
if 1 < ri.len: if 1 < ri.len:
app(pl, genThisArg(p, ri, 1, typ)) add(pl, genThisArg(p, ri, 1, typ))
app(pl, op.r) add(pl, op.r)
var params: PRope var params: Rope
for i in countup(2, length - 1): for i in countup(2, length - 1):
if params != nil: params.app(~", ") if params != nil: params.add(~", ")
assert(sonsLen(typ) == sonsLen(typ.n)) assert(sonsLen(typ) == sonsLen(typ.n))
app(params, genOtherArg(p, ri, i, typ)) add(params, genOtherArg(p, ri, i, typ))
fixupCall(p, le, ri, d, pl, params) fixupCall(p, le, ri, d, pl, params)
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
@ -462,55 +462,55 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
var length = sonsLen(ri) var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n)) assert(sonsLen(typ) == sonsLen(typ.n))
# don't call 'ropeToStr' here for efficiency: # don't call '$' here for efficiency:
let pat = ri.sons[0].sym.loc.r.data let pat = ri.sons[0].sym.loc.r.data
internalAssert pat != nil internalAssert pat != nil
var start = 3 var start = 3
if ' ' in pat: if ' ' in pat:
start = 1 start = 1
app(pl, op.r) add(pl, op.r)
if length > 1: if length > 1:
app(pl, ~": ") add(pl, ~": ")
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri)) add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
start = 2 start = 2
else: else:
if length > 1: if length > 1:
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri)) add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
app(pl, ~" ") add(pl, ~" ")
app(pl, op.r) add(pl, op.r)
if length > 2: if length > 2:
app(pl, ~": ") add(pl, ~": ")
app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri)) add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
for i in countup(start, length-1): for i in countup(start, length-1):
assert(sonsLen(typ) == sonsLen(typ.n)) assert(sonsLen(typ) == sonsLen(typ.n))
if i >= sonsLen(typ): if i >= sonsLen(typ):
internalError(ri.info, "varargs for objective C method?") internalError(ri.info, "varargs for objective C method?")
assert(typ.n.sons[i].kind == nkSym) assert(typ.n.sons[i].kind == nkSym)
var param = typ.n.sons[i].sym var param = typ.n.sons[i].sym
app(pl, ~" ") add(pl, ~" ")
app(pl, param.name.s) add(pl, param.name.s)
app(pl, ~": ") add(pl, ~": ")
app(pl, genArg(p, ri.sons[i], param, ri)) add(pl, genArg(p, ri.sons[i], param, ri))
if typ.sons[0] != nil: if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]): if isInvalidReturnType(typ.sons[0]):
if sonsLen(ri) > 1: app(pl, ~" ") if sonsLen(ri) > 1: add(pl, ~" ")
# beware of 'result = p(result)'. We always allocate a temporary: # beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}: if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it: # We already got a temp. Great, special case it:
if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true) if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
app(pl, ~"Result: ") add(pl, ~"Result: ")
app(pl, addrLoc(d)) add(pl, addrLoc(d))
app(pl, ~"];$n") add(pl, ~"];$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp, needsInit=true) getTemp(p, typ.sons[0], tmp, needsInit=true)
app(pl, addrLoc(tmp)) add(pl, addrLoc(tmp))
app(pl, ~"];$n") add(pl, ~"];$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
app(pl, ~"]") add(pl, ~"]")
if d.k == locNone: getTemp(p, typ.sons[0], d) if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d: assert(d.t != nil) # generate an assignment to d:
var list: TLoc var list: TLoc
@ -518,7 +518,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
list.r = pl list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
app(pl, ~"];$n") add(pl, ~"];$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
proc genCall(p: BProc, e: PNode, d: var TLoc) = proc genCall(p: BProc, e: PNode, d: var TLoc) =

View file

@ -11,45 +11,45 @@
# -------------------------- constant expressions ------------------------ # -------------------------- constant expressions ------------------------
proc int64Literal(i: BiggestInt): PRope = proc int64Literal(i: BiggestInt): Rope =
if i > low(int64): if i > low(int64):
result = rfmt(nil, "IL64($1)", toRope(i)) result = rfmt(nil, "IL64($1)", rope(i))
else: else:
result = ~"(IL64(-9223372036854775807) - IL64(1))" result = ~"(IL64(-9223372036854775807) - IL64(1))"
proc uint64Literal(i: uint64): PRope = toRope($i & "ULL") proc uint64Literal(i: uint64): Rope = rope($i & "ULL")
proc intLiteral(i: BiggestInt): PRope = proc intLiteral(i: BiggestInt): Rope =
if i > low(int32) and i <= high(int32): if i > low(int32) and i <= high(int32):
result = toRope(i) result = rope(i)
elif i == low(int32): elif i == low(int32):
# Nim has the same bug for the same reasons :-) # Nim has the same bug for the same reasons :-)
result = ~"(-2147483647 -1)" result = ~"(-2147483647 -1)"
elif i > low(int64): elif i > low(int64):
result = rfmt(nil, "IL64($1)", toRope(i)) result = rfmt(nil, "IL64($1)", rope(i))
else: else:
result = ~"(IL64(-9223372036854775807) - IL64(1))" result = ~"(IL64(-9223372036854775807) - IL64(1))"
proc int32Literal(i: int): PRope = proc int32Literal(i: int): Rope =
if i == int(low(int32)): if i == int(low(int32)):
result = ~"(-2147483647 -1)" result = ~"(-2147483647 -1)"
else: else:
result = toRope(i) result = rope(i)
proc genHexLiteral(v: PNode): PRope = proc genHexLiteral(v: PNode): Rope =
# hex literals are unsigned in C # hex literals are unsigned in C
# so we don't generate hex literals any longer. # so we don't generate hex literals any longer.
if v.kind notin {nkIntLit..nkUInt64Lit}: if v.kind notin {nkIntLit..nkUInt64Lit}:
internalError(v.info, "genHexLiteral") internalError(v.info, "genHexLiteral")
result = intLiteral(v.intVal) result = intLiteral(v.intVal)
proc getStrLit(m: BModule, s: string): PRope = proc getStrLit(m: BModule, s: string): Rope =
discard cgsym(m, "TGenericSeq") discard cgsym(m, "TGenericSeq")
result = con("TMP", toRope(backendId())) result = "TMP" & rope(backendId())
appf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n", addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
[result, makeCString(s), toRope(len(s))]) [result, makeCString(s), rope(len(s))])
proc genLiteral(p: BProc, n: PNode, ty: PType): PRope = proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
if ty == nil: internalError(n.info, "genLiteral: ty is nil") if ty == nil: internalError(n.info, "genLiteral: ty is nil")
case n.kind case n.kind
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
@ -62,21 +62,21 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
of tyInt64: result = int64Literal(n.intVal) of tyInt64: result = int64Literal(n.intVal)
of tyUInt64: result = uint64Literal(uint64(n.intVal)) of tyUInt64: result = uint64Literal(uint64(n.intVal))
else: else:
result = ropef("(($1) $2)", [getTypeDesc(p.module, result = "(($1) $2)" % [getTypeDesc(p.module,
skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)]) skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)]
of nkNilLit: of nkNilLit:
let t = skipTypes(ty, abstractVarRange) let t = skipTypes(ty, abstractVarRange)
if t.kind == tyProc and t.callConv == ccClosure: if t.kind == tyProc and t.callConv == ccClosure:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
result = con("TMP", toRope(id)) result = "TMP" & rope(id)
if id == gBackendId: if id == gBackendId:
# not found in cache: # not found in cache:
inc(gBackendId) inc(gBackendId)
appf(p.module.s[cfsData], addf(p.module.s[cfsData],
"static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n", "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
[getTypeDesc(p.module, t), result]) [getTypeDesc(p.module, t), result])
else: else:
result = toRope("NIM_NIL") result = rope("NIM_NIL")
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if n.strVal.isNil: if n.strVal.isNil:
result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", []) result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
@ -87,16 +87,16 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
result = ropecg(p.module, "((#NimStringDesc*) &$1)", result = ropecg(p.module, "((#NimStringDesc*) &$1)",
[getStrLit(p.module, n.strVal)]) [getStrLit(p.module, n.strVal)])
else: else:
result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [toRope(id)]) result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)])
else: else:
result = makeCString(n.strVal) result = makeCString(n.strVal)
of nkFloatLit..nkFloat64Lit: of nkFloatLit..nkFloat64Lit:
result = toRope(n.floatVal.toStrMaxPrecision) result = rope(n.floatVal.toStrMaxPrecision)
else: else:
internalError(n.info, "genLiteral(" & $n.kind & ')') internalError(n.info, "genLiteral(" & $n.kind & ')')
result = nil result = nil
proc genLiteral(p: BProc, n: PNode): PRope = proc genLiteral(p: BProc, n: PNode): Rope =
result = genLiteral(p, n, n.typ) result = genLiteral(p, n, n.typ)
proc bitSetToWord(s: TBitSet, size: int): BiggestInt = proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
@ -113,10 +113,10 @@ proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
for j in countup(0, size - 1): for j in countup(0, size - 1):
if j < len(s): result = result or `shl`(Ze64(s[j]), (Size - 1 - j) * 8) if j < len(s): result = result or `shl`(Ze64(s[j]), (Size - 1 - j) * 8)
proc genRawSetData(cs: TBitSet, size: int): PRope = proc genRawSetData(cs: TBitSet, size: int): Rope =
var frmt: TFormatStr var frmt: FormatStr
if size > 8: if size > 8:
result = ropef("{$n") result = "{$n" % []
for i in countup(0, size - 1): for i in countup(0, size - 1):
if i < size - 1: if i < size - 1:
# not last iteration? # not last iteration?
@ -124,22 +124,22 @@ proc genRawSetData(cs: TBitSet, size: int): PRope =
else: frmt = "0x$1, " else: frmt = "0x$1, "
else: else:
frmt = "0x$1}$n" frmt = "0x$1}$n"
appf(result, frmt, [toRope(toHex(ze64(cs[i]), 2))]) addf(result, frmt, [rope(toHex(ze64(cs[i]), 2))])
else: else:
result = intLiteral(bitSetToWord(cs, size)) result = intLiteral(bitSetToWord(cs, size))
# result := toRope('0x' + ToHex(bitSetToWord(cs, size), size * 2)) # result := rope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
proc genSetNode(p: BProc, n: PNode): PRope = proc genSetNode(p: BProc, n: PNode): Rope =
var cs: TBitSet var cs: TBitSet
var size = int(getSize(n.typ)) var size = int(getSize(n.typ))
toBitSet(n, cs) toBitSet(n, cs)
if size > 8: if size > 8:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
result = con("TMP", toRope(id)) result = "TMP" & rope(id)
if id == gBackendId: if id == gBackendId:
# not found in cache: # not found in cache:
inc(gBackendId) inc(gBackendId)
appf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n", addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)]) [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
else: else:
result = genRawSetData(cs, size) result = genRawSetData(cs, size)
@ -211,12 +211,12 @@ proc asgnComplexity(n: PNode): int =
result += asgnComplexity(t) result += asgnComplexity(t)
else: discard else: discard
proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc = proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc =
assert field != nil assert field != nil
result.k = locField result.k = locField
result.s = a.s result.s = a.s
result.t = t result.t = t
result.r = rdLoc(a).con(".").con(field) result.r = rdLoc(a) & "." & field
result.heapRoot = a.heapRoot result.heapRoot = a.heapRoot
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
@ -230,7 +230,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
let t = skipTypes(dest.t, abstractInst).getUniqueType() let t = skipTypes(dest.t, abstractInst).getUniqueType()
for i in 0 .. <t.len: for i in 0 .. <t.len:
let t = t.sons[i] let t = t.sons[i]
let field = ropef("Field$1", i.toRope) let field = "Field$1" % [i.rope]
genAssignment(p, optAsgnLoc(dest, t, field), genAssignment(p, optAsgnLoc(dest, t, field),
optAsgnLoc(src, t, field), newflags) optAsgnLoc(src, t, field), newflags)
@ -313,8 +313,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
of tyProc: of tyProc:
if needsComplexAssignment(dest.t): if needsComplexAssignment(dest.t):
# optimize closure assignment: # optimize closure assignment:
let a = optAsgnLoc(dest, dest.t, "ClEnv".toRope) let a = optAsgnLoc(dest, dest.t, "ClEnv".rope)
let b = optAsgnLoc(src, dest.t, "ClEnv".toRope) let b = optAsgnLoc(src, dest.t, "ClEnv".rope)
genRefAssign(p, a, b, flags) genRefAssign(p, a, b, flags)
linefmt(p, cpsStmts, "$1.ClPrc = $2.ClPrc;$n", rdLoc(dest), rdLoc(src)) linefmt(p, cpsStmts, "$1.ClPrc = $2.ClPrc;$n", rdLoc(dest), rdLoc(src))
else: else:
@ -365,7 +365,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if mapType(ty) == ctArray: if mapType(ty) == ctArray:
useStringh(p.module) useStringh(p.module)
linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n", linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))) rdLoc(dest), rdLoc(src), rope(getSize(dest.t)))
else: else:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString, of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
@ -391,7 +391,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
if mapType(ty) == ctArray: if mapType(ty) == ctArray:
useStringh(p.module) useStringh(p.module)
linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n", linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))) rdLoc(dest), rdLoc(src), rope(getSize(dest.t)))
else: else:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
of tyPointer, tyChar, tyBool, tyEnum, tyCString, of tyPointer, tyChar, tyBool, tyEnum, tyCString,
@ -409,7 +409,7 @@ proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
else: else:
d = s # ``d`` is free, so fill it with ``s`` d = s # ``d`` is free, so fill it with ``s``
proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) = proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
var a: TLoc var a: TLoc
if d.k != locNone: if d.k != locNone:
# need to generate an assignment here # need to generate an assignment here
@ -424,7 +424,7 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
d.t = t d.t = t
d.r = r d.r = r
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) = proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
var a: TLoc var a: TLoc
if d.k != locNone: if d.k != locNone:
# need to generate an assignment here # need to generate an assignment here
@ -486,9 +486,9 @@ proc unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdCharLoc(a)])) putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdCharLoc(a)]))
proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc; proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
frmt: string): PRope = frmt: string): Rope =
var size = getSize(t) var size = getSize(t)
let storage = if size < platform.intSize: toRope("NI") let storage = if size < platform.intSize: rope("NI")
else: getTypeDesc(p.module, t) else: getTypeDesc(p.module, t)
result = getTempName() result = getTempName()
linefmt(p, cpsLocals, "$1 $2;$n", storage, result) linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
@ -522,11 +522,11 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
# later via 'chckRange' # later via 'chckRange'
let t = e.typ.skipTypes(abstractRange) let t = e.typ.skipTypes(abstractRange)
if optOverflowCheck notin p.options: if optOverflowCheck notin p.options:
let res = ropef(opr[m], [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)]) let res = opr[m] % [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)]
putIntoDest(p, d, e.typ, res) putIntoDest(p, d, e.typ, res)
else: else:
let res = binaryArithOverflowRaw(p, t, a, b, prc[m]) let res = binaryArithOverflowRaw(p, t, a, b, prc[m])
putIntoDest(p, d, e.typ, ropef("($#)($#)", [getTypeDesc(p.module, t), res])) putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, t), res])
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const const
@ -544,7 +544,7 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if optOverflowCheck in p.options: if optOverflowCheck in p.options:
linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n", linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
rdLoc(a), intLiteral(firstOrd(t))) rdLoc(a), intLiteral(firstOrd(t)))
putIntoDest(p, d, e.typ, ropef(opr[m], [rdLoc(a), toRope(getSize(t) * 8)])) putIntoDest(p, d, e.typ, opr[m] % [rdLoc(a), rope(getSize(t) * 8)])
proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const const
@ -613,8 +613,8 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
# BUGFIX: cannot use result-type here, as it may be a boolean # BUGFIX: cannot use result-type here, as it may be a boolean
s = max(getSize(a.t), getSize(b.t)) * 8 s = max(getSize(a.t), getSize(b.t)) * 8
putIntoDest(p, d, e.typ, putIntoDest(p, d, e.typ,
ropef(binArithTab[op], [rdLoc(a), rdLoc(b), toRope(s), binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
getSimpleTypeDesc(p.module, e.typ)])) getSimpleTypeDesc(p.module, e.typ)])
proc genEqProc(p: BProc, e: PNode, d: var TLoc) = proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc var a, b: TLoc
@ -624,10 +624,9 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
if a.t.callConv == ccClosure: if a.t.callConv == ccClosure:
putIntoDest(p, d, e.typ, putIntoDest(p, d, e.typ,
ropef("($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)", [ "($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)" % [rdLoc(a), rdLoc(b)])
rdLoc(a), rdLoc(b)]))
else: else:
putIntoDest(p, d, e.typ, ropef("($1 == $2)", [rdLoc(a), rdLoc(b)])) putIntoDest(p, d, e.typ, "($1 == $2)" % [rdLoc(a), rdLoc(b)])
proc genIsNil(p: BProc, e: PNode, d: var TLoc) = proc genIsNil(p: BProc, e: PNode, d: var TLoc) =
let t = skipTypes(e.sons[1].typ, abstractRange) let t = skipTypes(e.sons[1].typ, abstractRange)
@ -667,8 +666,8 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
t = skipTypes(e.typ, abstractRange) t = skipTypes(e.typ, abstractRange)
putIntoDest(p, d, e.typ, putIntoDest(p, d, e.typ,
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8), unArithTab[op] % [rdLoc(a), rope(getSize(t) * 8),
getSimpleTypeDesc(p.module, e.typ)])) getSimpleTypeDesc(p.module, e.typ)])
proc isCppRef(p: BProc; typ: PType): bool {.inline.} = proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
result = p.module.compileToCpp and result = p.module.compileToCpp and
@ -707,14 +706,14 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
# so the '&' and '*' cancel out: # so the '&' and '*' cancel out:
putIntoDest(p, d, a.t.sons[0], rdLoc(a)) putIntoDest(p, d, a.t.sons[0], rdLoc(a))
else: else:
putIntoDest(p, d, e.typ, ropef("(*$1)", [rdLoc(a)])) putIntoDest(p, d, e.typ, "(*$1)" % [rdLoc(a)])
proc genAddr(p: BProc, e: PNode, d: var TLoc) = proc genAddr(p: BProc, e: PNode, d: var TLoc) =
# careful 'addr(myptrToArray)' needs to get the ampersand: # careful 'addr(myptrToArray)' needs to get the ampersand:
if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}: if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
var a: TLoc var a: TLoc
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
putIntoDest(p, d, e.typ, con("&", a.r)) putIntoDest(p, d, e.typ, "&" & a.r)
#Message(e.info, warnUser, "HERE NEW &") #Message(e.info, warnUser, "HERE NEW &")
elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ): elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
expr(p, e.sons[0], d) expr(p, e.sons[0], d)
@ -747,7 +746,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
case e.sons[1].kind case e.sons[1].kind
of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal) of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem") else: internalError(e.info, "genTupleElem")
appf(r, ".Field$1", [toRope(i)]) addf(r, ".Field$1", [rope(i)])
putIntoDest(p, d, ty.sons[i], r) putIntoDest(p, d, ty.sons[i], r)
proc genRecordField(p: BProc, e: PNode, d: var TLoc) = proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
@ -758,7 +757,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
if ty.kind == tyTuple: if ty.kind == tyTuple:
# we found a unique tuple type which lacks field information # we found a unique tuple type which lacks field information
# so we use Field$i # so we use Field$i
appf(r, ".Field$1", [toRope(f.position)]) addf(r, ".Field$1", [rope(f.position)])
putIntoDest(p, d, f.typ, r) putIntoDest(p, d, f.typ, r)
else: else:
var field: PSym = nil var field: PSym = nil
@ -767,17 +766,17 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
internalError(e.info, "genRecordField") internalError(e.info, "genRecordField")
field = lookupInRecord(ty.n, f.name) field = lookupInRecord(ty.n, f.name)
if field != nil: break if field != nil: break
if not p.module.compileToCpp: app(r, ".Sup") if not p.module.compileToCpp: add(r, ".Sup")
ty = getUniqueType(ty.sons[0]) ty = getUniqueType(ty.sons[0])
if field == nil: internalError(e.info, "genRecordField 2 ") if field == nil: internalError(e.info, "genRecordField 2 ")
if field.loc.r == nil: internalError(e.info, "genRecordField 3") if field.loc.r == nil: internalError(e.info, "genRecordField 3")
appf(r, ".$1", [field.loc.r]) addf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r) putIntoDest(p, d, field.typ, r)
#d.s = a.s #d.s = a.s
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) = proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
var test, u, v: TLoc var test, u, v: TLoc
for i in countup(1, sonsLen(e) - 1): for i in countup(1, sonsLen(e) - 1):
var it = e.sons[i] var it = e.sons[i]
@ -790,12 +789,12 @@ proc genFieldCheck(p: BProc, e: PNode, obj: PRope, field: PSym) =
initLoc(test, locNone, it.typ, OnStack) initLoc(test, locNone, it.typ, OnStack)
initLocExpr(p, it.sons[1], u) initLocExpr(p, it.sons[1], u)
initLoc(v, locExpr, disc.typ, OnUnknown) initLoc(v, locExpr, disc.typ, OnUnknown)
v.r = ropef("$1.$2", [obj, disc.sym.loc.r]) v.r = "$1.$2" % [obj, disc.sym.loc.r]
genInExprAux(p, it, u, v, test) genInExprAux(p, it, u, v, test)
let id = nodeTableTestOrSet(p.module.dataCache, let id = nodeTableTestOrSet(p.module.dataCache,
newStrNode(nkStrLit, field.name.s), gBackendId) newStrNode(nkStrLit, field.name.s), gBackendId)
let strLit = if id == gBackendId: getStrLit(p.module, field.name.s) let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
else: con("TMP", toRope(id)) else: "TMP" & rope(id)
if op.magic == mNot: if op.magic == mNot:
linefmt(p, cpsStmts, linefmt(p, cpsStmts,
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n", "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
@ -811,7 +810,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
a: TLoc a: TLoc
f, field: PSym f, field: PSym
ty: PType ty: PType
r: PRope r: Rope
ty = genRecordFieldAux(p, e.sons[0], d, a) ty = genRecordFieldAux(p, e.sons[0], d, a)
r = rdLoc(a) r = rdLoc(a)
f = e.sons[0].sons[1].sym f = e.sons[0].sons[1].sym
@ -820,13 +819,13 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
assert(ty.kind in {tyTuple, tyObject}) assert(ty.kind in {tyTuple, tyObject})
field = lookupInRecord(ty.n, f.name) field = lookupInRecord(ty.n, f.name)
if field != nil: break if field != nil: break
if not p.module.compileToCpp: app(r, ".Sup") if not p.module.compileToCpp: add(r, ".Sup")
ty = getUniqueType(ty.sons[0]) ty = getUniqueType(ty.sons[0])
if field == nil: internalError(e.info, "genCheckedRecordField") if field == nil: internalError(e.info, "genCheckedRecordField")
if field.loc.r == nil: if field.loc.r == nil:
internalError(e.info, "genCheckedRecordField") # generate the checks: internalError(e.info, "genCheckedRecordField") # generate the checks:
genFieldCheck(p, e, r, field) genFieldCheck(p, e, r, field)
app(r, rfmt(nil, ".$1", field.loc.r)) add(r, rfmt(nil, ".$1", field.loc.r))
putIntoDest(p, d, field.typ, r) putIntoDest(p, d, field.typ, r)
else: else:
genRecordField(p, e.sons[0], d) genRecordField(p, e.sons[0], d)
@ -955,11 +954,11 @@ proc genEcho(p: BProc, n: PNode) =
# is threadsafe. # is threadsafe.
internalAssert n.kind == nkBracket internalAssert n.kind == nkBracket
discard lists.includeStr(p.module.headerFiles, "<stdio.h>") discard lists.includeStr(p.module.headerFiles, "<stdio.h>")
var args: PRope = nil var args: Rope = nil
var a: TLoc var a: TLoc
for i in countup(0, n.len-1): for i in countup(0, n.len-1):
initLocExpr(p, n.sons[i], a) initLocExpr(p, n.sons[i], a)
appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)]) addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
linefmt(p, cpsStmts, "printf($1$2);$n", linefmt(p, cpsStmts, "printf($1$2);$n",
makeCString(repeat("%s", n.len) & tnl), args) makeCString(repeat("%s", n.len) & tnl), args)
@ -986,22 +985,22 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
var a, tmp: TLoc var a, tmp: TLoc
getTemp(p, e.typ, tmp) getTemp(p, e.typ, tmp)
var L = 0 var L = 0
var appends: PRope = nil var appends: Rope = nil
var lens: PRope = nil var lens: Rope = nil
for i in countup(0, sonsLen(e) - 2): for i in countup(0, sonsLen(e) - 2):
# compute the length expression: # compute the length expression:
initLocExpr(p, e.sons[i + 1], a) initLocExpr(p, e.sons[i + 1], a)
if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar: if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
inc(L) inc(L)
app(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a))) add(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
else: else:
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}: if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 1].strVal)) inc(L, len(e.sons[i + 1].strVal))
else: else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)]) addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
app(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a))) add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, toRope(L)) linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
app(p.s(cpsStmts), appends) add(p.s(cpsStmts), appends)
if d.k == locNone: if d.k == locNone:
d = tmp d = tmp
keepAlive(p, tmp) keepAlive(p, tmp)
@ -1023,7 +1022,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
# } # }
var var
a, dest: TLoc a, dest: TLoc
appends, lens: PRope appends, lens: Rope
assert(d.k == locNone) assert(d.k == locNone)
var L = 0 var L = 0
initLocExpr(p, e.sons[1], dest) initLocExpr(p, e.sons[1], dest)
@ -1032,19 +1031,19 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[i + 2], a) initLocExpr(p, e.sons[i + 2], a)
if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar: if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
inc(L) inc(L)
app(appends, rfmt(p.module, "#appendChar($1, $2);$n", add(appends, rfmt(p.module, "#appendChar($1, $2);$n",
rdLoc(dest), rdLoc(a))) rdLoc(dest), rdLoc(a)))
else: else:
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}: if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 2].strVal)) inc(L, len(e.sons[i + 2].strVal))
else: else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)]) addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
app(appends, rfmt(p.module, "#appendString($1, $2);$n", add(appends, rfmt(p.module, "#appendString($1, $2);$n",
rdLoc(dest), rdLoc(a))) rdLoc(dest), rdLoc(a)))
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
rdLoc(dest), lens, toRope(L)) rdLoc(dest), lens, rope(L))
keepAlive(p, dest) keepAlive(p, dest)
app(p.s(cpsStmts), appends) add(p.s(cpsStmts), appends)
gcUsage(e) gcUsage(e)
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
@ -1074,14 +1073,14 @@ proc genReset(p: BProc, n: PNode) =
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange))) addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange)))
proc rawGenNew(p: BProc, a: TLoc, sizeExpr: PRope) = proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
var sizeExpr = sizeExpr var sizeExpr = sizeExpr
let refType = skipTypes(a.t, abstractVarRange) let refType = skipTypes(a.t, abstractVarRange)
var b: TLoc var b: TLoc
initLoc(b, locExpr, a.t, OnHeap) initLoc(b, locExpr, a.t, OnHeap)
if sizeExpr.isNil: if sizeExpr.isNil:
sizeExpr = ropef("sizeof($1)", sizeExpr = "sizeof($1)" %
getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))) [getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))]
let args = [getTypeDesc(p.module, refType), let args = [getTypeDesc(p.module, refType),
genTypeInfo(p.module, refType), genTypeInfo(p.module, refType),
sizeExpr] sizeExpr]
@ -1111,7 +1110,7 @@ proc genNew(p: BProc, e: PNode) =
rawGenNew(p, a, nil) rawGenNew(p, a, nil)
gcUsage(e) gcUsage(e)
proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) = proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
let seqtype = skipTypes(dest.t, abstractVarRange) let seqtype = skipTypes(dest.t, abstractVarRange)
let args = [getTypeDesc(p.module, seqtype), let args = [getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype), length] genTypeInfo(p.module, seqtype), length]
@ -1144,7 +1143,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
if isRef: if isRef:
rawGenNew(p, tmp, nil) rawGenNew(p, tmp, nil)
t = t.lastSon.skipTypes(abstractInst) t = t.lastSon.skipTypes(abstractInst)
r = ropef("(*$1)", r) r = "(*$1)" % [r]
gcUsage(e) gcUsage(e)
else: else:
constructLoc(p, tmp) constructLoc(p, tmp)
@ -1158,13 +1157,13 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
while ty != nil: while ty != nil:
field = lookupInRecord(ty.n, it.sons[0].sym.name) field = lookupInRecord(ty.n, it.sons[0].sym.name)
if field != nil: break if field != nil: break
if not p.module.compileToCpp: app(tmp2.r, ".Sup") if not p.module.compileToCpp: add(tmp2.r, ".Sup")
ty = getUniqueType(ty.sons[0]) ty = getUniqueType(ty.sons[0])
if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr") if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
if it.len == 3 and optFieldCheck in p.options: if it.len == 3 and optFieldCheck in p.options:
genFieldCheck(p, it.sons[2], tmp2.r, field) genFieldCheck(p, it.sons[2], tmp2.r, field)
app(tmp2.r, ".") add(tmp2.r, ".")
app(tmp2.r, field.loc.r) add(tmp2.r, field.loc.r)
tmp2.k = locTemp tmp2.k = locTemp
tmp2.t = field.loc.t tmp2.t = field.loc.t
tmp2.s = if isRef: OnHeap else: OnStack tmp2.s = if isRef: OnHeap else: OnStack
@ -1214,14 +1213,14 @@ proc genNewFinalize(p: BProc, e: PNode) =
var var
a, b, f: TLoc a, b, f: TLoc
refType, bt: PType refType, bt: PType
ti: PRope ti: Rope
oldModule: BModule oldModule: BModule
refType = skipTypes(e.sons[1].typ, abstractVarRange) refType = skipTypes(e.sons[1].typ, abstractVarRange)
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], f) initLocExpr(p, e.sons[2], f)
initLoc(b, locExpr, a.t, OnHeap) initLoc(b, locExpr, a.t, OnHeap)
ti = genTypeInfo(p.module, refType) ti = genTypeInfo(p.module, refType)
appf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [ b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
getTypeDesc(p.module, refType), getTypeDesc(p.module, refType),
ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))]) ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))])
@ -1230,18 +1229,18 @@ proc genNewFinalize(p: BProc, e: PNode) =
genObjectInit(p, cpsStmts, bt, a, false) genObjectInit(p, cpsStmts, bt, a, false)
gcUsage(e) gcUsage(e)
proc genOfHelper(p: BProc; dest: PType; a: PRope): PRope = proc genOfHelper(p: BProc; dest: PType; a: Rope): Rope =
# unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
# have to call it here first: # have to call it here first:
let ti = genTypeInfo(p.module, dest) let ti = genTypeInfo(p.module, dest)
if tfFinal in dest.flags or (p.module.objHasKidsValid and if tfFinal in dest.flags or (p.module.objHasKidsValid and
tfObjHasKids notin dest.flags): tfObjHasKids notin dest.flags):
result = ropef("$1.m_type == $2", a, ti) result = "$1.m_type == $2" % [a, ti]
else: else:
discard cgsym(p.module, "TNimType") discard cgsym(p.module, "TNimType")
inc p.module.labels inc p.module.labels
let cache = con("Nim_OfCheck_CACHE", p.module.labels.toRope) let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope
appf(p.module.s[cfsVars], "static TNimType* $#[2];$n", cache) addf(p.module.s[cfsVars], "static TNimType* $#[2];$n", [cache])
result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache) result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
when false: when false:
# former version: # former version:
@ -1253,7 +1252,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
initLocExpr(p, x, a) initLocExpr(p, x, a)
var dest = skipTypes(typ, typedescPtrs) var dest = skipTypes(typ, typedescPtrs)
var r = rdLoc(a) var r = rdLoc(a)
var nilCheck: PRope = nil var nilCheck: Rope = nil
var t = skipTypes(a.t, abstractInst) var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyPtr, tyRef}: while t.kind in {tyVar, tyPtr, tyRef}:
if t.kind != tyVar: nilCheck = r if t.kind != tyVar: nilCheck = r
@ -1262,7 +1261,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
t = skipTypes(t.lastSon, typedescInst) t = skipTypes(t.lastSon, typedescInst)
if not p.module.compileToCpp: if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil: while t.kind == tyObject and t.sons[0] != nil:
app(r, ~".Sup") add(r, ~".Sup")
t = skipTypes(t.sons[0], typedescInst) t = skipTypes(t.sons[0], typedescInst)
if isObjLackingTypeField(t): if isObjLackingTypeField(t):
globalError(x.info, errGenerated, globalError(x.info, errGenerated,
@ -1303,13 +1302,13 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
var b: TLoc var b: TLoc
case a.t.kind case a.t.kind
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)])) putIntoDest(p, b, e.typ, "$1, $1Len0" % [rdLoc(a)])
of tyString, tySequence: of tyString, tySequence:
putIntoDest(p, b, e.typ, putIntoDest(p, b, e.typ,
ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)])) "$1->data, $1->$2" % [rdLoc(a), lenField(p)])
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
putIntoDest(p, b, e.typ, putIntoDest(p, b, e.typ,
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])) "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))])
else: internalError(e.sons[0].info, "genRepr()") else: internalError(e.sons[0].info, "genRepr()")
putIntoDest(p, d, e.typ, putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
@ -1357,8 +1356,8 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else: unaryExpr(p, e, d, "$1->len") else: unaryExpr(p, e, d, "$1->len")
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
# YYY: length(sideeffect) is optimized away incorrectly? # YYY: length(sideeffect) is optimized away incorrectly?
if op == mHigh: putIntoDest(p, d, e.typ, toRope(lastOrd(typ))) if op == mHigh: putIntoDest(p, d, e.typ, rope(lastOrd(typ)))
else: putIntoDest(p, d, e.typ, toRope(lengthOrd(typ))) else: putIntoDest(p, d, e.typ, rope(lengthOrd(typ)))
else: internalError(e.info, "genArrayLen()") else: internalError(e.info, "genArrayLen()")
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
@ -1396,13 +1395,13 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) =
genAssignment(p, a, b, {}) genAssignment(p, a, b, {})
genAssignment(p, b, tmp, {}) genAssignment(p, b, tmp, {})
proc rdSetElemLoc(a: TLoc, setType: PType): PRope = proc rdSetElemLoc(a: TLoc, setType: PType): Rope =
# read a location of an set element; it may need a subtraction operation # read a location of an set element; it may need a subtraction operation
# before the set operation # before the set operation
result = rdCharLoc(a) result = rdCharLoc(a)
assert(setType.kind == tySet) assert(setType.kind == tySet)
if firstOrd(setType) != 0: if firstOrd(setType) != 0:
result = ropef("($1- $2)", [result, toRope(firstOrd(setType))]) result = "($1- $2)" % [result, rope(firstOrd(setType))]
proc fewCmps(s: PNode): bool = proc fewCmps(s: PNode): bool =
# this function estimates whether it is better to emit code # this function estimates whether it is better to emit code
@ -1416,7 +1415,7 @@ proc fewCmps(s: PNode): bool =
result = sonsLen(s) <= 8 # 8 seems to be a good value result = sonsLen(s) <= 8 # 8 seems to be a good value
proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) = proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)])) putIntoDest(p, d, e.typ, frmt % [rdLoc(a), rdSetElemLoc(b, a.t)])
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) = proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
case int(getSize(skipTypes(e.sons[1].typ, abstractVar))) case int(getSize(skipTypes(e.sons[1].typ, abstractVar)))
@ -1446,19 +1445,19 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
e.sons[2] e.sons[2]
initLocExpr(p, ea, a) initLocExpr(p, ea, a)
initLoc(b, locExpr, e.typ, OnUnknown) initLoc(b, locExpr, e.typ, OnUnknown)
b.r = toRope("(") b.r = rope("(")
var length = sonsLen(e.sons[1]) var length = sonsLen(e.sons[1])
for i in countup(0, length - 1): for i in countup(0, length - 1):
if e.sons[1].sons[i].kind == nkRange: if e.sons[1].sons[i].kind == nkRange:
initLocExpr(p, e.sons[1].sons[i].sons[0], x) initLocExpr(p, e.sons[1].sons[i].sons[0], x)
initLocExpr(p, e.sons[1].sons[i].sons[1], y) initLocExpr(p, e.sons[1].sons[i].sons[1], y)
appf(b.r, "$1 >= $2 && $1 <= $3", addf(b.r, "$1 >= $2 && $1 <= $3",
[rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)]) [rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)])
else: else:
initLocExpr(p, e.sons[1].sons[i], x) initLocExpr(p, e.sons[1].sons[i], x)
appf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)]) addf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
if i < length - 1: app(b.r, " || ") if i < length - 1: add(b.r, " || ")
app(b.r, ")") add(b.r, ")")
putIntoDest(p, d, e.typ, b.r) putIntoDest(p, d, e.typ, b.r)
else: else:
assert(e.sons[1].typ != nil) assert(e.sons[1].typ != nil)
@ -1514,7 +1513,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, getSysType(tyBool), d) if d.k == locNone: getTemp(p, getSysType(tyBool), d)
lineF(p, cpsStmts, lookupOpr[op], lineF(p, cpsStmts, lookupOpr[op],
[rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)]) [rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
of mEqSet: of mEqSet:
useStringh(p.module) useStringh(p.module)
binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)") binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)")
@ -1527,8 +1526,8 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
lineF(p, cpsStmts, lineF(p, cpsStmts,
"for ($1 = 0; $1 < $2; $1++) $n" & "for ($1 = 0; $1 < $2; $1++) $n" &
" $3[$1] = $4[$1] $6 $5[$1];$n", [ " $3[$1] = $4[$1] $6 $5[$1];$n", [
rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b), rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b),
toRope(lookupOpr[op])]) rope(lookupOpr[op])])
of mInSet: genInOp(p, e, d) of mInSet: genInOp(p, e, d)
else: internalError(e.info, "genSetOp") else: internalError(e.info, "genSetOp")
@ -1545,14 +1544,14 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
let etyp = skipTypes(e.typ, abstractRange) let etyp = skipTypes(e.typ, abstractRange)
if etyp.kind in ValueTypes and lfIndirect notin a.flags: if etyp.kind in ValueTypes and lfIndirect notin a.flags:
putIntoDest(p, d, e.typ, ropef("(*($1*) ($2))", putIntoDest(p, d, e.typ, "(*($1*) ($2))" %
[getTypeDesc(p.module, e.typ), addrLoc(a)])) [getTypeDesc(p.module, e.typ), addrLoc(a)])
elif etyp.kind == tyProc and etyp.callConv == ccClosure: elif etyp.kind == tyProc and etyp.callConv == ccClosure:
putIntoDest(p, d, e.typ, ropef("(($1) ($2))", putIntoDest(p, d, e.typ, "(($1) ($2))" %
[getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)])) [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)])
else: else:
putIntoDest(p, d, e.typ, ropef("(($1) ($2))", putIntoDest(p, d, e.typ, "(($1) ($2))" %
[getTypeDesc(p.module, e.typ), rdCharLoc(a)])) [getTypeDesc(p.module, e.typ), rdCharLoc(a)])
proc genCast(p: BProc, e: PNode, d: var TLoc) = proc genCast(p: BProc, e: PNode, d: var TLoc) =
const floatTypes = {tyFloat..tyFloat128} const floatTypes = {tyFloat..tyFloat128}
@ -1562,9 +1561,9 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
if destt.kind in floatTypes or srct.kind in floatTypes: if destt.kind in floatTypes or srct.kind in floatTypes:
# 'cast' and some float type involved? --> use a union. # 'cast' and some float type involved? --> use a union.
inc(p.labels) inc(p.labels)
var lbl = p.labels.toRope var lbl = p.labels.rope
var tmp: TLoc var tmp: TLoc
tmp.r = ropef("LOC$1.source", lbl) tmp.r = "LOC$1.source" % [lbl]
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n", linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl) getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl)
tmp.k = locExpr tmp.k = locExpr
@ -1572,7 +1571,7 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
tmp.s = OnStack tmp.s = OnStack
tmp.flags = {} tmp.flags = {}
expr(p, e.sons[1], tmp) expr(p, e.sons[1], tmp)
putIntoDest(p, d, e.typ, ropef("LOC$#.dest", lbl)) putIntoDest(p, d, e.typ, "LOC$#.dest" % [lbl])
else: else:
# I prefer the shorter cast version for pointer types -> generate less # I prefer the shorter cast version for pointer types -> generate less
# C code; plus it's the right thing to do for closures: # C code; plus it's the right thing to do for closures:
@ -1584,16 +1583,16 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
# range checks for unsigned turned out to be buggy and annoying: # range checks for unsigned turned out to be buggy and annoying:
if optRangeCheck notin p.options or dest.kind in {tyUInt..tyUInt64}: if optRangeCheck notin p.options or dest.kind in {tyUInt..tyUInt64}:
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, n.typ, ropef("(($1) ($2))", putIntoDest(p, d, n.typ, "(($1) ($2))" %
[getTypeDesc(p.module, dest), rdCharLoc(a)])) [getTypeDesc(p.module, dest), rdCharLoc(a)])
else: else:
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
if leValue(n.sons[2], n.sons[1]): if not leValue(n.sons[1], n.sons[2]):
internalError(n.info, "range check will always fail; empty range") internalError(n.info, "range check will always fail; empty range")
putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [ putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
getTypeDesc(p.module, dest), rdCharLoc(a), getTypeDesc(p.module, dest), rdCharLoc(a),
genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest), genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest),
toRope(magic)])) rope(magic)]))
proc genConv(p: BProc, e: PNode, d: var TLoc) = proc genConv(p: BProc, e: PNode, d: var TLoc) =
let destType = e.typ.skipTypes({tyVar, tyGenericInst}) let destType = e.typ.skipTypes({tyVar, tyGenericInst})
@ -1605,8 +1604,7 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) =
proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) = proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc var a: TLoc
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, skipTypes(n.typ, abstractVar), ropef("$1->data", putIntoDest(p, d, skipTypes(n.typ, abstractVar), "$1->data" % [rdLoc(a)])
[rdLoc(a)]))
proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) = proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc var a: TLoc
@ -1641,7 +1639,7 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, rfmt(nil, "(($4)($2) $1 ($4)($3))", putIntoDest(p, d, e.typ, rfmt(nil, "(($4)($2) $1 ($4)($3))",
toRope(opr[m]), rdLoc(a), rdLoc(b), rope(opr[m]), rdLoc(a), rdLoc(b),
getSimpleTypeDesc(p.module, e[1].typ))) getSimpleTypeDesc(p.module, e[1].typ)))
if optNaNCheck in p.options: if optNaNCheck in p.options:
linefmt(p, cpsStmts, "#nanCheck($1);$n", rdLoc(d)) linefmt(p, cpsStmts, "#nanCheck($1);$n", rdLoc(d))
@ -1651,7 +1649,7 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
binaryArith(p, e, d, m) binaryArith(p, e, d, m)
proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var line, filen: PRope var line, filen: Rope
case op case op
of mOr, mAnd: genAndOr(p, e, d, op) of mOr, mAnd: genAndOr(p, e, d, op)
of mNot..mToBiggestInt: unaryArith(p, e, d, op) of mNot..mToBiggestInt: unaryArith(p, e, d, op)
@ -1672,7 +1670,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"$# = #subInt64($#, $#);$n"] "$# = #subInt64($#, $#);$n"]
const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n", const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
"$# = #subInt($#, $#);$n"] "$# = #subInt($#, $#);$n"]
if optOverflowCheck notin p.options: let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
binaryStmt(p, e, d, opr[op]) binaryStmt(p, e, d, opr[op])
else: else:
var a, b: TLoc var a, b: TLoc
@ -1681,12 +1680,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
let ranged = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar}) let ranged = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar})
let res = binaryArithOverflowRaw(p, ranged, a, b, let res = binaryArithOverflowRaw(p, ranged, a, b,
if underlying.kind == tyInt64: fun64[op] else: fun[op]) if underlying.kind == tyInt64: fun64[op] else: fun[op])
putIntoDest(p, a, ranged, ropef("($#)($#)", [ putIntoDest(p, a, ranged, "($#)($#)" % [
getTypeDesc(p.module, ranged), res])) getTypeDesc(p.module, ranged), res])
of mConStrStr: genStrConcat(p, e, d) of mConStrStr: genStrConcat(p, e, d)
of mAppendStrCh: of mAppendStrCh:
@ -1713,8 +1711,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mNewSeq: genNewSeq(p, e) of mNewSeq: genNewSeq(p, e)
of mSizeOf: of mSizeOf:
let t = e.sons[1].typ.skipTypes({tyTypeDesc}) let t = e.sons[1].typ.skipTypes({tyTypeDesc})
putIntoDest(p, d, e.typ, ropef("((NI)sizeof($1))", putIntoDest(p, d, e.typ, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
[getTypeDesc(p.module, t)]))
of mChr: genSomeCast(p, e, d) of mChr: genSomeCast(p, e, d)
of mOrd: genOrd(p, e, d) of mOrd: genOrd(p, e, d)
of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray: of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
@ -1730,7 +1727,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
mParseBiggestFloat: mParseBiggestFloat:
var opr = e.sons[0].sym var opr = e.sons[0].sym
if lfNoDecl notin opr.loc.flags: if lfNoDecl notin opr.loc.flags:
discard cgsym(p.module, opr.loc.r.ropeToStr) discard cgsym(p.module, $opr.loc.r)
genCall(p, e, d) genCall(p, e, d)
of mReset: genReset(p, e) of mReset: genReset(p, e)
of mEcho: genEcho(p, e[1].skipConv) of mEcho: genEcho(p, e[1].skipConv)
@ -1752,17 +1749,17 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mDotDot: genCall(p, e, d) of mDotDot: genCall(p, e, d)
else: internalError(e.info, "genMagicExpr: " & $op) else: internalError(e.info, "genMagicExpr: " & $op)
proc genConstExpr(p: BProc, n: PNode): PRope proc genConstExpr(p: BProc, n: PNode): Rope
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr: if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
var t = getUniqueType(n.typ) var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
fillLoc(d, locData, t, con("TMP", toRope(id)), OnHeap) fillLoc(d, locData, t, "TMP" & rope(id), OnHeap)
if id == gBackendId: if id == gBackendId:
# expression not found in the cache: # expression not found in the cache:
inc(gBackendId) inc(gBackendId)
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), d.r, genConstExpr(p, n)]) [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
result = true result = true
else: else:
@ -1824,13 +1821,12 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
var it = n.sons[i] var it = n.sons[i]
if it.kind == nkExprColonExpr: it = it.sons[1] if it.kind == nkExprColonExpr: it = it.sons[1]
initLoc(rec, locExpr, it.typ, d.s) initLoc(rec, locExpr, it.typ, d.s)
rec.r = ropef("$1.Field$2", [rdLoc(d), toRope(i)]) rec.r = "$1.Field$2" % [rdLoc(d), rope(i)]
expr(p, it, rec) expr(p, it, rec)
when false: when false:
initLoc(rec, locExpr, it.typ, d.s) initLoc(rec, locExpr, it.typ, d.s)
if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genTupleConstr") if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genTupleConstr")
rec.r = ropef("$1.$2", rec.r = "$1.$2" % [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]
[rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)])
expr(p, it, rec) expr(p, it, rec)
proc isConstClosure(n: PNode): bool {.inline.} = proc isConstClosure(n: PNode): bool {.inline.} =
@ -1842,8 +1838,8 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
if isConstClosure(n): if isConstClosure(n):
inc(p.labels) inc(p.labels)
var tmp = con("LOC", toRope(p.labels)) var tmp = "LOC" & rope(p.labels)
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)]) [getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)])
putIntoDest(p, d, n.typ, tmp) putIntoDest(p, d, n.typ, tmp)
else: else:
@ -1861,7 +1857,7 @@ proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
if d.k == locNone: getTemp(p, n.typ, d) if d.k == locNone: getTemp(p, n.typ, d)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
initLoc(arr, locExpr, elemType(skipTypes(n.typ, abstractInst)), d.s) initLoc(arr, locExpr, elemType(skipTypes(n.typ, abstractInst)), d.s)
arr.r = ropef("$1[$2]", [rdLoc(d), intLiteral(i)]) arr.r = "$1[$2]" % [rdLoc(d), intLiteral(i)]
expr(p, n.sons[i], arr) expr(p, n.sons[i], arr)
proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) = proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) =
@ -1880,16 +1876,16 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
var dest = skipTypes(n.typ, abstractPtrs) var dest = skipTypes(n.typ, abstractPtrs)
if optObjCheck in p.options and not isObjLackingTypeField(dest): if optObjCheck in p.options and not isObjLackingTypeField(dest):
var r = rdLoc(a) var r = rdLoc(a)
var nilCheck: PRope = nil var nilCheck: Rope = nil
var t = skipTypes(a.t, abstractInst) var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyPtr, tyRef}: while t.kind in {tyVar, tyPtr, tyRef}:
if t.kind != tyVar: nilCheck = r if t.kind != tyVar: nilCheck = r
if t.kind != tyVar or not p.module.compileToCpp: if t.kind != tyVar or not p.module.compileToCpp:
r = ropef("(*$1)", [r]) r = "(*$1)" % [r]
t = skipTypes(t.lastSon, abstractInst) t = skipTypes(t.lastSon, abstractInst)
if not p.module.compileToCpp: if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil: while t.kind == tyObject and t.sons[0] != nil:
app(r, ".Sup") add(r, ".Sup")
t = skipTypes(t.sons[0], abstractInst) t = skipTypes(t.sons[0], abstractInst)
if nilCheck != nil: if nilCheck != nil:
linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n", linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
@ -1899,10 +1895,10 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
r, genTypeInfo(p.module, dest)) r, genTypeInfo(p.module, dest))
if n.sons[0].typ.kind != tyObject: if n.sons[0].typ.kind != tyObject:
putIntoDest(p, d, n.typ, putIntoDest(p, d, n.typ,
ropef("(($1) ($2))", [getTypeDesc(p.module, n.typ), rdLoc(a)])) "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)])
else: else:
putIntoDest(p, d, n.typ, ropef("(*($1*) ($2))", putIntoDest(p, d, n.typ, "(*($1*) ($2))" %
[getTypeDesc(p.module, dest), addrLoc(a)])) [getTypeDesc(p.module, dest), addrLoc(a)])
proc downConv(p: BProc, n: PNode, d: var TLoc) = proc downConv(p: BProc, n: PNode, d: var TLoc) =
if p.module.compileToCpp: if p.module.compileToCpp:
@ -1919,10 +1915,10 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
var r = rdLoc(a) var r = rdLoc(a)
let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar} let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}
if isRef: if isRef:
app(r, "->Sup") add(r, "->Sup")
else: else:
app(r, ".Sup") add(r, ".Sup")
for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup") for i in countup(2, abs(inheritanceDiff(dest, src))): add(r, ".Sup")
if isRef: if isRef:
# it can happen that we end up generating '&&x->Sup' here, so we pack # it can happen that we end up generating '&&x->Sup' here, so we pack
# the '&x->Sup' into a temporary and then those address is taken # the '&x->Sup' into a temporary and then those address is taken
@ -1933,7 +1929,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
getTemp(p, n.typ, d) getTemp(p, n.typ, d)
linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r) linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
else: else:
r = con("&", r) r = "&" & r
putIntoDest(p, d, n.typ, r) putIntoDest(p, d, n.typ, r)
else: else:
putIntoDest(p, d, n.typ, r) putIntoDest(p, d, n.typ, r)
@ -1942,12 +1938,12 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ) var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
var tmp = con("TMP", toRope(id)) var tmp = "TMP" & rope(id)
if id == gBackendId: if id == gBackendId:
# expression not found in the cache: # expression not found in the cache:
inc(gBackendId) inc(gBackendId)
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)]) [getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
if d.k == locNone: if d.k == locNone:
@ -1982,7 +1978,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else: else:
genComplexConst(p, sym, d) genComplexConst(p, sym, d)
of skEnumField: of skEnumField:
putIntoDest(p, d, n.typ, toRope(sym.position)) putIntoDest(p, d, n.typ, rope(sym.position))
of skVar, skForVar, skResult, skLet: of skVar, skForVar, skResult, skLet:
if sfGlobal in sym.flags: genVarPrototype(p.module, sym) if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil: if sym.loc.r == nil or sym.loc.t == nil:
@ -1991,7 +1987,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if sfThread in sym.flags: if sfThread in sym.flags:
accessThreadLocalVar(p, sym) accessThreadLocalVar(p, sym)
if emulatedThreadVars(): if emulatedThreadVars():
putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r)) putIntoDest(p, d, sym.loc.t, "NimTV->" & sym.loc.r)
else: else:
putLocIntoDest(p, d, sym.loc) putLocIntoDest(p, d, sym.loc)
else: else:
@ -2134,42 +2130,42 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkBreakState: genBreakState(p, n) of nkBreakState: genBreakState(p, n)
else: internalError(n.info, "expr(" & $n.kind & "); unknown node kind") else: internalError(n.info, "expr(" & $n.kind & "); unknown node kind")
proc genNamedConstExpr(p: BProc, n: PNode): PRope = proc genNamedConstExpr(p: BProc, n: PNode): Rope =
if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1]) if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1])
else: result = genConstExpr(p, n) else: result = genConstExpr(p, n)
proc genConstSimpleList(p: BProc, n: PNode): PRope = proc genConstSimpleList(p: BProc, n: PNode): Rope =
var length = sonsLen(n) var length = sonsLen(n)
result = toRope("{") result = rope("{")
for i in countup(0, length - 2): for i in countup(0, length - 2):
appf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])]) addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
if length > 0: app(result, genNamedConstExpr(p, n.sons[length - 1])) if length > 0: add(result, genNamedConstExpr(p, n.sons[length - 1]))
appf(result, "}$n") addf(result, "}$n", [])
proc genConstSeq(p: BProc, n: PNode, t: PType): PRope = proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
var data = ropef("{{$1, $1}", n.len.toRope) var data = "{{$1, $1}" % [n.len.rope]
if n.len > 0: if n.len > 0:
# array part needs extra curlies: # array part needs extra curlies:
data.app(", {") data.add(", {")
for i in countup(0, n.len - 1): for i in countup(0, n.len - 1):
if i > 0: data.appf(",$n") if i > 0: data.addf(",$n", [])
data.app genConstExpr(p, n.sons[i]) data.add genConstExpr(p, n.sons[i])
data.app("}") data.add("}")
data.app("}") data.add("}")
inc(gBackendId) inc(gBackendId)
result = con("CNSTSEQ", gBackendId.toRope) result = "CNSTSEQ" & gBackendId.rope
appcg(p.module, cfsData, appcg(p.module, cfsData,
"NIM_CONST struct {$n" & "NIM_CONST struct {$n" &
" #TGenericSeq Sup;$n" & " #TGenericSeq Sup;$n" &
" $1 data[$2];$n" & " $1 data[$2];$n" &
"} $3 = $4;$n", [ "} $3 = $4;$n", [
getTypeDesc(p.module, t.sons[0]), n.len.toRope, result, data]) getTypeDesc(p.module, t.sons[0]), n.len.rope, result, data])
result = ropef("(($1)&$2)", [getTypeDesc(p.module, t), result]) result = "(($1)&$2)" % [getTypeDesc(p.module, t), result]
proc genConstExpr(p: BProc, n: PNode): PRope = proc genConstExpr(p: BProc, n: PNode): Rope =
case n.kind case n.kind
of nkHiddenStdConv, nkHiddenSubConv: of nkHiddenStdConv, nkHiddenSubConv:
result = genConstExpr(p, n.sons[1]) result = genConstExpr(p, n.sons[1])

View file

@ -45,29 +45,29 @@ const
] ]
NimMergeEndMark = "/*\tNIM_merge_END:*/" NimMergeEndMark = "/*\tNIM_merge_END:*/"
proc genSectionStart*(fs: TCFileSection): PRope = proc genSectionStart*(fs: TCFileSection): Rope =
if compilationCachePresent: if compilationCachePresent:
result = toRope(tnl) result = rope(tnl)
app(result, "/*\t") add(result, "/*\t")
app(result, CFileSectionNames[fs]) add(result, CFileSectionNames[fs])
app(result, ":*/") add(result, ":*/")
app(result, tnl) add(result, tnl)
proc genSectionEnd*(fs: TCFileSection): PRope = proc genSectionEnd*(fs: TCFileSection): Rope =
if compilationCachePresent: if compilationCachePresent:
result = toRope(NimMergeEndMark & tnl) result = rope(NimMergeEndMark & tnl)
proc genSectionStart*(ps: TCProcSection): PRope = proc genSectionStart*(ps: TCProcSection): Rope =
if compilationCachePresent: if compilationCachePresent:
result = toRope(tnl) result = rope(tnl)
app(result, "/*\t") add(result, "/*\t")
app(result, CProcSectionNames[ps]) add(result, CProcSectionNames[ps])
app(result, ":*/") add(result, ":*/")
app(result, tnl) add(result, tnl)
proc genSectionEnd*(ps: TCProcSection): PRope = proc genSectionEnd*(ps: TCProcSection): Rope =
if compilationCachePresent: if compilationCachePresent:
result = toRope(NimMergeEndMark & tnl) result = rope(NimMergeEndMark & tnl)
proc writeTypeCache(a: TIdTable, s: var string) = proc writeTypeCache(a: TIdTable, s: var string) =
var i = 0 var i = 0
@ -79,7 +79,7 @@ proc writeTypeCache(a: TIdTable, s: var string) =
s.add(' ') s.add(' ')
encodeVInt(id, s) encodeVInt(id, s)
s.add(':') s.add(':')
encodeStr(PRope(value).ropeToStr, s) encodeStr($Rope(value), s)
inc i inc i
s.add('}') s.add('}')
@ -95,7 +95,7 @@ proc writeIntSet(a: IntSet, s: var string) =
inc i inc i
s.add('}') s.add('}')
proc genMergeInfo*(m: BModule): PRope = proc genMergeInfo*(m: BModule): Rope =
if optSymbolFiles notin gGlobalOptions: return nil if optSymbolFiles notin gGlobalOptions: return nil
var s = "/*\tNIM_merge_INFO:" var s = "/*\tNIM_merge_INFO:"
s.add(tnl) s.add(tnl)
@ -111,7 +111,7 @@ proc genMergeInfo*(m: BModule): PRope =
encodeVInt(ord(m.frameDeclared), s) encodeVInt(ord(m.frameDeclared), s)
s.add(tnl) s.add(tnl)
s.add("*/") s.add("*/")
result = s.toRope result = s.rope
template `^`(pos: int): expr = L.buf[pos] template `^`(pos: int): expr = L.buf[pos]
@ -145,7 +145,7 @@ proc atEndMark(buf: cstring, pos: int): bool =
while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
result = s == NimMergeEndMark.len result = s == NimMergeEndMark.len
proc readVerbatimSection(L: var TBaseLexer): PRope = proc readVerbatimSection(L: var TBaseLexer): Rope =
var pos = L.bufpos var pos = L.bufpos
var buf = L.buf var buf = L.buf
var r = newStringOfCap(30_000) var r = newStringOfCap(30_000)
@ -169,7 +169,7 @@ proc readVerbatimSection(L: var TBaseLexer): PRope =
r.add(buf[pos]) r.add(buf[pos])
inc pos inc pos
L.bufpos = pos L.bufpos = pos
result = r.toRope result = r.rope
proc readKey(L: var TBaseLexer, result: var string) = proc readKey(L: var TBaseLexer, result: var string) =
var pos = L.bufpos var pos = L.bufpos
@ -197,7 +197,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
# XXX little hack: we create a "fake" type object with the correct Id # XXX little hack: we create a "fake" type object with the correct Id
# better would be to adapt the data structure to not even store the # better would be to adapt the data structure to not even store the
# object as key, but only the Id # object as key, but only the Id
idTablePut(result, newFakeType(key), value.toRope) idTablePut(result, newFakeType(key), value.rope)
inc L.bufpos inc L.bufpos
proc readIntSet(L: var TBaseLexer, result: var IntSet) = proc readIntSet(L: var TBaseLexer, result: var IntSet) =
@ -280,11 +280,11 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
proc mergeRequired*(m: BModule): bool = proc mergeRequired*(m: BModule): bool =
for i in cfsHeaders..cfsProcs: for i in cfsHeaders..cfsProcs:
if m.s[i] != nil: if m.s[i] != nil:
#echo "not empty: ", i, " ", ropeToStr(m.s[i]) #echo "not empty: ", i, " ", m.s[i]
return true return true
for i in low(TCProcSection)..high(TCProcSection): for i in low(TCProcSection)..high(TCProcSection):
if m.initProc.s(i) != nil: if m.initProc.s(i) != nil:
#echo "not empty: ", i, " ", ropeToStr(m.initProc.s[i]) #echo "not empty: ", i, " ", m.initProc.s[i]
return true return true
proc mergeFiles*(cfilename: string, m: BModule) = proc mergeFiles*(cfilename: string, m: BModule) =
@ -293,6 +293,6 @@ proc mergeFiles*(cfilename: string, m: BModule) =
readMergeSections(cfilename, old) readMergeSections(cfilename, old)
# do the merge; old section before new section: # do the merge; old section before new section:
for i in low(TCFileSection)..high(TCFileSection): for i in low(TCFileSection)..high(TCFileSection):
m.s[i] = con(old.f[i], m.s[i]) m.s[i] = old.f[i] & m.s[i]
for i in low(TCProcSection)..high(TCProcSection): for i in low(TCProcSection)..high(TCProcSection):
m.initProc.s(i) = con(old.p[i], m.initProc.s(i)) m.initProc.s(i) = old.p[i] & m.initProc.s(i)

View file

@ -61,11 +61,10 @@ proc genVarTuple(p: BProc, n: PNode) =
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1])) initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1]))
initLoc(field, locExpr, t.sons[i], tup.s) initLoc(field, locExpr, t.sons[i], tup.s)
if t.kind == tyTuple: if t.kind == tyTuple:
field.r = ropef("$1.Field$2", [rdLoc(tup), toRope(i)]) field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else: else:
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple") if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
field.r = ropef("$1.$2", field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
putLocIntoDest(p, v.loc, field) putLocIntoDest(p, v.loc, field)
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
@ -86,8 +85,8 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
else: else:
expr(p, ri, a) expr(p, ri, a)
proc startBlock(p: BProc, start: TFormatStr = "{$n", proc startBlock(p: BProc, start: FormatStr = "{$n",
args: varargs[PRope]): int {.discardable.} = args: varargs[Rope]): int {.discardable.} =
lineCg(p, cpsStmts, start, args) lineCg(p, cpsStmts, start, args)
inc(p.labels) inc(p.labels)
result = len(p.blocks) result = len(p.blocks)
@ -96,21 +95,21 @@ proc startBlock(p: BProc, start: TFormatStr = "{$n",
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16 p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16 p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
proc assignLabel(b: var TBlock): PRope {.inline.} = proc assignLabel(b: var TBlock): Rope {.inline.} =
b.label = con("LA", b.id.toRope) b.label = "LA" & b.id.rope
result = b.label result = b.label
proc blockBody(b: var TBlock): PRope = proc blockBody(b: var TBlock): Rope =
result = b.sections[cpsLocals] result = b.sections[cpsLocals]
if b.frameLen > 0: if b.frameLen > 0:
result.appf("F.len+=$1;$n", b.frameLen.toRope) result.addf("F.len+=$1;$n", [b.frameLen.rope])
result.app(b.sections[cpsInit]) result.add(b.sections[cpsInit])
result.app(b.sections[cpsStmts]) result.add(b.sections[cpsStmts])
proc endBlock(p: BProc, blockEnd: PRope) = proc endBlock(p: BProc, blockEnd: Rope) =
let topBlock = p.blocks.len-1 let topBlock = p.blocks.len-1
# the block is merged into the parent block # the block is merged into the parent block
app(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody) add(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
setLen(p.blocks, topBlock) setLen(p.blocks, topBlock)
# this is done after the block is popped so $n is # this is done after the block is popped so $n is
# properly indented when pretty printing is enabled # properly indented when pretty printing is enabled
@ -124,7 +123,7 @@ proc endBlock(p: BProc) =
~"}$n" ~"}$n"
let frameLen = p.blocks[topBlock].frameLen let frameLen = p.blocks[topBlock].frameLen
if frameLen > 0: if frameLen > 0:
blockEnd.appf("F.len-=$1;$n", frameLen.toRope) blockEnd.addf("F.len-=$1;$n", [frameLen.rope])
endBlock(p, blockEnd) endBlock(p, blockEnd)
proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} = proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
@ -145,7 +144,7 @@ template preserveBreakIdx(body: stmt): stmt {.immediate.} =
proc genState(p: BProc, n: PNode) = proc genState(p: BProc, n: PNode) =
internalAssert n.len == 1 and n.sons[0].kind == nkIntLit internalAssert n.len == 1 and n.sons[0].kind == nkIntLit
let idx = n.sons[0].intVal let idx = n.sons[0].intVal
linefmt(p, cpsStmts, "STATE$1: ;$n", idx.toRope) linefmt(p, cpsStmts, "STATE$1: ;$n", idx.rope)
proc genGotoState(p: BProc, n: PNode) = proc genGotoState(p: BProc, n: PNode) =
# we resist the temptation to translate it into duff's device as it later # we resist the temptation to translate it into duff's device as it later
@ -159,7 +158,7 @@ proc genGotoState(p: BProc, n: PNode) =
p.beforeRetNeeded = true p.beforeRetNeeded = true
lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", []) lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", [])
for i in 0 .. lastOrd(n.sons[0].typ): for i in 0 .. lastOrd(n.sons[0].typ):
lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [toRope(i)]) lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [rope(i)])
lineF(p, cpsStmts, "}$n", []) lineF(p, cpsStmts, "}$n", [])
proc genBreakState(p: BProc, n: PNode) = proc genBreakState(p: BProc, n: PNode) =
@ -214,17 +213,17 @@ proc genSingleVar(p: BProc, a: PNode) =
var tmp: TLoc var tmp: TLoc
if value.kind in nkCallKinds and value[0].kind == nkSym and if value.kind in nkCallKinds and value[0].kind == nkSym and
sfConstructor in value[0].sym.flags: sfConstructor in value[0].sym.flags:
var params: PRope var params: Rope
let typ = skipTypes(value.sons[0].typ, abstractInst) let typ = skipTypes(value.sons[0].typ, abstractInst)
assert(typ.kind == tyProc) assert(typ.kind == tyProc)
for i in 1.. <value.len: for i in 1.. <value.len:
if params != nil: params.app(~", ") if params != nil: params.add(~", ")
assert(sonsLen(typ) == sonsLen(typ.n)) assert(sonsLen(typ) == sonsLen(typ.n))
app(params, genOtherArg(p, value, i, typ)) add(params, genOtherArg(p, value, i, typ))
lineF(p, cpsStmts, "$#($#);$n", decl, params) lineF(p, cpsStmts, "$#($#);$n", [decl, params])
else: else:
initLocExprSingleUse(p, value, tmp) initLocExprSingleUse(p, value, tmp)
lineF(p, cpsStmts, "$# = $#;$n", decl, tmp.rdLoc) lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
return return
assignLocalVar(p, v) assignLocalVar(p, v)
initLocalVar(p, v, imm) initLocalVar(p, v, imm)
@ -298,9 +297,9 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
when not newScopeForIf: startBlock(p) when not newScopeForIf: startBlock(p)
if p.module.compileToCpp: if p.module.compileToCpp:
# avoid "jump to label crosses initialization" error: # avoid "jump to label crosses initialization" error:
app(p.s(cpsStmts), "{") add(p.s(cpsStmts), "{")
expr(p, it.sons[1], d) expr(p, it.sons[1], d)
app(p.s(cpsStmts), "}") add(p.s(cpsStmts), "}")
else: else:
expr(p, it.sons[1], d) expr(p, it.sons[1], d)
endBlock(p) endBlock(p)
@ -389,11 +388,11 @@ proc genComputedGoto(p: BProc; n: PNode) =
localError(n.info, "no case statement found for computed goto"); return localError(n.info, "no case statement found for computed goto"); return
var id = p.labels+1 var id = p.labels+1
inc p.labels, arraySize+1 inc p.labels, arraySize+1
let tmp = ropef("TMP$1", id.toRope) let tmp = "TMP$1" % [id.rope]
var gotoArray = ropef("static void* $#[$#] = {", tmp, arraySize.toRope) var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope]
for i in 1..arraySize-1: for i in 1..arraySize-1:
gotoArray.appf("&&TMP$#, ", (id+i).toRope) gotoArray.addf("&&TMP$#, ", [(id+i).rope])
gotoArray.appf("&&TMP$#};$n", (id+arraySize).toRope) gotoArray.addf("&&TMP$#};$n", [(id+arraySize).rope])
line(p, cpsLocals, gotoArray) line(p, cpsLocals, gotoArray)
let topBlock = p.blocks.len-1 let topBlock = p.blocks.len-1
@ -407,13 +406,13 @@ proc genComputedGoto(p: BProc; n: PNode) =
for j in 0 .. casePos-1: genStmts(p, n.sons[j]) for j in 0 .. casePos-1: genStmts(p, n.sons[j])
let tailA = p.blocks[topBlock].sections[cpsStmts] let tailA = p.blocks[topBlock].sections[cpsStmts]
p.blocks[topBlock].sections[cpsStmts] = oldBody.con(tailA) p.blocks[topBlock].sections[cpsStmts] = oldBody & tailA
let caseStmt = n.sons[casePos] let caseStmt = n.sons[casePos]
var a: TLoc var a: TLoc
initLocExpr(p, caseStmt.sons[0], a) initLocExpr(p, caseStmt.sons[0], a)
# first goto: # first goto:
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc) lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
for i in 1 .. <caseStmt.len: for i in 1 .. <caseStmt.len:
startBlock(p) startBlock(p)
@ -423,16 +422,16 @@ proc genComputedGoto(p: BProc; n: PNode) =
localError(it.info, "range notation not available for computed goto") localError(it.info, "range notation not available for computed goto")
return return
let val = getOrdValue(it.sons[j]) let val = getOrdValue(it.sons[j])
lineF(p, cpsStmts, "TMP$#:$n", intLiteral(val+id+1)) lineF(p, cpsStmts, "TMP$#:$n", [intLiteral(val+id+1)])
genStmts(p, it.lastSon) genStmts(p, it.lastSon)
#for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB #for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB
#for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA #for j in 0 .. casePos-1: genStmts(p, n.sons[j]) # tailA
app(p.s(cpsStmts), tailB) add(p.s(cpsStmts), tailB)
app(p.s(cpsStmts), tailA) add(p.s(cpsStmts), tailA)
var a: TLoc var a: TLoc
initLocExpr(p, caseStmt.sons[0], a) initLocExpr(p, caseStmt.sons[0], a)
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc) lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
endBlock(p) endBlock(p)
proc genWhileStmt(p: BProc, t: PNode) = proc genWhileStmt(p: BProc, t: PNode) =
@ -498,9 +497,9 @@ proc genParForStmt(p: BProc, t: PNode) =
lineF(p, cpsStmts, "#pragma omp parallel for $4$n" & lineF(p, cpsStmts, "#pragma omp parallel for $4$n" &
"for ($1 = $2; $1 <= $3; ++$1)", "for ($1 = $2; $1 <= $3; ++$1)",
forLoopVar.loc.rdLoc, [forLoopVar.loc.rdLoc,
rangeA.rdLoc, rangeB.rdLoc, rangeA.rdLoc, rangeB.rdLoc,
call.sons[3].getStr.toRope) call.sons[3].getStr.rope])
p.breakIdx = startBlock(p) p.breakIdx = startBlock(p)
p.blocks[p.breakIdx].isLoop = true p.blocks[p.breakIdx].isLoop = true
@ -560,7 +559,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
linefmt(p, cpsStmts, "#reraiseException();$n") linefmt(p, cpsStmts, "#reraiseException();$n")
proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
rangeFormat, eqFormat: TFormatStr, labl: TLabel) = rangeFormat, eqFormat: FormatStr, labl: TLabel) =
var var
x, y: TLoc x, y: TLoc
var length = sonsLen(b) var length = sonsLen(b)
@ -578,7 +577,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
labId, until: int): TLabel = labId, until: int): TLabel =
var lend = getLabel(p) var lend = getLabel(p)
for i in 1..until: for i in 1..until:
lineF(p, cpsStmts, "LA$1: ;$n", [toRope(labId + i)]) lineF(p, cpsStmts, "LA$1: ;$n", [rope(labId + i)])
if t.sons[i].kind == nkOfBranch: if t.sons[i].kind == nkOfBranch:
var length = sonsLen(t.sons[i]) var length = sonsLen(t.sons[i])
exprBlock(p, t.sons[i].sons[length - 1], d) exprBlock(p, t.sons[i].sons[length - 1], d)
@ -588,7 +587,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
result = lend result = lend
proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc, proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: TFormatStr, rangeFormat, eqFormat: FormatStr,
until: int, a: TLoc): TLabel = until: int, a: TLoc): TLabel =
# generate a C-if statement for a Nim case statement # generate a C-if statement for a Nim case statement
var labId = p.labels var labId = p.labels
@ -596,27 +595,27 @@ proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
inc(p.labels) inc(p.labels)
if t.sons[i].kind == nkOfBranch: # else statement if t.sons[i].kind == nkOfBranch: # else statement
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat, genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
con("LA", toRope(p.labels))) "LA" & rope(p.labels))
else: else:
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)]) lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
if until < t.len-1: if until < t.len-1:
inc(p.labels) inc(p.labels)
var gotoTarget = p.labels var gotoTarget = p.labels
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(gotoTarget)]) lineF(p, cpsStmts, "goto LA$1;$n", [rope(gotoTarget)])
result = genCaseSecondPass(p, t, d, labId, until) result = genCaseSecondPass(p, t, d, labId, until)
lineF(p, cpsStmts, "LA$1: ;$n", [toRope(gotoTarget)]) lineF(p, cpsStmts, "LA$1: ;$n", [rope(gotoTarget)])
else: else:
result = genCaseSecondPass(p, t, d, labId, until) result = genCaseSecondPass(p, t, d, labId, until)
proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc, proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: TFormatStr) = rangeFormat, eqFormat: FormatStr) =
var a: TLoc var a: TLoc
initLocExpr(p, t.sons[0], a) initLocExpr(p, t.sons[0], a)
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a) var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
fixLabel(p, lend) fixLabel(p, lend)
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel, proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
branches: var openArray[PRope]) = branches: var openArray[Rope]) =
var x: TLoc var x: TLoc
var length = sonsLen(b) var length = sonsLen(b)
for i in countup(0, length - 2): for i in countup(0, length - 2):
@ -634,7 +633,7 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1) if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
if strings > stringCaseThreshold: if strings > stringCaseThreshold:
var bitMask = math.nextPowerOfTwo(strings) - 1 var bitMask = math.nextPowerOfTwo(strings) - 1
var branches: seq[PRope] var branches: seq[Rope]
newSeq(branches, bitMask + 1) newSeq(branches, bitMask + 1)
var a: TLoc var a: TLoc
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto: initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
@ -642,21 +641,21 @@ proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
for i in countup(1, sonsLen(t) - 1): for i in countup(1, sonsLen(t) - 1):
inc(p.labels) inc(p.labels)
if t.sons[i].kind == nkOfBranch: if t.sons[i].kind == nkOfBranch:
genCaseStringBranch(p, t.sons[i], a, con("LA", toRope(p.labels)), genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels),
branches) branches)
else: else:
# else statement: nothing to do yet # else statement: nothing to do yet
# but we reserved a label, which we use later # but we reserved a label, which we use later
discard discard
linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n", linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
rdLoc(a), toRope(bitMask)) rdLoc(a), rope(bitMask))
for j in countup(0, high(branches)): for j in countup(0, high(branches)):
if branches[j] != nil: if branches[j] != nil:
lineF(p, cpsStmts, "case $1: $n$2break;$n", lineF(p, cpsStmts, "case $1: $n$2break;$n",
[intLiteral(j), branches[j]]) [intLiteral(j), branches[j]])
lineF(p, cpsStmts, "}$n") # else statement: lineF(p, cpsStmts, "}$n", []) # else statement:
if t.sons[sonsLen(t)-1].kind != nkOfBranch: if t.sons[sonsLen(t)-1].kind != nkOfBranch:
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)]) lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
# third pass: generate statements # third pass: generate statements
var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1) var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
fixLabel(p, lend) fixLabel(p, lend)
@ -718,13 +717,13 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
genCaseRange(p, branch) genCaseRange(p, branch)
else: else:
# else part of case statement: # else part of case statement:
lineF(p, cpsStmts, "default:$n") lineF(p, cpsStmts, "default:$n", [])
hasDefault = true hasDefault = true
exprBlock(p, branch.lastSon, d) exprBlock(p, branch.lastSon, d)
lineF(p, cpsStmts, "break;$n") lineF(p, cpsStmts, "break;$n", [])
if (hasAssume in CC[cCompiler].props) and not hasDefault: if (hasAssume in CC[cCompiler].props) and not hasDefault:
lineF(p, cpsStmts, "default: __assume(0);$n") lineF(p, cpsStmts, "default: __assume(0);$n", [])
lineF(p, cpsStmts, "}$n") lineF(p, cpsStmts, "}$n", [])
if lend != nil: fixLabel(p, lend) if lend != nil: fixLabel(p, lend)
proc genCase(p: BProc, t: PNode, d: var TLoc) = proc genCase(p: BProc, t: PNode, d: var TLoc) =
@ -774,7 +773,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if not isEmptyType(t.typ) and d.k == locNone: if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d) getTemp(p, t.typ, d)
var var
exc: PRope exc: Rope
i, length, blen: int i, length, blen: int
genLineDir(p, t) genLineDir(p, t)
exc = getTempName() exc = getTempName()
@ -794,16 +793,16 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
var catchAllPresent = false var catchAllPresent = false
while (i < length) and (t.sons[i].kind == nkExceptBranch): while (i < length) and (t.sons[i].kind == nkExceptBranch):
blen = sonsLen(t.sons[i]) blen = sonsLen(t.sons[i])
if i > 1: appf(p.s(cpsStmts), "else ") if i > 1: addf(p.s(cpsStmts), "else ", [])
if blen == 1: if blen == 1:
# general except section: # general except section:
catchAllPresent = true catchAllPresent = true
exprBlock(p, t.sons[i].sons[0], d) exprBlock(p, t.sons[i].sons[0], d)
else: else:
var orExpr: PRope = nil var orExpr: Rope = nil
for j in countup(0, blen - 2): for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType) assert(t.sons[i].sons[j].kind == nkType)
if orExpr != nil: app(orExpr, "||") if orExpr != nil: add(orExpr, "||")
appcg(p.module, orExpr, appcg(p.module, orExpr,
"#isObj($1.exp->m_type, $2)", "#isObj($1.exp->m_type, $2)",
[exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)]) [exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
@ -814,7 +813,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
# reraise the exception if there was no catch all # reraise the exception if there was no catch all
# and none of the handlers matched # and none of the handlers matched
if not catchAllPresent: if not catchAllPresent:
if i > 1: lineF(p, cpsStmts, "else ") if i > 1: lineF(p, cpsStmts, "else ", [])
startBlock(p) startBlock(p)
var finallyBlock = t.lastSon var finallyBlock = t.lastSon
if finallyBlock.kind == nkFinally: if finallyBlock.kind == nkFinally:
@ -824,7 +823,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
line(p, cpsStmts, ~"throw;$n") line(p, cpsStmts, ~"throw;$n")
endBlock(p) endBlock(p)
lineF(p, cpsStmts, "}$n") # end of catch block lineF(p, cpsStmts, "}$n", []) # end of catch block
dec p.inExceptBlock dec p.inExceptBlock
discard pop(p.nestedTryStmts) discard pop(p.nestedTryStmts)
@ -895,17 +894,17 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
var blen = sonsLen(t.sons[i]) var blen = sonsLen(t.sons[i])
if blen == 1: if blen == 1:
# general except section: # general except section:
if i > 1: lineF(p, cpsStmts, "else") if i > 1: lineF(p, cpsStmts, "else", [])
startBlock(p) startBlock(p)
linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint) linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
expr(p, t.sons[i].sons[0], d) expr(p, t.sons[i].sons[0], d)
linefmt(p, cpsStmts, "#popCurrentException();$n") linefmt(p, cpsStmts, "#popCurrentException();$n")
endBlock(p) endBlock(p)
else: else:
var orExpr: PRope = nil var orExpr: Rope = nil
for j in countup(0, blen - 2): for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType) assert(t.sons[i].sons[j].kind == nkType)
if orExpr != nil: app(orExpr, "||") if orExpr != nil: add(orExpr, "||")
appcg(p.module, orExpr, appcg(p.module, orExpr,
"#isObj(#getCurrentException()->Sup.m_type, $1)", "#isObj(#getCurrentException()->Sup.m_type, $1)",
[genTypeInfo(p.module, t.sons[i].sons[j].typ)]) [genTypeInfo(p.module, t.sons[i].sons[j].typ)])
@ -925,7 +924,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
discard pop(p.finallySafePoints) discard pop(p.finallySafePoints)
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint) linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope = proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
var res = "" var res = ""
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
case t.sons[i].kind case t.sons[i].kind
@ -936,7 +935,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}: if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
var a: TLoc var a: TLoc
initLocExpr(p, t.sons[i], a) initLocExpr(p, t.sons[i], a)
res.add(rdLoc(a).ropeToStr) res.add($rdLoc(a))
else: else:
var r = sym.loc.r var r = sym.loc.r
if r == nil: if r == nil:
@ -944,7 +943,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
# it doesn't matter much: # it doesn't matter much:
r = mangleName(sym) r = mangleName(sym)
sym.loc.r = r # but be consequent! sym.loc.r = r # but be consequent!
res.add(r.ropeToStr) res.add($r)
else: internalError(t.sons[i].info, "genAsmOrEmitStmt()") else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
if isAsmStmt and hasGnuAsm in CC[cCompiler].props: if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
@ -954,15 +953,15 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): PRope =
if x[j] in {'"', ':'}: if x[j] in {'"', ':'}:
# don't modify the line if already in quotes or # don't modify the line if already in quotes or
# some clobber register list: # some clobber register list:
app(result, x); app(result, tnl) add(result, x); add(result, tnl)
elif x[j] != '\0': elif x[j] != '\0':
# ignore empty lines # ignore empty lines
app(result, "\"") add(result, "\"")
app(result, x) add(result, x)
app(result, "\\n\"\n") add(result, "\\n\"\n")
else: else:
res.add(tnl) res.add(tnl)
result = res.toRope result = res.rope
proc genAsmStmt(p: BProc, t: PNode) = proc genAsmStmt(p: BProc, t: PNode) =
assert(t.kind == nkAsmStmt) assert(t.kind == nkAsmStmt)
@ -973,7 +972,7 @@ proc genAsmStmt(p: BProc, t: PNode) =
# work: # work:
if p.prc == nil: if p.prc == nil:
# top level asm statement? # top level asm statement?
appf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s]) addf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
else: else:
lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s]) lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
@ -982,14 +981,14 @@ proc genEmit(p: BProc, t: PNode) =
if p.prc == nil: if p.prc == nil:
# top level emit pragma? # top level emit pragma?
genCLineDir(p.module.s[cfsProcHeaders], t.info) genCLineDir(p.module.s[cfsProcHeaders], t.info)
app(p.module.s[cfsProcHeaders], s) add(p.module.s[cfsProcHeaders], s)
else: else:
genLineDir(p, t) genLineDir(p, t)
line(p, cpsStmts, s) line(p, cpsStmts, s)
var var
breakPointId: int = 0 breakPointId: int = 0
gBreakpoints: PRope # later the breakpoints are inserted into the main proc gBreakpoints: Rope # later the breakpoints are inserted into the main proc
proc genBreakPoint(p: BProc, t: PNode) = proc genBreakPoint(p: BProc, t: PNode) =
var name: string var name: string
@ -1003,7 +1002,7 @@ proc genBreakPoint(p: BProc, t: PNode) =
genLineDir(p, t) # BUGFIX genLineDir(p, t) # BUGFIX
appcg(p.module, gBreakpoints, appcg(p.module, gBreakpoints,
"#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [ "#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
toRope(toLinenumber(t.info)), makeCString(toFilename(t.info)), rope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
makeCString(name)]) makeCString(name)])
proc genWatchpoint(p: BProc, n: PNode) = proc genWatchpoint(p: BProc, n: PNode) =

View file

@ -7,7 +7,7 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## Thread var support for crappy architectures that lack native support for ## Thread var support for crappy architectures that lack native support for
## thread local storage. (**Thank you Mac OS X!**) ## thread local storage. (**Thank you Mac OS X!**)
# included from cgen.nim # included from cgen.nim
@ -19,12 +19,12 @@ proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.threadVarAccessed: if emulatedThreadVars() and not p.threadVarAccessed:
p.threadVarAccessed = true p.threadVarAccessed = true
p.module.usesThreadVars = true p.module.usesThreadVars = true
appf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n") addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
app(p.procSec(cpsInit), add(p.procSec(cpsInit),
ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n")) ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
var var
nimtv: PRope # nimrod thread vars; the struct body nimtv: Rope # nimrod thread vars; the struct body
nimtvDeps: seq[PType] = @[] # type deps: every module needs whole struct nimtvDeps: seq[PType] = @[] # type deps: every module needs whole struct
nimtvDeclared = initIntSet() # so that every var/field exists only once nimtvDeclared = initIntSet() # so that every var/field exists only once
# in the struct # in the struct
@ -43,23 +43,23 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
# allocator for it :-( # allocator for it :-(
if not containsOrIncl(nimtvDeclared, s.id): if not containsOrIncl(nimtvDeclared, s.id):
nimtvDeps.add(s.loc.t) nimtvDeps.add(s.loc.t)
appf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r]) addf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
else: else:
if isExtern: app(m.s[cfsVars], "extern ") if isExtern: add(m.s[cfsVars], "extern ")
if optThreads in gGlobalOptions: app(m.s[cfsVars], "NIM_THREADVAR ") if optThreads in gGlobalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
app(m.s[cfsVars], getTypeDesc(m, s.loc.t)) add(m.s[cfsVars], getTypeDesc(m, s.loc.t))
appf(m.s[cfsVars], " $1;$n", [s.loc.r]) addf(m.s[cfsVars], " $1;$n", [s.loc.r])
proc generateThreadLocalStorage(m: BModule) = proc generateThreadLocalStorage(m: BModule) =
if nimtv != nil and (m.usesThreadVars or sfMainModule in m.module.flags): if nimtv != nil and (m.usesThreadVars or sfMainModule in m.module.flags):
for t in items(nimtvDeps): discard getTypeDesc(m, t) for t in items(nimtvDeps): discard getTypeDesc(m, t)
appf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv]) addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
proc generateThreadVarsSize(m: BModule) = proc generateThreadVarsSize(m: BModule) =
if nimtv != nil: if nimtv != nil:
let externc = if gCmd != cmdCompileToCpp and let externc = if gCmd != cmdCompileToCpp and
sfCompileToCpp in m.module.flags: "extern \"C\"" sfCompileToCpp in m.module.flags: "extern \"C\""
else: "" else: ""
appf(m.s[cfsProcs], addf(m.s[cfsProcs],
"$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n", "$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
[externc.toRope]) [externc.rope])

View file

@ -17,11 +17,11 @@ type
p: BProc p: BProc
visitorFrmt: string visitorFrmt: string
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType)
proc genCaseRange(p: BProc, branch: PNode) proc genCaseRange(p: BProc, branch: PNode)
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) = proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, n: PNode) =
if n == nil: return if n == nil: return
case n.kind case n.kind
of nkRecList: of nkRecList:
@ -31,31 +31,31 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc") if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
var p = c.p var p = c.p
let disc = n.sons[0].sym let disc = n.sons[0].sym
lineF(p, cpsStmts, "switch ($1.$2) {$n", accessor, disc.loc.r) lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
let branch = n.sons[i] let branch = n.sons[i]
assert branch.kind in {nkOfBranch, nkElse} assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch: if branch.kind == nkOfBranch:
genCaseRange(c.p, branch) genCaseRange(c.p, branch)
else: else:
lineF(p, cpsStmts, "default:$n") lineF(p, cpsStmts, "default:$n", [])
genTraverseProc(c, accessor, lastSon(branch)) genTraverseProc(c, accessor, lastSon(branch))
lineF(p, cpsStmts, "break;$n") lineF(p, cpsStmts, "break;$n", [])
lineF(p, cpsStmts, "} $n") lineF(p, cpsStmts, "} $n", [])
of nkSym: of nkSym:
let field = n.sym let field = n.sym
if field.loc.t == nil: if field.loc.t == nil:
internalError(n.info, "genTraverseProc()") internalError(n.info, "genTraverseProc()")
genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t) genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
else: internalError(n.info, "genTraverseProc()") else: internalError(n.info, "genTraverseProc()")
proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} = proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
if not m.compileToCpp: if not m.compileToCpp:
result = ropef("$1.Sup", accessor) result = "$1.Sup" % [accessor]
else: else:
result = accessor result = accessor
proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) = proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) =
if typ == nil: return if typ == nil: return
var p = c.p var p = c.p
case typ.kind case typ.kind
@ -66,9 +66,9 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
var i: TLoc var i: TLoc
getTemp(p, getSysType(tyInt), i) getTemp(p, getSysType(tyInt), i)
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
i.r, arraySize.toRope) i.r, arraySize.rope)
genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1]) genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
lineF(p, cpsStmts, "}$n") lineF(p, cpsStmts, "}$n", [])
of tyObject: of tyObject:
for i in countup(0, sonsLen(typ) - 1): for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i]) genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i])
@ -76,7 +76,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
of tyTuple: of tyTuple:
let typ = getUniqueType(typ) let typ = getUniqueType(typ)
for i in countup(0, sonsLen(typ) - 1): for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.toRope), typ.sons[i]) genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i])
of tyRef, tyString, tySequence: of tyRef, tyString, tySequence:
lineCg(p, cpsStmts, c.visitorFrmt, accessor) lineCg(p, cpsStmts, c.visitorFrmt, accessor)
of tyProc: of tyProc:
@ -85,67 +85,67 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
else: else:
discard discard
proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) = proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
var p = c.p var p = c.p
assert typ.kind == tySequence assert typ.kind == tySequence
var i: TLoc var i: TLoc
getTemp(p, getSysType(tyInt), i) getTemp(p, getSysType(tyInt), i)
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n", lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
i.r, accessor, toRope(if c.p.module.compileToCpp: "len" else: "Sup.len")) [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")])
genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0]) genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0])
lineF(p, cpsStmts, "}$n") lineF(p, cpsStmts, "}$n", [])
proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope = proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope =
var c: TTraversalClosure var c: TTraversalClosure
var p = newProc(nil, m) var p = newProc(nil, m)
result = getGlobalTempName() result = getGlobalTempName()
case reason case reason
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n" of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
else: assert false else: assert false
let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result) let header = "N_NIMCALL(void, $1)(void* p, NI op)" % [result]
let t = getTypeDesc(m, typ) let t = getTypeDesc(m, typ)
lineF(p, cpsLocals, "$1 a;$n", t) lineF(p, cpsLocals, "$1 a;$n", [t])
lineF(p, cpsInit, "a = ($1)p;$n", t) lineF(p, cpsInit, "a = ($1)p;$n", [t])
c.p = p c.p = p
assert typ.kind != tyTypeDesc assert typ.kind != tyTypeDesc
if typ.kind == tySequence: if typ.kind == tySequence:
genTraverseProcSeq(c, "a".toRope, typ) genTraverseProcSeq(c, "a".rope, typ)
else: else:
if skipTypes(typ.sons[0], typedescInst).kind in {tyArrayConstr, tyArray}: if skipTypes(typ.sons[0], typedescInst).kind in {tyArrayConstr, tyArray}:
# C's arrays are broken beyond repair: # C's arrays are broken beyond repair:
genTraverseProc(c, "a".toRope, typ.sons[0]) genTraverseProc(c, "a".rope, typ.sons[0])
else: else:
genTraverseProc(c, "(*a)".toRope, typ.sons[0]) genTraverseProc(c, "(*a)".rope, typ.sons[0])
let generatedProc = ropef("$1 {$n$2$3$4}$n",
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
m.s[cfsProcHeaders].appf("$1;$n", header)
m.s[cfsProcs].app(generatedProc)
proc genTraverseProcForGlobal(m: BModule, s: PSym): PRope = let generatedProc = "$1 {$n$2$3$4}$n" %
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
m.s[cfsProcHeaders].addf("$1;$n", [header])
m.s[cfsProcs].add(generatedProc)
proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
discard genTypeInfo(m, s.loc.t) discard genTypeInfo(m, s.loc.t)
var c: TTraversalClosure var c: TTraversalClosure
var p = newProc(nil, m) var p = newProc(nil, m)
var sLoc = s.loc.r var sLoc = s.loc.r
result = getGlobalTempName() result = getGlobalTempName()
if sfThread in s.flags and emulatedThreadVars(): if sfThread in s.flags and emulatedThreadVars():
accessThreadLocalVar(p, s) accessThreadLocalVar(p, s)
sLoc = con("NimTV->", sLoc) sLoc = "NimTV->" & sLoc
c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n" c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
c.p = p c.p = p
let header = ropef("N_NIMCALL(void, $1)()", result) let header = "N_NIMCALL(void, $1)()" % [result]
genTraverseProc(c, sLoc, s.loc.t) genTraverseProc(c, sLoc, s.loc.t)
let generatedProc = ropef("$1 {$n$2$3$4}$n", let generatedProc = "$1 {$n$2$3$4}$n" %
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]) [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
m.s[cfsProcHeaders].appf("$1;$n", header) m.s[cfsProcHeaders].addf("$1;$n", [header])
m.s[cfsProcs].app(generatedProc) m.s[cfsProcs].add(generatedProc)

View file

@ -25,7 +25,7 @@ proc isKeyword(w: PIdent): bool =
ord(wInline): return true ord(wInline): return true
else: return false else: return false
proc mangleName(s: PSym): PRope = proc mangleName(s: PSym): Rope =
result = s.loc.r result = s.loc.r
if result == nil: if result == nil:
when oKeepVariableNames: when oKeepVariableNames:
@ -77,27 +77,27 @@ proc mangleName(s: PSym): PRope =
# These are not properly scoped now - we need to add blocks # These are not properly scoped now - we need to add blocks
# around for loops in transf # around for loops in transf
if keepOrigName: if keepOrigName:
result = s.name.s.mangle.newRope result = s.name.s.mangle.rope
else: else:
app(result, newRope(mangle(s.name.s))) add(result, rope(mangle(s.name.s)))
app(result, ~"_") add(result, ~"_")
app(result, toRope(s.id)) add(result, rope(s.id))
else: else:
app(result, newRope(mangle(s.name.s))) add(result, rope(mangle(s.name.s)))
app(result, ~"_") add(result, ~"_")
app(result, toRope(s.id)) add(result, rope(s.id))
s.loc.r = result s.loc.r = result
proc typeName(typ: PType): PRope = proc typeName(typ: PType): Rope =
result = if typ.sym != nil: typ.sym.name.s.mangle.toRope result = if typ.sym != nil: typ.sym.name.s.mangle.rope
else: ~"TY" else: ~"TY"
proc getTypeName(typ: PType): PRope = proc getTypeName(typ: PType): Rope =
if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}: if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}:
result = typ.sym.loc.r result = typ.sym.loc.r
else: else:
if typ.loc.r == nil: if typ.loc.r == nil:
typ.loc.r = con(typ.typeName, typ.id.toRope) typ.loc.r = typ.typeName & typ.id.rope
result = typ.loc.r result = typ.loc.r
if result == nil: internalError("getTypeName: " & $typ.kind) if result == nil: internalError("getTypeName: " & $typ.kind)
@ -156,7 +156,7 @@ proc isImportedType(t: PType): bool =
proc isImportedCppType(t: PType): bool = proc isImportedCppType(t: PType): bool =
result = t.sym != nil and sfInfixCall in t.sym.flags result = t.sym != nil and sfInfixCall in t.sym.flags
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope
proc needsComplexAssignment(typ: PType): bool = proc needsComplexAssignment(typ: PType): bool =
result = containsGarbageCollectedRef(typ) result = containsGarbageCollectedRef(typ)
@ -189,17 +189,17 @@ const
# but one can #define it to what one wants # but one can #define it to what one wants
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"] "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"]
proc cacheGetType(tab: TIdTable, key: PType): PRope = proc cacheGetType(tab: TIdTable, key: PType): Rope =
# returns nil if we need to declare this type # returns nil if we need to declare this type
# since types are now unique via the ``getUniqueType`` mechanism, this slow # since types are now unique via the ``getUniqueType`` mechanism, this slow
# linear search is not necessary anymore: # linear search is not necessary anymore:
result = PRope(idTableGet(tab, key)) result = Rope(idTableGet(tab, key))
proc getTempName(): PRope = proc getTempName(): Rope =
result = rfmt(nil, "TMP$1", toRope(backendId())) result = rfmt(nil, "TMP$1", rope(backendId()))
proc getGlobalTempName(): PRope = proc getGlobalTempName(): Rope =
result = rfmt(nil, "TMP$1", toRope(backendId())) result = rfmt(nil, "TMP$1", rope(backendId()))
proc ccgIntroducedPtr(s: PSym): bool = proc ccgIntroducedPtr(s: PSym): bool =
var pt = skipTypes(s.typ, typedescInst) var pt = skipTypes(s.typ, typedescInst)
@ -226,13 +226,13 @@ proc fillResult(param: PSym) =
incl(param.loc.flags, lfIndirect) incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown param.loc.s = OnUnknown
proc typeNameOrLiteral(t: PType, literal: string): PRope = proc typeNameOrLiteral(t: PType, literal: string): Rope =
if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone: if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
result = getTypeName(t) result = getTypeName(t)
else: else:
result = toRope(literal) result = rope(literal)
proc getSimpleTypeDesc(m: BModule, typ: PType): PRope = proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
const const
NumericalTypeToStr: array[tyInt..tyUInt64, string] = [ NumericalTypeToStr: array[tyInt..tyUInt64, string] = [
"NI", "NI8", "NI16", "NI32", "NI64", "NI", "NI8", "NI16", "NI32", "NI64",
@ -268,20 +268,20 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
proc pushType(m: BModule, typ: PType) = proc pushType(m: BModule, typ: PType) =
add(m.typeStack, typ) add(m.typeStack, typ)
proc getTypePre(m: BModule, typ: PType): PRope = proc getTypePre(m: BModule, typ: PType): Rope =
if typ == nil: result = toRope("void") if typ == nil: result = rope("void")
else: else:
result = getSimpleTypeDesc(m, typ) result = getSimpleTypeDesc(m, typ)
if result == nil: result = cacheGetType(m.typeCache, typ) if result == nil: result = cacheGetType(m.typeCache, typ)
proc structOrUnion(t: PType): PRope = proc structOrUnion(t: PType): Rope =
(if tfUnion in t.flags: toRope("union") else: toRope("struct")) (if tfUnion in t.flags: rope("union") else: rope("struct"))
proc getForwardStructFormat(m: BModule): string = proc getForwardStructFormat(m: BModule): string =
if m.compileToCpp: result = "$1 $2;$n" if m.compileToCpp: result = "$1 $2;$n"
else: result = "typedef $1 $2 $2;$n" else: result = "typedef $1 $2 $2;$n"
proc getTypeForward(m: BModule, typ: PType): PRope = proc getTypeForward(m: BModule, typ: PType): Rope =
result = cacheGetType(m.forwTypeCache, typ) result = cacheGetType(m.forwTypeCache, typ)
if result != nil: return if result != nil: return
result = getTypePre(m, typ) result = getTypePre(m, typ)
@ -290,12 +290,12 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
of tySequence, tyTuple, tyObject: of tySequence, tyTuple, tyObject:
result = getTypeName(typ) result = getTypeName(typ)
if not isImportedType(typ): if not isImportedType(typ):
appf(m.s[cfsForwardTypes], getForwardStructFormat(m), addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(typ), result]) [structOrUnion(typ), result])
idTablePut(m.forwTypeCache, typ, result) idTablePut(m.forwTypeCache, typ, result)
else: internalError("getTypeForward(" & $typ.kind & ')') else: internalError("getTypeForward(" & $typ.kind & ')')
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): PRope = proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
## like getTypeDescAux but creates only a *weak* dependency. In other words ## like getTypeDescAux but creates only a *weak* dependency. In other words
## we know we only need a pointer to it so we only generate a struct forward ## we know we only need a pointer to it so we only generate a struct forward
## declaration: ## declaration:
@ -310,7 +310,7 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): PRope =
pushType(m, x) pushType(m, x)
of tySequence: of tySequence:
let x = getUniqueType(etB) let x = getUniqueType(etB)
result = getTypeForward(m, x).con("*") result = getTypeForward(m, x) & "*"
pushType(m, x) pushType(m, x)
else: else:
result = getTypeDescAux(m, t, check) result = getTypeDescAux(m, t, check)
@ -321,7 +321,7 @@ proc paramStorageLoc(param: PSym): TStorageLoc =
else: else:
result = OnUnknown result = OnUnknown
proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
check: var IntSet, declareEnvironment=true) = check: var IntSet, declareEnvironment=true) =
params = nil params = nil
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]): if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
@ -332,18 +332,18 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams") if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
var param = t.n.sons[i].sym var param = t.n.sons[i].sym
if isCompileTimeOnly(param.typ): continue if isCompileTimeOnly(param.typ): continue
if params != nil: app(params, ~", ") if params != nil: add(params, ~", ")
fillLoc(param.loc, locParam, param.typ, mangleName(param), fillLoc(param.loc, locParam, param.typ, mangleName(param),
param.paramStorageLoc) param.paramStorageLoc)
if ccgIntroducedPtr(param): if ccgIntroducedPtr(param):
app(params, getTypeDescWeak(m, param.typ, check)) add(params, getTypeDescWeak(m, param.typ, check))
app(params, ~"*") add(params, ~"*")
incl(param.loc.flags, lfIndirect) incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown param.loc.s = OnUnknown
else: else:
app(params, getTypeDescAux(m, param.typ, check)) add(params, getTypeDescAux(m, param.typ, check))
app(params, ~" ") add(params, ~" ")
app(params, param.loc.r) add(params, param.loc.r)
# declare the len field for open arrays: # declare the len field for open arrays:
var arr = param.typ var arr = param.typ
if arr.kind == tyVar: arr = arr.sons[0] if arr.kind == tyVar: arr = arr.sons[0]
@ -352,78 +352,78 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
# this fixes the 'sort' bug: # this fixes the 'sort' bug:
if param.typ.kind == tyVar: param.loc.s = OnUnknown if param.typ.kind == tyVar: param.loc.s = OnUnknown
# need to pass hidden parameter: # need to pass hidden parameter:
appf(params, ", NI $1Len$2", [param.loc.r, j.toRope]) addf(params, ", NI $1Len$2", [param.loc.r, j.rope])
inc(j) inc(j)
arr = arr.sons[0] arr = arr.sons[0]
if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
var arr = t.sons[0] var arr = t.sons[0]
if params != nil: app(params, ", ") if params != nil: add(params, ", ")
if (mapReturnType(t.sons[0]) != ctArray): if (mapReturnType(t.sons[0]) != ctArray):
app(params, getTypeDescWeak(m, arr, check)) add(params, getTypeDescWeak(m, arr, check))
app(params, "*") add(params, "*")
else: else:
app(params, getTypeDescAux(m, arr, check)) add(params, getTypeDescAux(m, arr, check))
appf(params, " Result", []) addf(params, " Result", [])
if t.callConv == ccClosure and declareEnvironment: if t.callConv == ccClosure and declareEnvironment:
if params != nil: app(params, ", ") if params != nil: add(params, ", ")
app(params, "void* ClEnv") add(params, "void* ClEnv")
if tfVarargs in t.flags: if tfVarargs in t.flags:
if params != nil: app(params, ", ") if params != nil: add(params, ", ")
app(params, "...") add(params, "...")
if params == nil: app(params, "void)") if params == nil: add(params, "void)")
else: app(params, ")") else: add(params, ")")
params = con("(", params) params = "(" & params
proc mangleRecFieldName(field: PSym, rectype: PType): PRope = proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
if (rectype.sym != nil) and if (rectype.sym != nil) and
({sfImportc, sfExportc} * rectype.sym.flags != {}): ({sfImportc, sfExportc} * rectype.sym.flags != {}):
result = field.loc.r result = field.loc.r
else: else:
result = toRope(mangleField(field.name.s)) result = rope(mangleField(field.name.s))
if result == nil: internalError(field.info, "mangleRecFieldName") if result == nil: internalError(field.info, "mangleRecFieldName")
proc genRecordFieldsAux(m: BModule, n: PNode, proc genRecordFieldsAux(m: BModule, n: PNode,
accessExpr: PRope, rectype: PType, accessExpr: Rope, rectype: PType,
check: var IntSet): PRope = check: var IntSet): Rope =
var var
ae, uname, sname, a: PRope ae, uname, sname, a: Rope
k: PNode k: PNode
field: PSym field: PSym
result = nil result = nil
case n.kind case n.kind
of nkRecList: of nkRecList:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
app(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check)) add(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
of nkRecCase: of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux") if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux")
app(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check)) add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
uname = toRope(mangle(n.sons[0].sym.name.s) & 'U') uname = rope(mangle(n.sons[0].sym.name.s) & 'U')
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, uname]) if accessExpr != nil: ae = "$1.$2" % [accessExpr, uname]
else: ae = uname else: ae = uname
var unionBody: PRope = nil var unionBody: Rope = nil
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind case n.sons[i].kind
of nkOfBranch, nkElse: of nkOfBranch, nkElse:
k = lastSon(n.sons[i]) k = lastSon(n.sons[i])
if k.kind != nkSym: if k.kind != nkSym:
sname = con("S", toRope(i)) sname = "S" & rope(i)
a = genRecordFieldsAux(m, k, ropef("$1.$2", [ae, sname]), rectype, a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
check) check)
if a != nil: if a != nil:
app(unionBody, "struct {") add(unionBody, "struct {")
app(unionBody, a) add(unionBody, a)
appf(unionBody, "} $1;$n", [sname]) addf(unionBody, "} $1;$n", [sname])
else: else:
app(unionBody, genRecordFieldsAux(m, k, ae, rectype, check)) add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
else: internalError("genRecordFieldsAux(record case branch)") else: internalError("genRecordFieldsAux(record case branch)")
if unionBody != nil: if unionBody != nil:
appf(result, "union{$n$1} $2;$n", [unionBody, uname]) addf(result, "union{$n$1} $2;$n", [unionBody, uname])
of nkSym: of nkSym:
field = n.sym field = n.sym
if field.typ.kind == tyEmpty: return if field.typ.kind == tyEmpty: return
#assert(field.ast == nil) #assert(field.ast == nil)
sname = mangleRecFieldName(field, rectype) sname = mangleRecFieldName(field, rectype)
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname]) if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname]
else: ae = sname else: ae = sname
fillLoc(field.loc, locField, field.typ, ae, OnUnknown) fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
# for importcpp'ed objects, we only need to set field.loc, but don't # for importcpp'ed objects, we only need to set field.loc, but don't
@ -432,27 +432,27 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if not isImportedCppType(rectype): if not isImportedCppType(rectype):
let fieldType = field.loc.t.skipTypes(abstractInst) let fieldType = field.loc.t.skipTypes(abstractInst)
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
appf(result, "$1 $2[SEQ_DECL_SIZE];$n", addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
[getTypeDescAux(m, fieldType.elemType, check), sname]) [getTypeDescAux(m, fieldType.elemType, check), sname])
elif fieldType.kind == tySequence: elif fieldType.kind == tySequence:
# we need to use a weak dependency here for trecursive_table. # we need to use a weak dependency here for trecursive_table.
appf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname]) addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
else: else:
# don't use fieldType here because we need the # don't use fieldType here because we need the
# tyGenericInst for C++ template support # tyGenericInst for C++ template support
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname]) addf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
else: internalError(n.info, "genRecordFieldsAux()") else: internalError(n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope = proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
result = genRecordFieldsAux(m, typ.n, nil, typ, check) result = genRecordFieldsAux(m, typ.n, nil, typ, check)
proc getRecordDesc(m: BModule, typ: PType, name: PRope, proc getRecordDesc(m: BModule, typ: PType, name: Rope,
check: var IntSet): PRope = check: var IntSet): Rope =
# declare the record: # declare the record:
var hasField = false var hasField = false
var attribute: PRope = var attribute: Rope =
if tfPacked in typ.flags: toRope(CC[cCompiler].packedPragma) if tfPacked in typ.flags: rope(CC[cCompiler].packedPragma)
else: nil else: nil
result = ropecg(m, CC[cCompiler].structStmtFmt, result = ropecg(m, CC[cCompiler].structStmtFmt,
@ -475,27 +475,27 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
[getTypeDescAux(m, typ.sons[0], check)]) [getTypeDescAux(m, typ.sons[0], check)])
hasField = true hasField = true
else: else:
appf(result, " {$n", [name]) addf(result, " {$n", [name])
var desc = getRecordFields(m, typ, check) var desc = getRecordFields(m, typ, check)
if desc == nil and not hasField: if desc == nil and not hasField:
appf(result, "char dummy;$n", []) addf(result, "char dummy;$n", [])
else: else:
app(result, desc) add(result, desc)
app(result, "};" & tnl) add(result, "};" & tnl)
proc getTupleDesc(m: BModule, typ: PType, name: PRope, proc getTupleDesc(m: BModule, typ: PType, name: Rope,
check: var IntSet): PRope = check: var IntSet): Rope =
result = ropef("$1 $2 {$n", [structOrUnion(typ), name]) result = "$1 $2 {$n" % [structOrUnion(typ), name]
var desc: PRope = nil var desc: Rope = nil
for i in countup(0, sonsLen(typ) - 1): for i in countup(0, sonsLen(typ) - 1):
appf(desc, "$1 Field$2;$n", addf(desc, "$1 Field$2;$n",
[getTypeDescAux(m, typ.sons[i], check), toRope(i)]) [getTypeDescAux(m, typ.sons[i], check), rope(i)])
if desc == nil: app(result, "char dummy;" & tnl) if desc == nil: add(result, "char dummy;" & tnl)
else: app(result, desc) else: add(result, desc)
app(result, "};" & tnl) add(result, "};" & tnl)
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
# returns only the type's name # returns only the type's name
var t = getUniqueType(typ) var t = getUniqueType(typ)
if t == nil: internalError("getTypeDescAux: t == nil") if t == nil: internalError("getTypeDescAux: t == nil")
@ -523,39 +523,39 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
case etB.kind case etB.kind
of tyObject, tyTuple: of tyObject, tyTuple:
if isImportedCppType(etB) and et.kind == tyGenericInst: if isImportedCppType(etB) and et.kind == tyGenericInst:
result = con(getTypeDescAux(m, et, check), star) result = getTypeDescAux(m, et, check) & star
else: else:
# no restriction! We have a forward declaration for structs # no restriction! We have a forward declaration for structs
let x = getUniqueType(etB) let x = getUniqueType(etB)
let name = getTypeForward(m, x) let name = getTypeForward(m, x)
result = con(name, star) result = name & star
idTablePut(m.typeCache, t, result) idTablePut(m.typeCache, t, result)
pushType(m, x) pushType(m, x)
of tySequence: of tySequence:
# no restriction! We have a forward declaration for structs # no restriction! We have a forward declaration for structs
let x = getUniqueType(etB) let x = getUniqueType(etB)
let name = getTypeForward(m, x) let name = getTypeForward(m, x)
result = con(name, "*" & star) result = name & "*" & star
idTablePut(m.typeCache, t, result) idTablePut(m.typeCache, t, result)
pushType(m, x) pushType(m, x)
else: else:
# else we have a strong dependency :-( # else we have a strong dependency :-(
result = con(getTypeDescAux(m, et, check), star) result = getTypeDescAux(m, et, check) & star
idTablePut(m.typeCache, t, result) idTablePut(m.typeCache, t, result)
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
result = con(getTypeDescAux(m, t.sons[0], check), "*") result = getTypeDescAux(m, t.sons[0], check) & "*"
idTablePut(m.typeCache, t, result) idTablePut(m.typeCache, t, result)
of tyProc: of tyProc:
result = getTypeName(t) result = getTypeName(t)
idTablePut(m.typeCache, t, result) idTablePut(m.typeCache, t, result)
var rettype, desc: PRope var rettype, desc: Rope
genProcParams(m, t, rettype, desc, check) genProcParams(m, t, rettype, desc, check)
if not isImportedType(t): if not isImportedType(t):
if t.callConv != ccClosure: # procedure vars may need a closure! if t.callConv != ccClosure: # procedure vars may need a closure!
appf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n", addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
[toRope(CallingConvToStr[t.callConv]), rettype, result, desc]) [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
else: else:
appf(m.s[cfsTypes], "typedef struct {$n" & addf(m.s[cfsTypes], "typedef struct {$n" &
"N_NIMCALL_PTR($2, ClPrc) $3;$n" & "N_NIMCALL_PTR($2, ClPrc) $3;$n" &
"void* ClEnv;$n} $1;$n", "void* ClEnv;$n} $1;$n",
[result, rettype, desc]) [result, rettype, desc])
@ -566,11 +566,11 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
if result == nil: if result == nil:
result = getTypeName(t) result = getTypeName(t)
if not isImportedType(t): if not isImportedType(t):
appf(m.s[cfsForwardTypes], getForwardStructFormat(m), addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(t), result]) [structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result) idTablePut(m.forwTypeCache, t, result)
assert(cacheGetType(m.typeCache, t) == nil) assert(cacheGetType(m.typeCache, t) == nil)
idTablePut(m.typeCache, t, con(result, "*")) idTablePut(m.typeCache, t, result & "*")
if not isImportedType(t): if not isImportedType(t):
if skipTypes(t.sons[0], typedescInst).kind != tyEmpty: if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
const const
@ -582,8 +582,8 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
" $1 data[SEQ_DECL_SIZE];$n" & " $1 data[SEQ_DECL_SIZE];$n" &
"};$n", [getTypeDescAux(m, t.sons[0], check), result]) "};$n", [getTypeDescAux(m, t.sons[0], check), result])
else: else:
result = toRope("TGenericSeq") result = rope("TGenericSeq")
app(result, "*") add(result, "*")
of tyArrayConstr, tyArray: of tyArrayConstr, tyArray:
var n: BiggestInt = lengthOrd(t) var n: BiggestInt = lengthOrd(t)
if n <= 0: n = 1 # make an array of at least one element if n <= 0: n = 1 # make an array of at least one element
@ -591,17 +591,17 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
idTablePut(m.typeCache, t, result) idTablePut(m.typeCache, t, result)
if not isImportedType(t): if not isImportedType(t):
let foo = getTypeDescAux(m, t.sons[1], check) let foo = getTypeDescAux(m, t.sons[1], check)
appf(m.s[cfsTypes], "typedef $1 $2[$3];$n", addf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
[foo, result, toRope(n)]) [foo, result, rope(n)])
of tyObject, tyTuple: of tyObject, tyTuple:
if isImportedCppType(t) and typ.kind == tyGenericInst: if isImportedCppType(t) and typ.kind == tyGenericInst:
# for instantiated templates we do not go through the type cache as the # for instantiated templates we do not go through the type cache as the
# the type cache is not aware of 'tyGenericInst'. # the type cache is not aware of 'tyGenericInst'.
result = getTypeName(t).con("<") result = getTypeName(t) & "<"
for i in 1 .. typ.len-2: for i in 1 .. typ.len-2:
if i > 1: result.app(", ") if i > 1: result.add(", ")
result.app(getTypeDescAux(m, typ.sons[i], check)) result.add(getTypeDescAux(m, typ.sons[i], check))
result.app("> ") result.add("> ")
# always call for sideeffects: # always call for sideeffects:
assert t.kind != tyTuple assert t.kind != tyTuple
discard getRecordDesc(m, t, result, check) discard getRecordDesc(m, t, result, check)
@ -610,25 +610,25 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
if result == nil: if result == nil:
result = getTypeName(t) result = getTypeName(t)
if not isImportedType(t): if not isImportedType(t):
appf(m.s[cfsForwardTypes], getForwardStructFormat(m), addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
[structOrUnion(t), result]) [structOrUnion(t), result])
idTablePut(m.forwTypeCache, t, result) idTablePut(m.forwTypeCache, t, result)
idTablePut(m.typeCache, t, result) # always call for sideeffects: idTablePut(m.typeCache, t, result) # always call for sideeffects:
let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check) let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
else: getTupleDesc(m, t, result, check) else: getTupleDesc(m, t, result, check)
if not isImportedType(t): app(m.s[cfsTypes], recdesc) if not isImportedType(t): add(m.s[cfsTypes], recdesc)
of tySet: of tySet:
case int(getSize(t)) case int(getSize(t))
of 1: result = toRope("NU8") of 1: result = rope("NU8")
of 2: result = toRope("NU16") of 2: result = rope("NU16")
of 4: result = toRope("NU32") of 4: result = rope("NU32")
of 8: result = toRope("NU64") of 8: result = rope("NU64")
else: else:
result = getTypeName(t) result = getTypeName(t)
idTablePut(m.typeCache, t, result) idTablePut(m.typeCache, t, result)
if not isImportedType(t): if not isImportedType(t):
appf(m.s[cfsTypes], "typedef NU8 $1[$2];$n", addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
[result, toRope(getSize(t))]) [result, rope(getSize(t))])
of tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable, of tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable,
tyIter, tyTypeDesc: tyIter, tyTypeDesc:
result = getTypeDescAux(m, lastSon(t), check) result = getTypeDescAux(m, lastSon(t), check)
@ -638,7 +638,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
# fixes bug #145: # fixes bug #145:
excl(check, t.id) excl(check, t.id)
proc getTypeDesc(m: BModule, typ: PType): PRope = proc getTypeDesc(m: BModule, typ: PType): Rope =
var check = initIntSet() var check = initIntSet()
result = getTypeDescAux(m, typ, check) result = getTypeDescAux(m, typ, check)
@ -646,23 +646,23 @@ type
TClosureTypeKind = enum TClosureTypeKind = enum
clHalf, clHalfWithEnv, clFull clHalf, clHalfWithEnv, clFull
proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): PRope = proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
assert t.kind == tyProc assert t.kind == tyProc
var check = initIntSet() var check = initIntSet()
result = getTempName() result = getTempName()
var rettype, desc: PRope var rettype, desc: Rope
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf) genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
if not isImportedType(t): if not isImportedType(t):
if t.callConv != ccClosure or kind != clFull: if t.callConv != ccClosure or kind != clFull:
appf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n", addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
[toRope(CallingConvToStr[t.callConv]), rettype, result, desc]) [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
else: else:
appf(m.s[cfsTypes], "typedef struct {$n" & addf(m.s[cfsTypes], "typedef struct {$n" &
"N_NIMCALL_PTR($2, ClPrc) $3;$n" & "N_NIMCALL_PTR($2, ClPrc) $3;$n" &
"void* ClEnv;$n} $1;$n", "void* ClEnv;$n} $1;$n",
[result, rettype, desc]) [result, rettype, desc])
proc getTypeDesc(m: BModule, magic: string): PRope = proc getTypeDesc(m: BModule, magic: string): Rope =
var sym = magicsys.getCompilerProc(magic) var sym = magicsys.getCompilerProc(magic)
if sym != nil: if sym != nil:
result = getTypeDesc(m, sym.typ) result = getTypeDesc(m, sym.typ)
@ -678,38 +678,38 @@ proc finishTypeDescriptions(m: BModule) =
template cgDeclFrmt*(s: PSym): string = s.constraint.strVal template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
proc genProcHeader(m: BModule, prc: PSym): PRope = proc genProcHeader(m: BModule, prc: PSym): Rope =
var var
rettype, params: PRope rettype, params: Rope
genCLineDir(result, prc.info) genCLineDir(result, prc.info)
# using static is needed for inline procs # using static is needed for inline procs
if lfExportLib in prc.loc.flags: if lfExportLib in prc.loc.flags:
if m.isHeaderFile: if m.isHeaderFile:
result.app "N_LIB_IMPORT " result.add "N_LIB_IMPORT "
else: else:
result.app "N_LIB_EXPORT " result.add "N_LIB_EXPORT "
elif prc.typ.callConv == ccInline: elif prc.typ.callConv == ccInline:
result.app "static " result.add "static "
var check = initIntSet() var check = initIntSet()
fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown) fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown)
genProcParams(m, prc.typ, rettype, params, check) genProcParams(m, prc.typ, rettype, params, check)
# careful here! don't access ``prc.ast`` as that could reload large parts of # careful here! don't access ``prc.ast`` as that could reload large parts of
# the object graph! # the object graph!
if prc.constraint.isNil: if prc.constraint.isNil:
appf(result, "$1($2, $3)$4", addf(result, "$1($2, $3)$4",
[toRope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r, [rope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
params]) params])
else: else:
result = ropef(prc.cgDeclFrmt, [rettype, prc.loc.r, params]) result = prc.cgDeclFrmt % [rettype, prc.loc.r, params]
# ------------------ type info generation ------------------------------------- # ------------------ type info generation -------------------------------------
proc genTypeInfo(m: BModule, t: PType): PRope proc genTypeInfo(m: BModule, t: PType): Rope
proc getNimNode(m: BModule): PRope = proc getNimNode(m: BModule): Rope =
result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)]) result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
inc(m.typeNodes) inc(m.typeNodes)
proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) = proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: Rope) =
var nimtypeKind: int var nimtypeKind: int
#allocMemTI(m, typ, name) #allocMemTI(m, typ, name)
if isObjLackingTypeField(typ): if isObjLackingTypeField(typ):
@ -717,48 +717,47 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) =
else: else:
nimtypeKind = ord(typ.kind) nimtypeKind = ord(typ.kind)
var size: PRope var size: Rope
if tfIncompleteStruct in typ.flags: size = toRope"void*" if tfIncompleteStruct in typ.flags: size = rope"void*"
elif m.compileToCpp: size = getTypeDesc(m, origType) elif m.compileToCpp: size = getTypeDesc(m, origType)
else: size = getTypeDesc(m, typ) else: size = getTypeDesc(m, typ)
appf(m.s[cfsTypeInit3], addf(m.s[cfsTypeInit3],
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n", "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
[name, size, toRope(nimtypeKind), base]) [name, size, rope(nimtypeKind), base])
# compute type flags for GC optimization # compute type flags for GC optimization
var flags = 0 var flags = 0
if not containsGarbageCollectedRef(typ): flags = flags or 1 if not containsGarbageCollectedRef(typ): flags = flags or 1
if not canFormAcycle(typ): flags = flags or 2 if not canFormAcycle(typ): flags = flags or 2
#else MessageOut("can contain a cycle: " & typeToString(typ)) #else MessageOut("can contain a cycle: " & typeToString(typ))
if flags != 0: if flags != 0:
appf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, toRope(flags)]) addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
discard cgsym(m, "TNimType") discard cgsym(m, "TNimType")
appf(m.s[cfsVars], "TNimType $1; /* $2 */$n", addf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
[name, toRope(typeToString(typ))]) [name, rope(typeToString(typ))])
proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) = proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope) =
var base: PRope var base: Rope
if (sonsLen(typ) > 0) and (typ.sons[0] != nil): if (sonsLen(typ) > 0) and (typ.sons[0] != nil):
base = genTypeInfo(m, typ.sons[0]) base = genTypeInfo(m, typ.sons[0])
else: else:
base = toRope("0") base = rope("0")
genTypeInfoAuxBase(m, typ, origType, name, base) genTypeInfoAuxBase(m, typ, origType, name, base)
proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope = proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
# bugfix: we need to search the type that contains the discriminator: # bugfix: we need to search the type that contains the discriminator:
var objtype = objtype var objtype = objtype
while lookupInRecord(objtype.n, d.name) == nil: while lookupInRecord(objtype.n, d.name) == nil:
objtype = objtype.sons[0] objtype = objtype.sons[0]
if objtype.sym == nil: if objtype.sym == nil:
internalError(d.info, "anonymous obj with discriminator") internalError(d.info, "anonymous obj with discriminator")
result = ropef("NimDT_$1_$2", [ result = "NimDT_$1_$2" % [rope(objtype.id), rope(d.name.s.mangle)]
toRope(objtype.id), toRope(d.name.s.mangle)])
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope = proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")
var tmp = discriminatorTableName(m, objtype, d) var tmp = discriminatorTableName(m, objtype, d)
result = ropef("TNimNode* $1[$2];$n", [tmp, toRope(lengthOrd(d.typ)+1)]) result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(d.typ)+1)]
proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) = proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
case n.kind case n.kind
of nkRecList: of nkRecList:
var L = sonsLen(n) var L = sonsLen(n)
@ -766,29 +765,29 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
genObjectFields(m, typ, n.sons[0], expr) genObjectFields(m, typ, n.sons[0], expr)
elif L > 0: elif L > 0:
var tmp = getTempName() var tmp = getTempName()
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, toRope(L)]) addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
for i in countup(0, L-1): for i in countup(0, L-1):
var tmp2 = getNimNode(m) var tmp2 = getNimNode(m)
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(i), tmp2]) addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
genObjectFields(m, typ, n.sons[i], tmp2) genObjectFields(m, typ, n.sons[i], tmp2)
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n", addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, toRope(L), tmp]) [expr, rope(L), tmp])
else: else:
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, toRope(L)]) addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, rope(L)])
of nkRecCase: of nkRecCase:
assert(n.sons[0].kind == nkSym) assert(n.sons[0].kind == nkSym)
var field = n.sons[0].sym var field = n.sons[0].sym
var tmp = discriminatorTableName(m, typ, field) var tmp = discriminatorTableName(m, typ, field)
var L = lengthOrd(field.typ) var L = lengthOrd(field.typ)
assert L > 0 assert L > 0
appf(m.s[cfsTypeInit3], "$1.kind = 3;$n" & addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n" & "$1.sons = &$6[0];$n" & "$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
"$1.len = $7;$n", [expr, getTypeDesc(m, typ), field.loc.r, "$1.len = $7;$n", [expr, getTypeDesc(m, typ), field.loc.r,
genTypeInfo(m, field.typ), genTypeInfo(m, field.typ),
makeCString(field.name.s), makeCString(field.name.s),
tmp, toRope(L)]) tmp, rope(L)])
appf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, toRope(L+1)]) addf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, rope(L+1)])
for i in countup(1, sonsLen(n)-1): for i in countup(1, sonsLen(n)-1):
var b = n.sons[i] # branch var b = n.sons[i] # branch
var tmp2 = getNimNode(m) var tmp2 = getNimNode(m)
@ -802,60 +801,60 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
var x = int(getOrdValue(b.sons[j].sons[0])) var x = int(getOrdValue(b.sons[j].sons[0]))
var y = int(getOrdValue(b.sons[j].sons[1])) var y = int(getOrdValue(b.sons[j].sons[1]))
while x <= y: while x <= y:
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(x), tmp2]) addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
inc(x) inc(x)
else: else:
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
[tmp, toRope(getOrdValue(b.sons[j])), tmp2]) [tmp, rope(getOrdValue(b.sons[j])), tmp2])
of nkElse: of nkElse:
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
[tmp, toRope(L), tmp2]) [tmp, rope(L), tmp2])
else: internalError(n.info, "genObjectFields(nkRecCase)") else: internalError(n.info, "genObjectFields(nkRecCase)")
of nkSym: of nkSym:
var field = n.sym var field = n.sym
appf(m.s[cfsTypeInit3], "$1.kind = 1;$n" & addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" & "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n", [expr, getTypeDesc(m, typ), "$1.name = $5;$n", [expr, getTypeDesc(m, typ),
field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)]) field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
else: internalError(n.info, "genObjectFields") else: internalError(n.info, "genObjectFields")
proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) = proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name) if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0")) else: genTypeInfoAuxBase(m, typ, origType, name, rope("0"))
var tmp = getNimNode(m) var tmp = getNimNode(m)
if not isImportedCppType(typ): if not isImportedCppType(typ):
genObjectFields(m, typ, typ.n, tmp) genObjectFields(m, typ, typ.n, tmp)
appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp]) addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
var t = typ.sons[0] var t = typ.sons[0]
while t != nil: while t != nil:
t = t.skipTypes(abstractInst) t = t.skipTypes(abstractInst)
t.flags.incl tfObjHasKids t.flags.incl tfObjHasKids
t = t.sons[0] t = t.sons[0]
proc genTupleInfo(m: BModule, typ: PType, name: PRope) = proc genTupleInfo(m: BModule, typ: PType, name: Rope) =
genTypeInfoAuxBase(m, typ, typ, name, toRope("0")) genTypeInfoAuxBase(m, typ, typ, name, rope("0"))
var expr = getNimNode(m) var expr = getNimNode(m)
var length = sonsLen(typ) var length = sonsLen(typ)
if length > 0: if length > 0:
var tmp = getTempName() var tmp = getTempName()
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, toRope(length)]) addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)])
for i in countup(0, length - 1): for i in countup(0, length - 1):
var a = typ.sons[i] var a = typ.sons[i]
var tmp2 = getNimNode(m) var tmp2 = getNimNode(m)
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(i), tmp2]) addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
appf(m.s[cfsTypeInit3], "$1.kind = 1;$n" & addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
"$1.offset = offsetof($2, Field$3);$n" & "$1.offset = offsetof($2, Field$3);$n" &
"$1.typ = $4;$n" & "$1.typ = $4;$n" &
"$1.name = \"Field$3\";$n", "$1.name = \"Field$3\";$n",
[tmp2, getTypeDesc(m, typ), toRope(i), genTypeInfo(m, a)]) [tmp2, getTypeDesc(m, typ), rope(i), genTypeInfo(m, a)])
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n", addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, toRope(length), tmp]) [expr, rope(length), tmp])
else: else:
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
[expr, toRope(length)]) [expr, rope(length)])
appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr]) addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr])
proc genEnumInfo(m: BModule, typ: PType, name: PRope) = proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
# Type information for enumerations is quite heavy, so we do some # Type information for enumerations is quite heavy, so we do some
# optimizations here: The ``typ`` field is never set, as it is redundant # optimizations here: The ``typ`` field is never set, as it is redundant
# anyway. We generate a cstring array and a loop over it. Exceptional # anyway. We generate a cstring array and a loop over it. Exceptional
@ -863,9 +862,9 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
genTypeInfoAux(m, typ, typ, name) genTypeInfoAux(m, typ, typ, name)
var nodePtrs = getTempName() var nodePtrs = getTempName()
var length = sonsLen(typ.n) var length = sonsLen(typ.n)
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
[nodePtrs, toRope(length)]) [nodePtrs, rope(length)])
var enumNames, specialCases: PRope var enumNames, specialCases: Rope
var firstNimNode = m.typeNodes var firstNimNode = m.typeNodes
var hasHoles = false var hasHoles = false
for i in countup(0, length - 1): for i in countup(0, length - 1):
@ -874,38 +873,38 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
var elemNode = getNimNode(m) var elemNode = getNimNode(m)
if field.ast == nil: if field.ast == nil:
# no explicit string literal for the enum field, so use field.name: # no explicit string literal for the enum field, so use field.name:
app(enumNames, makeCString(field.name.s)) add(enumNames, makeCString(field.name.s))
else: else:
app(enumNames, makeCString(field.ast.strVal)) add(enumNames, makeCString(field.ast.strVal))
if i < length - 1: app(enumNames, ", " & tnl) if i < length - 1: add(enumNames, ", " & tnl)
if field.position != i or tfEnumHasHoles in typ.flags: if field.position != i or tfEnumHasHoles in typ.flags:
appf(specialCases, "$1.offset = $2;$n", [elemNode, toRope(field.position)]) addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
hasHoles = true hasHoles = true
var enumArray = getTempName() var enumArray = getTempName()
var counter = getTempName() var counter = getTempName()
appf(m.s[cfsTypeInit1], "NI $1;$n", [counter]) addf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
appf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n", addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
[enumArray, toRope(length), enumNames]) [enumArray, rope(length), enumNames])
appf(m.s[cfsTypeInit3], "for ($1 = 0; $1 < $2; $1++) {$n" & addf(m.s[cfsTypeInit3], "for ($1 = 0; $1 < $2; $1++) {$n" &
"$3[$1+$4].kind = 1;$n" & "$3[$1+$4].offset = $1;$n" & "$3[$1+$4].kind = 1;$n" & "$3[$1+$4].offset = $1;$n" &
"$3[$1+$4].name = $5[$1];$n" & "$6[$1] = &$3[$1+$4];$n" & "}$n", [counter, "$3[$1+$4].name = $5[$1];$n" & "$6[$1] = &$3[$1+$4];$n" & "}$n", [counter,
toRope(length), m.typeNodesName, toRope(firstNimNode), enumArray, nodePtrs]) rope(length), m.typeNodesName, rope(firstNimNode), enumArray, nodePtrs])
app(m.s[cfsTypeInit3], specialCases) add(m.s[cfsTypeInit3], specialCases)
appf(m.s[cfsTypeInit3], addf(m.s[cfsTypeInit3],
"$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4.node = &$1;$n", "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4.node = &$1;$n",
[getNimNode(m), toRope(length), nodePtrs, name]) [getNimNode(m), rope(length), nodePtrs, name])
if hasHoles: if hasHoles:
# 1 << 2 is {ntfEnumHole} # 1 << 2 is {ntfEnumHole}
appf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name]) addf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name])
proc genSetInfo(m: BModule, typ: PType, name: PRope) = proc genSetInfo(m: BModule, typ: PType, name: Rope) =
assert(typ.sons[0] != nil) assert(typ.sons[0] != nil)
genTypeInfoAux(m, typ, typ, name) genTypeInfoAux(m, typ, typ, name)
var tmp = getNimNode(m) var tmp = getNimNode(m)
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n", addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
[tmp, toRope(firstOrd(typ)), name]) [tmp, rope(firstOrd(typ)), name])
proc genArrayInfo(m: BModule, typ: PType, name: PRope) = proc genArrayInfo(m: BModule, typ: PType, name: Rope) =
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1])) genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
proc fakeClosureType(owner: PSym): PType = proc fakeClosureType(owner: PSym): PType =
@ -925,17 +924,17 @@ type
include ccgtrav include ccgtrav
proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) = proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
genProc(m, s) genProc(m, s)
appf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n", addf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
[result, s.loc.r]) [result, s.loc.r])
proc genTypeInfo(m: BModule, t: PType): PRope = proc genTypeInfo(m: BModule, t: PType): Rope =
let origType = t let origType = t
var t = getUniqueType(t) var t = getUniqueType(t)
result = ropef("NTI$1", [toRope(t.id)]) result = "NTI$1" % [rope(t.id)]
if containsOrIncl(m.typeInfoMarker, t.id): if containsOrIncl(m.typeInfoMarker, t.id):
return con("(&".toRope, result, ")".toRope) return "(&".rope & result & ")".rope
# getUniqueType doesn't skip tyDistinct when that has an overriden operation: # getUniqueType doesn't skip tyDistinct when that has an overriden operation:
while t.kind == tyDistinct: t = t.lastSon while t.kind == tyDistinct: t = t.lastSon
@ -946,23 +945,23 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
# reference the type info as extern here # reference the type info as extern here
discard cgsym(m, "TNimType") discard cgsym(m, "TNimType")
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")
appf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n", addf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n",
[result, toRope(typeToString(t))]) [result, rope(typeToString(t))])
return con("(&".toRope, result, ")".toRope) return "(&".rope & result & ")".rope
case t.kind case t.kind
of tyEmpty: result = toRope"0" of tyEmpty: result = rope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar: of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
genTypeInfoAuxBase(m, t, t, result, toRope"0") genTypeInfoAuxBase(m, t, t, result, rope"0")
of tyProc: of tyProc:
if t.callConv != ccClosure: if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, t, result, toRope"0") genTypeInfoAuxBase(m, t, t, result, rope"0")
else: else:
genTupleInfo(m, fakeClosureType(t.owner), result) genTupleInfo(m, fakeClosureType(t.owner), result)
of tySequence, tyRef: of tySequence, tyRef:
genTypeInfoAux(m, t, t, result) genTypeInfoAux(m, t, t, result)
if gSelectedGC >= gcMarkAndSweep: if gSelectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, t, tiNew) let markerProc = genTraverseProc(m, t, tiNew)
appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc]) addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
of tyPtr, tyRange: genTypeInfoAux(m, t, t, result) of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
of tyArrayConstr, tyArray: genArrayInfo(m, t, result) of tyArrayConstr, tyArray: genArrayInfo(m, t, result)
of tySet: genSetInfo(m, t, result) of tySet: genSetInfo(m, t, result)
@ -979,7 +978,7 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
genDeepCopyProc(m, t.deepCopy, result) genDeepCopyProc(m, t.deepCopy, result)
elif origType.deepCopy != nil: elif origType.deepCopy != nil:
genDeepCopyProc(m, origType.deepCopy, result) genDeepCopyProc(m, origType.deepCopy, result)
result = con("(&".toRope, result, ")".toRope) result = "(&".rope & result & ")".rope
proc genTypeSection(m: BModule, n: PNode) = proc genTypeSection(m: BModule, n: PNode) =
discard discard

View file

@ -193,13 +193,13 @@ proc mangle*(name: string): string =
else: else:
add(result, "HEX" & toHex(ord(c), 2)) add(result, "HEX" & toHex(ord(c), 2))
proc makeLLVMString*(s: string): PRope = proc makeLLVMString*(s: string): Rope =
const MaxLineLength = 64 const MaxLineLength = 64
result = nil result = nil
var res = "c\"" var res = "c\""
for i in countup(0, len(s) - 1): for i in countup(0, len(s) - 1):
if (i + 1) mod MaxLineLength == 0: if (i + 1) mod MaxLineLength == 0:
app(result, toRope(res)) add(result, rope(res))
setLen(res, 0) setLen(res, 0)
case s[i] case s[i]
of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\': of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
@ -207,6 +207,6 @@ proc makeLLVMString*(s: string): PRope =
add(res, toHex(ord(s[i]), 2)) add(res, toHex(ord(s[i]), 2))
else: add(res, s[i]) else: add(res, s[i])
add(res, "\\00\"") add(res, "\\00\"")
app(result, toRope(res)) add(result, rope(res))
initTypeTables() initTypeTables()

View file

@ -10,13 +10,15 @@
## This module implements the C code generator. ## This module implements the C code generator.
import import
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, ast, astalgo, hashes, trees, platform, magicsys, extccomp,
options, intsets, options, intsets,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
semparallel semparallel
import strutils except `%` # collides with ropes.`%`
when options.hasTinyCBackend: when options.hasTinyCBackend:
import tccgen import tccgen
@ -48,7 +50,7 @@ proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
result.r = nil result.r = nil
result.flags = {} result.flags = {}
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) = proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: Rope, s: TStorageLoc) =
# fills the loc if it is not already initialized # fills the loc if it is not already initialized
if a.k == locNone: if a.k == locNone:
a.k = k a.k = k
@ -72,9 +74,9 @@ proc useHeader(m: BModule, sym: PSym) =
assert(sym.annex != nil) assert(sym.annex != nil)
discard lists.includeStr(m.headerFiles, getStr(sym.annex.path)) discard lists.includeStr(m.headerFiles, getStr(sym.annex.path))
proc cgsym(m: BModule, name: string): PRope proc cgsym(m: BModule, name: string): Rope
proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope = proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
var i = 0 var i = 0
var length = len(frmt) var length = len(frmt)
result = nil result = nil
@ -84,11 +86,11 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
inc(i) # skip '$' inc(i) # skip '$'
case frmt[i] case frmt[i]
of '$': of '$':
app(result, "$") add(result, "$")
inc(i) inc(i)
of '#': of '#':
inc(i) inc(i)
app(result, args[num]) add(result, args[num])
inc(num) inc(num)
of '0'..'9': of '0'..'9':
var j = 0 var j = 0
@ -99,12 +101,12 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
num = j num = j
if j > high(args) + 1: if j > high(args) + 1:
internalError("ropes: invalid format string $" & $j) internalError("ropes: invalid format string $" & $j)
app(result, args[j-1]) add(result, args[j-1])
of 'n': of 'n':
if optLineDir notin gOptions: app(result, rnl) if optLineDir notin gOptions: add(result, rnl)
inc(i) inc(i)
of 'N': of 'N':
app(result, rnl) add(result, rnl)
inc(i) inc(i)
else: internalError("ropes: invalid format string $" & frmt[i]) else: internalError("ropes: invalid format string $" & frmt[i])
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars: elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
@ -113,74 +115,74 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
while frmt[j] in IdentChars: inc(j) while frmt[j] in IdentChars: inc(j)
var ident = substr(frmt, i, j-1) var ident = substr(frmt, i, j-1)
i = j i = j
app(result, cgsym(m, ident)) add(result, cgsym(m, ident))
elif frmt[i] == '#' and frmt[i+1] == '$': elif frmt[i] == '#' and frmt[i+1] == '$':
inc(i, 2) inc(i, 2)
var j = 0 var j = 0
while frmt[i] in Digits: while frmt[i] in Digits:
j = (j * 10) + ord(frmt[i]) - ord('0') j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i) inc(i)
app(result, cgsym(m, args[j-1].ropeToStr)) add(result, cgsym(m, $args[j-1]))
var start = i var start = i
while i < length: while i < length:
if frmt[i] != '$' and frmt[i] != '#': inc(i) if frmt[i] != '$' and frmt[i] != '#': inc(i)
else: break else: break
if i - 1 >= start: if i - 1 >= start:
app(result, substr(frmt, start, i - 1)) add(result, substr(frmt, start, i - 1))
template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr = template rfmt(m: BModule, fmt: string, args: varargs[Rope]): expr =
ropecg(m, fmt, args) ropecg(m, fmt, args)
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr, proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
args: varargs[PRope]) = args: varargs[Rope]) =
app(c, ropecg(m, frmt, args)) add(c, ropecg(m, frmt, args))
proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr, proc appcg(m: BModule, s: TCFileSection, frmt: FormatStr,
args: varargs[PRope]) = args: varargs[Rope]) =
app(m.s[s], ropecg(m, frmt, args)) add(m.s[s], ropecg(m, frmt, args))
proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr, proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
args: varargs[PRope]) = args: varargs[Rope]) =
app(p.s(s), ropecg(p.module, frmt, args)) add(p.s(s), ropecg(p.module, frmt, args))
var indent = "\t".toRope var indent = "\t".rope
proc indentLine(p: BProc, r: PRope): PRope = proc indentLine(p: BProc, r: Rope): Rope =
result = r result = r
for i in countup(0, p.blocks.len-1): prepend(result, indent) for i in countup(0, p.blocks.len-1): prepend(result, indent)
proc line(p: BProc, s: TCProcSection, r: PRope) = proc line(p: BProc, s: TCProcSection, r: Rope) =
app(p.s(s), indentLine(p, r)) add(p.s(s), indentLine(p, r))
proc line(p: BProc, s: TCProcSection, r: string) = proc line(p: BProc, s: TCProcSection, r: string) =
app(p.s(s), indentLine(p, r.toRope)) add(p.s(s), indentLine(p, r.rope))
proc lineF(p: BProc, s: TCProcSection, frmt: TFormatStr, proc lineF(p: BProc, s: TCProcSection, frmt: FormatStr,
args: varargs[PRope]) = args: openarray[Rope]) =
app(p.s(s), indentLine(p, ropef(frmt, args))) add(p.s(s), indentLine(p, frmt % args))
proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr, proc lineCg(p: BProc, s: TCProcSection, frmt: FormatStr,
args: varargs[PRope]) = args: varargs[Rope]) =
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args))) add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr, proc linefmt(p: BProc, s: TCProcSection, frmt: FormatStr,
args: varargs[PRope]) = args: varargs[Rope]) =
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args))) add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr, proc appLineCg(p: BProc, r: var Rope, frmt: FormatStr,
args: varargs[PRope]) = args: varargs[Rope]) =
app(r, indentLine(p, ropecg(p.module, frmt, args))) add(r, indentLine(p, ropecg(p.module, frmt, args)))
proc safeLineNm(info: TLineInfo): int = proc safeLineNm(info: TLineInfo): int =
result = toLinenumber(info) result = toLinenumber(info)
if result < 0: result = 0 # negative numbers are not allowed in #line if result < 0: result = 0 # negative numbers are not allowed in #line
proc genCLineDir(r: var PRope, filename: string, line: int) = proc genCLineDir(r: var Rope, filename: string, line: int) =
assert line >= 0 assert line >= 0
if optLineDir in gOptions: if optLineDir in gOptions:
appf(r, "$N#line $2 $1$N", addf(r, "$N#line $2 $1$N",
[toRope(makeSingleLineCString(filename)), toRope(line)]) [rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var PRope, info: TLineInfo) = proc genCLineDir(r: var Rope, info: TLineInfo) =
genCLineDir(r, info.toFullPath, info.safeLineNm) genCLineDir(r, info.toFullPath, info.safeLineNm)
proc freshLineInfo(p: BProc; info: TLineInfo): bool = proc freshLineInfo(p: BProc; info: TLineInfo): bool =
@ -193,22 +195,22 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
proc genLineDir(p: BProc, t: PNode) = proc genLineDir(p: BProc, t: PNode) =
var line = t.info.safeLineNm var line = t.info.safeLineNm
if optEmbedOrigSrc in gGlobalOptions: if optEmbedOrigSrc in gGlobalOptions:
app(p.s(cpsStmts), con(~"//", t.info.sourceLine, rnl)) add(p.s(cpsStmts), ~"//" & t.info.sourceLine & rnl)
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line) genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags): (p.prc == nil or sfPure notin p.prc.flags):
if freshLineInfo(p, t.info): if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "#endb($1, $2);$n", linefmt(p, cpsStmts, "#endb($1, $2);$n",
line.toRope, makeCString(toFilename(t.info))) line.rope, makeCString(toFilename(t.info)))
elif ({optLineTrace, optStackTrace} * p.options == elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0: (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0:
if freshLineInfo(p, t.info): if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "nimln($1, $2);$n", linefmt(p, cpsStmts, "nimln($1, $2);$n",
line.toRope, t.info.quotedFilename) line.rope, t.info.quotedFilename)
proc postStmtActions(p: BProc) {.inline.} = proc postStmtActions(p: BProc) {.inline.} =
app(p.s(cpsStmts), p.module.injectStmt) add(p.s(cpsStmts), p.module.injectStmt)
proc accessThreadLocalVar(p: BProc, s: PSym) proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(): bool {.inline.} proc emulatedThreadVars(): bool {.inline.}
@ -221,21 +223,21 @@ include "ccgtypes.nim"
# ------------------------------ Manager of temporaries ------------------ # ------------------------------ Manager of temporaries ------------------
proc rdLoc(a: TLoc): PRope = proc rdLoc(a: TLoc): Rope =
# 'read' location (deref if indirect) # 'read' location (deref if indirect)
result = a.r result = a.r
if lfIndirect in a.flags: result = ropef("(*$1)", [result]) if lfIndirect in a.flags: result = "(*$1)" % [result]
proc addrLoc(a: TLoc): PRope = proc addrLoc(a: TLoc): Rope =
result = a.r result = a.r
if lfIndirect notin a.flags and mapType(a.t) != ctArray: if lfIndirect notin a.flags and mapType(a.t) != ctArray:
result = con("(&", result).con(")") result = "(&" & result & ")"
proc rdCharLoc(a: TLoc): PRope = proc rdCharLoc(a: TLoc): Rope =
# read a location that may need a char-cast: # read a location that may need a char-cast:
result = rdLoc(a) result = rdLoc(a)
if skipTypes(a.t, abstractRange).kind == tyChar: if skipTypes(a.t, abstractRange).kind == tyChar:
result = ropef("((NU8)($1))", [result]) result = "((NU8)($1))" % [result]
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
takeAddr: bool) = takeAddr: bool) =
@ -244,11 +246,11 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
discard discard
of frHeader: of frHeader:
var r = rdLoc(a) var r = rdLoc(a)
if not takeAddr: r = ropef("(*$1)", [r]) if not takeAddr: r = "(*$1)" % [r]
var s = skipTypes(t, abstractInst) var s = skipTypes(t, abstractInst)
if not p.module.compileToCpp: if not p.module.compileToCpp:
while (s.kind == tyObject) and (s.sons[0] != nil): while (s.kind == tyObject) and (s.sons[0] != nil):
app(r, ".Sup") add(r, ".Sup")
s = skipTypes(s.sons[0], abstractInst) s = skipTypes(s.sons[0], abstractInst)
linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t)) linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t))
of frEmbedded: of frEmbedded:
@ -276,7 +278,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
if containsGcRef: if containsGcRef:
var nilLoc: TLoc var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, OnStack) initLoc(nilLoc, locTemp, loc.t, OnStack)
nilLoc.r = toRope("NIM_NIL") nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc, {afSrcIsNil}) genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else: else:
linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc)) linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
@ -325,7 +327,7 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels) inc(p.labels)
result.r = con("LOC", toRope(p.labels)) result.r = "LOC" & rope(p.labels)
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
result.k = locTemp result.k = locTemp
#result.a = - 1 #result.a = - 1
@ -340,9 +342,9 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
# of interior pointers instead # of interior pointers instead
if optRefcGC notin gGlobalOptions: return if optRefcGC notin gGlobalOptions: return
var result: TLoc var result: TLoc
var fid = toRope(p.gcFrameId) var fid = rope(p.gcFrameId)
result.r = con("GCFRAME.F", fid) result.r = "GCFRAME.F" & fid
appf(p.gcFrameType, " $1 F$2;$n", addf(p.gcFrameType, " $1 F$2;$n",
[getTypeDesc(p.module, toKeepAlive.t), fid]) [getTypeDesc(p.module, toKeepAlive.t), fid])
inc(p.gcFrameId) inc(p.gcFrameId)
result.k = locTemp result.k = locTemp
@ -359,10 +361,10 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
addrLoc(result), addrLoc(toKeepAlive), rdLoc(result)) addrLoc(result), addrLoc(toKeepAlive), rdLoc(result))
proc initGCFrame(p: BProc): PRope = proc initGCFrame(p: BProc): Rope =
if p.gcFrameId > 0: result = ropef("struct {$1} GCFRAME;$n", p.gcFrameType) if p.gcFrameId > 0: result = "struct {$1} GCFRAME;$n" % [p.gcFrameType]
proc deinitGCFrame(p: BProc): PRope = proc deinitGCFrame(p: BProc): Rope =
if p.gcFrameId > 0: if p.gcFrameId > 0:
result = ropecg(p.module, result = ropecg(p.module,
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n") "if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
@ -371,42 +373,42 @@ proc localDebugInfo(p: BProc, s: PSym) =
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
# XXX work around a bug: No type information for open arrays possible: # XXX work around a bug: No type information for open arrays possible:
if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
var a = con("&", s.loc.r) var a = "&" & s.loc.r
if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
lineF(p, cpsInit, lineF(p, cpsInit,
"F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n", "F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
[p.maxFrameLen.toRope, makeCString(normalize(s.name.s)), a, [p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
genTypeInfo(p.module, s.loc.t)]) genTypeInfo(p.module, s.loc.t)])
inc(p.maxFrameLen) inc(p.maxFrameLen)
inc p.blocks[p.blocks.len-1].frameLen inc p.blocks[p.blocks.len-1].frameLen
proc localVarDecl(p: BProc; s: PSym): PRope = proc localVarDecl(p: BProc; s: PSym): Rope =
if s.loc.k == locNone: if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack) fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
result = getTypeDesc(p.module, s.loc.t) result = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil: if s.constraint.isNil:
if sfRegister in s.flags: app(result, " register") if sfRegister in s.flags: add(result, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(decl, " GC_GUARD") # add(decl, " GC_GUARD")
if sfVolatile in s.flags: app(result, " volatile") if sfVolatile in s.flags: add(result, " volatile")
app(result, " ") add(result, " ")
app(result, s.loc.r) add(result, s.loc.r)
else: else:
result = ropef(s.cgDeclFrmt, result, s.loc.r) result = s.cgDeclFrmt % [result, s.loc.r]
proc assignLocalVar(p: BProc, s: PSym) = proc assignLocalVar(p: BProc, s: PSym) =
#assert(s.loc.k == locNone) # not yet assigned #assert(s.loc.k == locNone) # not yet assigned
# this need not be fulfilled for inline procs; they are regenerated # this need not be fulfilled for inline procs; they are regenerated
# for each module that uses them! # for each module that uses them!
let decl = localVarDecl(p, s).con(";" & tnl) let decl = localVarDecl(p, s) & ";" & tnl
line(p, cpsLocals, decl) line(p, cpsLocals, decl)
localDebugInfo(p, s) localDebugInfo(p, s)
include ccgthreadvars include ccgthreadvars
proc varInDynamicLib(m: BModule, sym: PSym) proc varInDynamicLib(m: BModule, sym: PSym)
proc mangleDynLibProc(sym: PSym): PRope proc mangleDynLibProc(sym: PSym): Rope
proc assignGlobalVar(p: BProc, s: PSym) = proc assignGlobalVar(p: BProc, s: PSym) =
if s.loc.k == locNone: if s.loc.k == locNone:
@ -424,17 +426,17 @@ proc assignGlobalVar(p: BProc, s: PSym) =
if sfThread in s.flags: if sfThread in s.flags:
declareThreadVar(p.module, s, sfImportc in s.flags) declareThreadVar(p.module, s, sfImportc in s.flags)
else: else:
var decl: PRope = nil var decl: Rope = nil
var td = getTypeDesc(p.module, s.loc.t) var td = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil: if s.constraint.isNil:
if sfImportc in s.flags: app(decl, "extern ") if sfImportc in s.flags: add(decl, "extern ")
app(decl, td) add(decl, td)
if sfRegister in s.flags: app(decl, " register") if sfRegister in s.flags: add(decl, " register")
if sfVolatile in s.flags: app(decl, " volatile") if sfVolatile in s.flags: add(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r]) addf(decl, " $1;$n", [s.loc.r])
else: else:
decl = ropef(s.cgDeclFrmt & ";$n", td, s.loc.r) decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r]
app(p.module.s[cfsVars], decl) add(p.module.s[cfsVars], decl)
if p.withinLoop > 0: if p.withinLoop > 0:
# fixes tests/run/tzeroarray: # fixes tests/run/tzeroarray:
resetLoc(p, s.loc) resetLoc(p, s.loc)
@ -455,7 +457,7 @@ proc fillProcLoc(sym: PSym) =
proc getLabel(p: BProc): TLabel = proc getLabel(p: BProc): TLabel =
inc(p.labels) inc(p.labels)
result = con("LA", toRope(p.labels)) result = "LA" & rope(p.labels)
proc fixLabel(p: BProc, labl: TLabel) = proc fixLabel(p: BProc, labl: TLabel) =
lineF(p, cpsStmts, "$1: ;$n", [labl]) lineF(p, cpsStmts, "$1: ;$n", [labl])
@ -467,9 +469,9 @@ proc expr(p: BProc, n: PNode, d: var TLoc)
proc genProcPrototype(m: BModule, sym: PSym) proc genProcPrototype(m: BModule, sym: PSym)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
proc intLiteral(i: BiggestInt): PRope proc intLiteral(i: BiggestInt): Rope
proc genLiteral(p: BProc, n: PNode): PRope proc genLiteral(p: BProc, n: PNode): Rope
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): PRope proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e.typ, OnUnknown) initLoc(result, locNone, e.typ, OnUnknown)
@ -480,13 +482,13 @@ proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
result.flags.incl lfSingleUse result.flags.incl lfSingleUse
expr(p, e, result) expr(p, e, result)
proc lenField(p: BProc): PRope = proc lenField(p: BProc): Rope =
result = toRope(if p.module.compileToCpp: "len" else: "Sup.len") result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
include ccgcalls, "ccgstmts.nim", "ccgexprs.nim" include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
# ----------------------------- dynamic library handling ----------------- # ----------------------------- dynamic library handling -----------------
# We don't finalize dynamic libs as this does the OS for us. # We don't finalize dynamic libs as the OS does this for us.
proc isGetProcAddr(lib: PLib): bool = proc isGetProcAddr(lib: PLib): bool =
let n = lib.path let n = lib.path
@ -500,16 +502,16 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
var tmp = getGlobalTempName() var tmp = getGlobalTempName()
assert(lib.name == nil) assert(lib.name == nil)
lib.name = tmp # BUGFIX: cgsym has awful side-effects lib.name = tmp # BUGFIX: cgsym has awful side-effects
appf(m.s[cfsVars], "static void* $1;$n", [tmp]) addf(m.s[cfsVars], "static void* $1;$n", [tmp])
if lib.path.kind in {nkStrLit..nkTripleStrLit}: if lib.path.kind in {nkStrLit..nkTripleStrLit}:
var s: TStringSeq = @[] var s: TStringSeq = @[]
libCandidates(lib.path.strVal, s) libCandidates(lib.path.strVal, s)
if gVerbosity >= 2: if gVerbosity >= 2:
msgWriteln("Dependency: " & lib.path.strVal) msgWriteln("Dependency: " & lib.path.strVal)
var loadlib: PRope = nil var loadlib: Rope = nil
for i in countup(0, high(s)): for i in countup(0, high(s)):
inc(m.labels) inc(m.labels)
if i > 0: app(loadlib, "||") if i > 0: add(loadlib, "||")
appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n", appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
[tmp, getStrLit(m, s[i])]) [tmp, getStrLit(m, s[i])])
appcg(m, m.s[cfsDynLibInit], appcg(m, m.s[cfsDynLibInit],
@ -520,21 +522,21 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
p.options = p.options - {optStackTrace, optEndb} p.options = p.options - {optStackTrace, optEndb}
var dest: TLoc var dest: TLoc
initLocExpr(p, lib.path, dest) initLocExpr(p, lib.path, dest)
app(m.s[cfsVars], p.s(cpsLocals)) add(m.s[cfsVars], p.s(cpsLocals))
app(m.s[cfsDynLibInit], p.s(cpsInit)) add(m.s[cfsDynLibInit], p.s(cpsInit))
app(m.s[cfsDynLibInit], p.s(cpsStmts)) add(m.s[cfsDynLibInit], p.s(cpsStmts))
appcg(m, m.s[cfsDynLibInit], appcg(m, m.s[cfsDynLibInit],
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n", "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
[tmp, rdLoc(dest)]) [tmp, rdLoc(dest)])
if lib.name == nil: internalError("loadDynamicLib") if lib.name == nil: internalError("loadDynamicLib")
proc mangleDynLibProc(sym: PSym): PRope = proc mangleDynLibProc(sym: PSym): Rope =
if sfCompilerProc in sym.flags: if sfCompilerProc in sym.flags:
# NOTE: sym.loc.r is the external name! # NOTE: sym.loc.r is the external name!
result = toRope(sym.name.s) result = rope(sym.name.s)
else: else:
result = ropef("Dl_$1", [toRope(sym.id)]) result = "Dl_$1" % [rope(sym.id)]
proc symInDynamicLib(m: BModule, sym: PSym) = proc symInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex var lib = sym.annex
@ -549,30 +551,28 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
let n = lib.path let n = lib.path
var a: TLoc var a: TLoc
initLocExpr(m.initProc, n[0], a) initLocExpr(m.initProc, n[0], a)
var params = con(rdLoc(a), "(") var params = rdLoc(a) & "("
for i in 1 .. n.len-2: for i in 1 .. n.len-2:
initLocExpr(m.initProc, n[i], a) initLocExpr(m.initProc, n[i], a)
params.app(rdLoc(a)) params.add(rdLoc(a))
params.app(", ") params.add(", ")
let load = ropef("\t$1 = ($2) ($3$4));$n", let load = "\t$1 = ($2) ($3$4));$n" %
[tmp, getTypeDesc(m, sym.typ), [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
params, makeCString(ropeToStr(extname))])
var last = lastSon(n) var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last.sons[1] if last.kind == nkHiddenStdConv: last = last.sons[1]
internalAssert(last.kind == nkStrLit) internalAssert(last.kind == nkStrLit)
let idx = last.strVal let idx = last.strVal
if idx.len == 0: if idx.len == 0:
app(m.initProc.s(cpsStmts), load) add(m.initProc.s(cpsStmts), load)
elif idx.len == 1 and idx[0] in {'0'..'9'}: elif idx.len == 1 and idx[0] in {'0'..'9'}:
app(m.extensionLoaders[idx[0]], load) add(m.extensionLoaders[idx[0]], load)
else: else:
internalError(sym.info, "wrong index: " & idx) internalError(sym.info, "wrong index: " & idx)
else: else:
appcg(m, m.s[cfsDynLibInit], appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n", "\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ), [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
lib.name, makeCString(ropeToStr(extname))]) addf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc varInDynamicLib(m: BModule, sym: PSym) = proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex var lib = sym.annex
@ -584,16 +584,15 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
inc(m.labels, 2) inc(m.labels, 2)
appcg(m, m.s[cfsDynLibInit], appcg(m, m.s[cfsDynLibInit],
"$1 = ($2*) #nimGetProcAddr($3, $4);$n", "$1 = ($2*) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ), [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
lib.name, makeCString(ropeToStr(extname))]) addf(m.s[cfsVars], "$2* $1;$n",
appf(m.s[cfsVars], "$2* $1;$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t)]) [sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc symInDynamicLibPartial(m: BModule, sym: PSym) = proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym) sym.loc.r = mangleDynLibProc(sym)
sym.typ.sym = nil # generate a new name sym.typ.sym = nil # generate a new name
proc cgsym(m: BModule, name: string): PRope = proc cgsym(m: BModule, name: string): Rope =
var sym = magicsys.getCompilerProc(name) var sym = magicsys.getCompilerProc(name)
if sym != nil: if sym != nil:
case sym.kind case sym.kind
@ -609,29 +608,29 @@ proc cgsym(m: BModule, name: string): PRope =
result = sym.loc.r result = sym.loc.r
proc generateHeaders(m: BModule) = proc generateHeaders(m: BModule) =
app(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl) add(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
var it = PStrEntry(m.headerFiles.head) var it = PStrEntry(m.headerFiles.head)
while it != nil: while it != nil:
if it.data[0] notin {'\"', '<'}: if it.data[0] notin {'\"', '<'}:
appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)]) addf(m.s[cfsHeaders], "$N#include \"$1\"$N", [rope(it.data)])
else: else:
appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)]) addf(m.s[cfsHeaders], "$N#include $1$N", [rope(it.data)])
it = PStrEntry(it.next) it = PStrEntry(it.next)
proc retIsNotVoid(s: PSym): bool = proc retIsNotVoid(s: PSym): bool =
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0]) result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
proc initFrame(p: BProc, procname, filename: PRope): PRope = proc initFrame(p: BProc, procname, filename: Rope): Rope =
discard cgsym(p.module, "nimFrame") discard cgsym(p.module, "nimFrame")
if p.maxFrameLen > 0: if p.maxFrameLen > 0:
discard cgsym(p.module, "TVarSlot") discard cgsym(p.module, "TVarSlot")
result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N", result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
procname, filename, p.maxFrameLen.toRope, procname, filename, p.maxFrameLen.rope,
p.blocks[0].frameLen.toRope) p.blocks[0].frameLen.rope)
else: else:
result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename) result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
proc deinitFrame(p: BProc): PRope = proc deinitFrame(p: BProc): Rope =
result = rfmt(p.module, "\t#popFrame();$n") result = rfmt(p.module, "\t#popFrame();$n")
proc closureSetup(p: BProc, prc: PSym) = proc closureSetup(p: BProc, prc: PSym) =
@ -650,7 +649,7 @@ proc closureSetup(p: BProc, prc: PSym) =
proc genProcAux(m: BModule, prc: PSym) = proc genProcAux(m: BModule, prc: PSym) =
var p = newProc(prc, m) var p = newProc(prc, m)
var header = genProcHeader(m, prc) var header = genProcHeader(m, prc)
var returnStmt: PRope = nil var returnStmt: Rope = nil
assert(prc.ast != nil) assert(prc.ast != nil)
if sfPure notin prc.flags and prc.typ.sons[0] != nil: if sfPure notin prc.flags and prc.typ.sons[0] != nil:
if resultPos >= prc.ast.len: if resultPos >= prc.ast.len:
@ -676,33 +675,33 @@ proc genProcAux(m: BModule, prc: PSym) =
assignParam(p, param) assignParam(p, param)
closureSetup(p, prc) closureSetup(p, prc)
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc. genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
var generatedProc: PRope var generatedProc: Rope
if sfPure in prc.flags: if sfPure in prc.flags:
if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props: if hasNakedDeclspec in extccomp.CC[extccomp.cCompiler].props:
header = con("__declspec(naked) ", header) header = "__declspec(naked) " & header
generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N", generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)) header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
else: else:
generatedProc = rfmt(nil, "$N$1 {$N", header) generatedProc = rfmt(nil, "$N$1 {$N", header)
app(generatedProc, initGCFrame(p)) add(generatedProc, initGCFrame(p))
if optStackTrace in prc.options: if optStackTrace in prc.options:
app(generatedProc, p.s(cpsLocals)) add(generatedProc, p.s(cpsLocals))
var procname = makeCString(prc.name.s) var procname = makeCString(prc.name.s)
app(generatedProc, initFrame(p, procname, prc.info.quotedFilename)) add(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
else: else:
app(generatedProc, p.s(cpsLocals)) add(generatedProc, p.s(cpsLocals))
if optProfiler in prc.options: if optProfiler in prc.options:
# invoke at proc entry for recursion: # invoke at proc entry for recursion:
appcg(p, cpsInit, "\t#nimProfile();$n", []) appcg(p, cpsInit, "\t#nimProfile();$n", [])
if p.beforeRetNeeded: app(generatedProc, "{") if p.beforeRetNeeded: add(generatedProc, "{")
app(generatedProc, p.s(cpsInit)) add(generatedProc, p.s(cpsInit))
app(generatedProc, p.s(cpsStmts)) add(generatedProc, p.s(cpsStmts))
if p.beforeRetNeeded: app(generatedProc, ~"\t}BeforeRet: ;$n") if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet: ;$n")
app(generatedProc, deinitGCFrame(p)) add(generatedProc, deinitGCFrame(p))
if optStackTrace in prc.options: app(generatedProc, deinitFrame(p)) if optStackTrace in prc.options: add(generatedProc, deinitFrame(p))
app(generatedProc, returnStmt) add(generatedProc, returnStmt)
app(generatedProc, ~"}$N") add(generatedProc, ~"}$N")
app(m.s[cfsProcs], generatedProc) add(m.s[cfsProcs], generatedProc)
proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} = proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} =
result = sfCompileToCpp in m.module.flags and result = sfCompileToCpp in m.module.flags and
@ -715,15 +714,15 @@ proc genProcPrototype(m: BModule, sym: PSym) =
if lfDynamicLib in sym.loc.flags: if lfDynamicLib in sym.loc.flags:
if getModule(sym).id != m.module.id and if getModule(sym).id != m.module.id and
not containsOrIncl(m.declaredThings, sym.id): not containsOrIncl(m.declaredThings, sym.id):
app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n", add(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym))) getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
elif not containsOrIncl(m.declaredProtos, sym.id): elif not containsOrIncl(m.declaredProtos, sym.id):
var header = genProcHeader(m, sym) var header = genProcHeader(m, sym)
if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
header = con("extern \"C\" ", header) header = "extern \"C\" " & header
if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props: if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
header.app(" __attribute__((naked))") header.add(" __attribute__((naked))")
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header)) add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
proc genProcNoForward(m: BModule, prc: PSym) = proc genProcNoForward(m: BModule, prc: PSym) =
fillProcLoc(prc) fillProcLoc(prc)
@ -760,16 +759,16 @@ proc requestConstImpl(p: BProc, sym: PSym) =
var q = findPendingModule(m, sym) var q = findPendingModule(m, sym)
if q != nil and not containsOrIncl(q.declaredThings, sym.id): if q != nil and not containsOrIncl(q.declaredThings, sym.id):
assert q.initProc.module == q assert q.initProc.module == q
appf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n", addf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)]) [getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)])
# declare header: # declare header:
if q != m and not containsOrIncl(m.declaredThings, sym.id): if q != m and not containsOrIncl(m.declaredThings, sym.id):
assert(sym.loc.r != nil) assert(sym.loc.r != nil)
let headerDecl = ropef("extern NIM_CONST $1 $2;$n", let headerDecl = "extern NIM_CONST $1 $2;$n" %
[getTypeDesc(m, sym.loc.t), sym.loc.r]) [getTypeDesc(m, sym.loc.t), sym.loc.r]
app(m.s[cfsData], headerDecl) add(m.s[cfsData], headerDecl)
if sfExportc in sym.flags and generatedHeader != nil: if sfExportc in sym.flags and generatedHeader != nil:
app(generatedHeader.s[cfsData], headerDecl) add(generatedHeader.s[cfsData], headerDecl)
proc isActivated(prc: PSym): bool = prc.typ != nil proc isActivated(prc: PSym): bool = prc.typ != nil
@ -798,47 +797,47 @@ proc genVarPrototypeAux(m: BModule, sym: PSym) =
if sfThread in sym.flags: if sfThread in sym.flags:
declareThreadVar(m, sym, true) declareThreadVar(m, sym, true)
else: else:
app(m.s[cfsVars], "extern ") add(m.s[cfsVars], "extern ")
app(m.s[cfsVars], getTypeDesc(m, sym.loc.t)) add(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
if lfDynamicLib in sym.loc.flags: app(m.s[cfsVars], "*") if lfDynamicLib in sym.loc.flags: add(m.s[cfsVars], "*")
if sfRegister in sym.flags: app(m.s[cfsVars], " register") if sfRegister in sym.flags: add(m.s[cfsVars], " register")
if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile") if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
appf(m.s[cfsVars], " $1;$n", [sym.loc.r]) addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
proc genVarPrototype(m: BModule, sym: PSym) = proc genVarPrototype(m: BModule, sym: PSym) =
genVarPrototypeAux(m, sym) genVarPrototypeAux(m, sym)
proc addIntTypes(result: var PRope) {.inline.} = proc addIntTypes(result: var Rope) {.inline.} =
appf(result, "#define NIM_INTBITS $1", [ addf(result, "#define NIM_INTBITS $1", [
platform.CPU[targetCPU].intSize.toRope]) platform.CPU[targetCPU].intSize.rope])
proc getCopyright(cfile: string): PRope = proc getCopyright(cfile: string): Rope =
if optCompileOnly in gGlobalOptions: if optCompileOnly in gGlobalOptions:
result = ropef("/* Generated by Nim Compiler v$1 */$N" & result = ("/* Generated by Nim Compiler v$1 */$N" &
"/* (c) 2015 Andreas Rumpf */$N" & "/* (c) 2015 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N", "/* The generated code is subject to the original license. */$N") %
[toRope(VersionAsString)]) [rope(VersionAsString)]
else: else:
result = ropef("/* Generated by Nim Compiler v$1 */$N" & result = ("/* Generated by Nim Compiler v$1 */$N" &
"/* (c) 2015 Andreas Rumpf */$N" & "/* (c) 2015 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N" & "/* The generated code is subject to the original license. */$N" &
"/* Compiled for: $2, $3, $4 */$N" & "/* Compiled for: $2, $3, $4 */$N" &
"/* Command for C compiler:$n $5 */$N", "/* Command for C compiler:$n $5 */$N") %
[toRope(VersionAsString), [rope(VersionAsString),
toRope(platform.OS[targetOS].name), rope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name), rope(platform.CPU[targetCPU].name),
toRope(extccomp.CC[extccomp.cCompiler].name), rope(extccomp.CC[extccomp.cCompiler].name),
toRope(getCompileCFileCmd(cfile))]) rope(getCompileCFileCmd(cfile))]
proc getFileHeader(cfile: string): PRope = proc getFileHeader(cfile: string): Rope =
result = getCopyright(cfile) result = getCopyright(cfile)
addIntTypes(result) addIntTypes(result)
proc genFilenames(m: BModule): PRope = proc genFilenames(m: BModule): Rope =
discard cgsym(m, "dbgRegisterFilename") discard cgsym(m, "dbgRegisterFilename")
result = nil result = nil
for i in 0.. <fileInfos.len: for i in 0.. <fileInfos.len:
result.appf("dbgRegisterFilename($1);$N", fileInfos[i].projPath.makeCString) result.addf("dbgRegisterFilename($1);$N", [fileInfos[i].projPath.makeCString])
proc genMainProc(m: BModule) = proc genMainProc(m: BModule) =
const const
@ -920,7 +919,7 @@ proc genMainProc(m: BModule) =
MainProcs & MainProcs &
"}$N$N" "}$N$N"
var nimMain, otherMain: TFormatStr var nimMain, otherMain: FormatStr
if platform.targetOS == osWindows and if platform.targetOS == osWindows and
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}: gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
if optGenGuiApp in gGlobalOptions: if optGenGuiApp in gGlobalOptions:
@ -941,10 +940,10 @@ proc genMainProc(m: BModule) =
otherMain = PosixCMain otherMain = PosixCMain
if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint") if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
if optEndb in gOptions: if optEndb in gOptions:
gBreakpoints.app(m.genFilenames) gBreakpoints.add(m.genFilenames)
let initStackBottomCall = let initStackBottomCall =
if platform.targetOS == osStandalone: "".toRope if platform.targetOS == osStandalone: "".rope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N") else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
inc(m.labels) inc(m.labels)
appcg(m, m.s[cfsProcs], PreMainBody, [ appcg(m, m.s[cfsProcs], PreMainBody, [
@ -952,56 +951,56 @@ proc genMainProc(m: BModule) =
if emulatedThreadVars() and platform.targetOS != osStandalone: if emulatedThreadVars() and platform.targetOS != osStandalone:
ropecg(m, "\t#initThreadVarsEmulation();$N") ropecg(m, "\t#initThreadVarsEmulation();$N")
else: else:
"".toRope, "".rope,
initStackBottomCall]) initStackBottomCall])
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, toRope(m.labels)]) appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, rope(m.labels)])
if optNoMain notin gGlobalOptions: if optNoMain notin gGlobalOptions:
appcg(m, m.s[cfsProcs], otherMain, []) appcg(m, m.s[cfsProcs], otherMain, [])
proc getSomeInitName(m: PSym, suffix: string): PRope = proc getSomeInitName(m: PSym, suffix: string): Rope =
assert m.kind == skModule assert m.kind == skModule
assert m.owner.kind == skPackage assert m.owner.kind == skPackage
if {sfSystemModule, sfMainModule} * m.flags == {}: if {sfSystemModule, sfMainModule} * m.flags == {}:
result = m.owner.name.s.mangle.toRope result = m.owner.name.s.mangle.rope
result.app "_" result.add "_"
result.app m.name.s result.add m.name.s
result.app suffix result.add suffix
proc getInitName(m: PSym): PRope = getSomeInitName(m, "Init") proc getInitName(m: PSym): Rope = getSomeInitName(m, "Init")
proc getDatInitName(m: PSym): PRope = getSomeInitName(m, "DatInit") proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit")
proc registerModuleToMain(m: PSym) = proc registerModuleToMain(m: PSym) =
var var
init = m.getInitName init = m.getInitName
datInit = m.getDatInitName datInit = m.getDatInitName
appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init]) addf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init])
appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit]) addf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit])
if sfSystemModule notin m.flags: if sfSystemModule notin m.flags:
appf(mainDatInit, "\t$1();$N", [datInit]) addf(mainDatInit, "\t$1();$N", [datInit])
let initCall = ropef("\t$1();$N", [init]) let initCall = "\t$1();$N" % [init]
if sfMainModule in m.flags: if sfMainModule in m.flags:
app(mainModInit, initCall) add(mainModInit, initCall)
else: else:
app(otherModsInit, initCall) add(otherModsInit, initCall)
proc genInitCode(m: BModule) = proc genInitCode(m: BModule) =
var initname = getInitName(m.module) var initname = getInitName(m.module)
var prc = ropef("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", [initname]) var prc = "NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N" % [initname]
if m.typeNodes > 0: if m.typeNodes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
[m.typeNodesName, toRope(m.typeNodes)]) [m.typeNodesName, rope(m.typeNodes)])
if m.nimTypes > 0: if m.nimTypes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n", appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
[m.nimTypesName, toRope(m.nimTypes)]) [m.nimTypesName, rope(m.nimTypes)])
app(prc, initGCFrame(m.initProc)) add(prc, initGCFrame(m.initProc))
app(prc, genSectionStart(cpsLocals)) add(prc, genSectionStart(cpsLocals))
app(prc, m.preInitProc.s(cpsLocals)) add(prc, m.preInitProc.s(cpsLocals))
app(prc, m.initProc.s(cpsLocals)) add(prc, m.initProc.s(cpsLocals))
app(prc, m.postInitProc.s(cpsLocals)) add(prc, m.postInitProc.s(cpsLocals))
app(prc, genSectionEnd(cpsLocals)) add(prc, genSectionEnd(cpsLocals))
if optStackTrace in m.initProc.options and not m.frameDeclared: if optStackTrace in m.initProc.options and not m.frameDeclared:
# BUT: the generated init code might depend on a current frame, so # BUT: the generated init code might depend on a current frame, so
@ -1009,58 +1008,58 @@ proc genInitCode(m: BModule) =
m.frameDeclared = true m.frameDeclared = true
if not m.preventStackTrace: if not m.preventStackTrace:
var procname = makeCString(m.module.name.s) var procname = makeCString(m.module.name.s)
app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename)) add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
else: else:
app(prc, ~"\tTFrame F; F.len = 0;$N") add(prc, ~"\tTFrame F; F.len = 0;$N")
app(prc, genSectionStart(cpsInit)) add(prc, genSectionStart(cpsInit))
app(prc, m.preInitProc.s(cpsInit)) add(prc, m.preInitProc.s(cpsInit))
app(prc, m.initProc.s(cpsInit)) add(prc, m.initProc.s(cpsInit))
app(prc, m.postInitProc.s(cpsInit)) add(prc, m.postInitProc.s(cpsInit))
app(prc, genSectionEnd(cpsInit)) add(prc, genSectionEnd(cpsInit))
app(prc, genSectionStart(cpsStmts)) add(prc, genSectionStart(cpsStmts))
app(prc, m.preInitProc.s(cpsStmts)) add(prc, m.preInitProc.s(cpsStmts))
app(prc, m.initProc.s(cpsStmts)) add(prc, m.initProc.s(cpsStmts))
app(prc, m.postInitProc.s(cpsStmts)) add(prc, m.postInitProc.s(cpsStmts))
app(prc, genSectionEnd(cpsStmts)) add(prc, genSectionEnd(cpsStmts))
if optStackTrace in m.initProc.options and not m.preventStackTrace: if optStackTrace in m.initProc.options and not m.preventStackTrace:
app(prc, deinitFrame(m.initProc)) add(prc, deinitFrame(m.initProc))
app(prc, deinitGCFrame(m.initProc)) add(prc, deinitGCFrame(m.initProc))
appf(prc, "}$N$N") addf(prc, "}$N$N", [])
prc.appf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", prc.addf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
[getDatInitName(m.module)]) [getDatInitName(m.module)])
for i in cfsTypeInit1..cfsDynLibInit: for i in cfsTypeInit1..cfsDynLibInit:
app(prc, genSectionStart(i)) add(prc, genSectionStart(i))
app(prc, m.s[i]) add(prc, m.s[i])
app(prc, genSectionEnd(i)) add(prc, genSectionEnd(i))
appf(prc, "}$N$N") addf(prc, "}$N$N", [])
# we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
# that would lead to a *nesting* of merge sections which the merger does # that would lead to a *nesting* of merge sections which the merger does
# not support. So we add it to another special section: ``cfsInitProc`` # not support. So we add it to another special section: ``cfsInitProc``
app(m.s[cfsInitProc], prc) add(m.s[cfsInitProc], prc)
for i, el in pairs(m.extensionLoaders): for i, el in pairs(m.extensionLoaders):
if el != nil: if el != nil:
let ex = ropef("N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N", let ex = "N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" %
(i.ord - '0'.ord).toRope, el) [(i.ord - '0'.ord).rope, el]
app(m.s[cfsInitProc], ex) add(m.s[cfsInitProc], ex)
proc genModule(m: BModule, cfile: string): PRope = proc genModule(m: BModule, cfile: string): Rope =
result = getFileHeader(cfile) result = getFileHeader(cfile)
result.app(genMergeInfo(m)) result.add(genMergeInfo(m))
generateHeaders(m) generateHeaders(m)
generateThreadLocalStorage(m) generateThreadLocalStorage(m)
for i in countup(cfsHeaders, cfsProcs): for i in countup(cfsHeaders, cfsProcs):
app(result, genSectionStart(i)) add(result, genSectionStart(i))
app(result, m.s[i]) add(result, m.s[i])
app(result, genSectionEnd(i)) add(result, genSectionEnd(i))
app(result, m.s[cfsInitProc]) add(result, m.s[cfsInitProc])
proc newPreInitProc(m: BModule): BProc = proc newPreInitProc(m: BModule): BProc =
result = newProc(nil, m) result = newProc(nil, m)
@ -1172,22 +1171,22 @@ proc myOpen(module: PSym): PPassContext =
proc writeHeader(m: BModule) = proc writeHeader(m: BModule) =
var result = getCopyright(m.filename) var result = getCopyright(m.filename)
var guard = ropef("__$1__", m.filename.splitFile.name.toRope) var guard = "__$1__" % [m.filename.splitFile.name.rope]
result.appf("#ifndef $1$n#define $1$n", guard) result.addf("#ifndef $1$n#define $1$n", [guard])
addIntTypes(result) addIntTypes(result)
generateHeaders(m) generateHeaders(m)
generateThreadLocalStorage(m) generateThreadLocalStorage(m)
for i in countup(cfsHeaders, cfsProcs): for i in countup(cfsHeaders, cfsProcs):
app(result, genSectionStart(i)) add(result, genSectionStart(i))
app(result, m.s[i]) add(result, m.s[i])
app(result, genSectionEnd(i)) add(result, genSectionEnd(i))
app(result, m.s[cfsInitProc]) add(result, m.s[cfsInitProc])
if optGenDynLib in gGlobalOptions: if optGenDynLib in gGlobalOptions:
result.app("N_LIB_IMPORT ") result.add("N_LIB_IMPORT ")
result.appf("N_CDECL(void, NimMain)(void);$n") result.addf("N_CDECL(void, NimMain)(void);$n", [])
result.appf("#endif /* $1 */$n", guard) result.addf("#endif /* $1 */$n", [guard])
writeRope(result, m.filename) writeRope(result, m.filename)
proc getCFile(m: BModule): string = proc getCFile(m: BModule): string =
@ -1224,7 +1223,7 @@ proc finishModule(m: BModule) =
dec(gForwardedProcsCounter, i) dec(gForwardedProcsCounter, i)
setLen(m.forwardedProcs, 0) setLen(m.forwardedProcs, 0)
proc shouldRecompile(code: PRope, cfile: string): bool = proc shouldRecompile(code: Rope, cfile: string): bool =
result = true result = true
if optForceFullMake notin gGlobalOptions: if optForceFullMake notin gGlobalOptions:
var objFile = toObjFile(cfile) var objFile = toObjFile(cfile)
@ -1249,13 +1248,13 @@ proc writeModule(m: BModule, pending: bool) =
finishTypeDescriptions(m) finishTypeDescriptions(m)
if sfMainModule in m.module.flags: if sfMainModule in m.module.flags:
# generate main file: # generate main file:
app(m.s[cfsProcHeaders], mainModProcs) add(m.s[cfsProcHeaders], mainModProcs)
generateThreadVarsSize(m) generateThreadVarsSize(m)
var code = genModule(m, cfile) var code = genModule(m, cfile)
when hasTinyCBackend: when hasTinyCBackend:
if gCmd == cmdRun: if gCmd == cmdRun:
tccgen.compileCCode(ropeToStr(code)) tccgen.compileCCode($code)
return return
if shouldRecompile(code, cfile): if shouldRecompile(code, cfile):

View file

@ -15,7 +15,7 @@ import
from msgs import TLineInfo from msgs import TLineInfo
type type
TLabel* = PRope # for the C generator a label is just a rope TLabel* = Rope # for the C generator a label is just a rope
TCFileSection* = enum # the sections a generated C file consists of TCFileSection* = enum # the sections a generated C file consists of
cfsMergeInfo, # section containing merge information cfsMergeInfo, # section containing merge information
cfsHeaders, # section for C include file headers cfsHeaders, # section for C include file headers
@ -45,17 +45,17 @@ type
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
ctCString ctCString
TCFileSections* = array[TCFileSection, PRope] # represents a generated C file TCFileSections* = array[TCFileSection, Rope] # represents a generated C file
TCProcSection* = enum # the sections a generated C proc consists of TCProcSection* = enum # the sections a generated C proc consists of
cpsLocals, # section of local variables for C proc cpsLocals, # section of local variables for C proc
cpsInit, # section for init of variables for C proc cpsInit, # section for init of variables for C proc
cpsStmts # section of local statements for C proc cpsStmts # section of local statements for C proc
TCProcSections* = array[TCProcSection, PRope] # represents a generated C proc TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
BModule* = ref TCGen BModule* = ref TCGen
BProc* = ref TCProc BProc* = ref TCProc
TBlock*{.final.} = object TBlock*{.final.} = object
id*: int # the ID of the label; positive means that it id*: int # the ID of the label; positive means that it
label*: PRope # generated text for the label label*: Rope # generated text for the label
# nil if label is not used # nil if label is not used
sections*: TCProcSections # the code beloging sections*: TCProcSections # the code beloging
isLoop*: bool # whether block is a loop isLoop*: bool # whether block is a loop
@ -73,7 +73,7 @@ type
inExceptBlock*: int # are we currently inside an except block? inExceptBlock*: int # are we currently inside an except block?
# leaving such scopes by raise or by return must # leaving such scopes by raise or by return must
# execute any applicable finally blocks # execute any applicable finally blocks
finallySafePoints*: seq[PRope] # For correctly cleaning up exceptions when finallySafePoints*: seq[Rope] # For correctly cleaning up exceptions when
# using return in finally statements # using return in finally statements
labels*: Natural # for generating unique labels in the C proc labels*: Natural # for generating unique labels in the C proc
blocks*: seq[TBlock] # nested blocks blocks*: seq[TBlock] # nested blocks
@ -89,7 +89,7 @@ type
# requires 'T x = T()' to become 'T x; x = T()' # requires 'T x = T()' to become 'T x; x = T()'
# (yes, C++ is weird like that) # (yes, C++ is weird like that)
gcFrameId*: Natural # for the GC stack marking gcFrameId*: Natural # for the GC stack marking
gcFrameType*: PRope # the struct {} we put the GC markers into gcFrameType*: Rope # the struct {} we put the GC markers into
TTypeSeq* = seq[PType] TTypeSeq* = seq[PType]
TCGen = object of TPassContext # represents a C source file TCGen = object of TPassContext # represents a C source file
@ -118,24 +118,24 @@ type
dataCache*: TNodeTable dataCache*: TNodeTable
forwardedProcs*: TSymSeq # keep forwarded procs here forwardedProcs*: TSymSeq # keep forwarded procs here
typeNodes*, nimTypes*: int # used for type info generation typeNodes*, nimTypes*: int # used for type info generation
typeNodesName*, nimTypesName*: PRope # used for type info generation typeNodesName*, nimTypesName*: Rope # used for type info generation
labels*: Natural # for generating unique module-scope names labels*: Natural # for generating unique module-scope names
extensionLoaders*: array['0'..'9', PRope] # special procs for the extensionLoaders*: array['0'..'9', Rope] # special procs for the
# OpenGL wrapper # OpenGL wrapper
injectStmt*: PRope injectStmt*: Rope
var var
mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: PRope mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
# varuious parts of the main module # varuious parts of the main module
gMapping*: PRope # the generated mapping file (if requested) gMapping*: Rope # the generated mapping file (if requested)
gModules*: seq[BModule] = @[] # list of all compiled modules gModules*: seq[BModule] = @[] # list of all compiled modules
gForwardedProcsCounter*: int = 0 gForwardedProcsCounter*: int = 0
proc s*(p: BProc, s: TCProcSection): var PRope {.inline.} = proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# section in the current block # section in the current block
result = p.blocks[p.blocks.len - 1].sections[s] result = p.blocks[p.blocks.len - 1].sections[s]
proc procSec*(p: BProc, s: TCProcSection): var PRope {.inline.} = proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# top level proc sections # top level proc sections
result = p.blocks[0].sections[s] result = p.blocks[0].sections[s]

View file

@ -24,8 +24,8 @@ bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational") bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
bootSwitch(usedNoGC, defined(nogc), "--gc:none") bootSwitch(usedNoGC, defined(nogc), "--gc:none")
import import
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
wordrecg, parseutils, nimblecmd, idents, parseopt wordrecg, parseutils, nimblecmd, idents, parseopt
# but some have deps to imported modules. Yay. # but some have deps to imported modules. Yay.
@ -39,8 +39,8 @@ bootSwitch(usedFFI, hasFFI, "-d:useFFI")
proc writeCommandLineUsage*() proc writeCommandLineUsage*()
type type
TCmdLinePass* = enum TCmdLinePass* = enum
passCmd1, # first pass over the command line passCmd1, # first pass over the command line
passCmd2, # second pass over the command line passCmd2, # second pass over the command line
passPP # preprocessor called processCommand() passPP # preprocessor called processCommand()
@ -54,30 +54,30 @@ const
HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" & HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
"Copyright (c) 2006-2015 by Andreas Rumpf\n" "Copyright (c) 2006-2015 by Andreas Rumpf\n"
const const
Usage = slurp"doc/basicopt.txt".replace("//", "") Usage = slurp"doc/basicopt.txt".replace("//", "")
AdvancedUsage = slurp"doc/advopt.txt".replace("//", "") AdvancedUsage = slurp"doc/advopt.txt".replace("//", "")
proc getCommandLineDesc(): string = proc getCommandLineDesc(): string =
result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]) & Usage CPU[platform.hostCPU].name]) & Usage
proc helpOnError(pass: TCmdLinePass) = proc helpOnError(pass: TCmdLinePass) =
if pass == passCmd1: if pass == passCmd1:
msgWriteln(getCommandLineDesc()) msgWriteln(getCommandLineDesc())
msgQuit(0) msgQuit(0)
proc writeAdvancedUsage(pass: TCmdLinePass) = proc writeAdvancedUsage(pass: TCmdLinePass) =
if pass == passCmd1: if pass == passCmd1:
msgWriteln(`%`(HelpMessage, [VersionAsString, msgWriteln(`%`(HelpMessage, [VersionAsString,
platform.OS[platform.hostOS].name, platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name]) & AdvancedUsage) CPU[platform.hostCPU].name]) & AdvancedUsage)
msgQuit(0) msgQuit(0)
proc writeVersionInfo(pass: TCmdLinePass) = proc writeVersionInfo(pass: TCmdLinePass) =
if pass == passCmd1: if pass == passCmd1:
msgWriteln(`%`(HelpMessage, [VersionAsString, msgWriteln(`%`(HelpMessage, [VersionAsString,
platform.OS[platform.hostOS].name, platform.OS[platform.hostOS].name,
CPU[platform.hostCPU].name])) CPU[platform.hostCPU].name]))
discard """const gitHash = gorge("git log -n 1 --format=%H") discard """const gitHash = gorge("git log -n 1 --format=%H")
@ -92,8 +92,8 @@ proc writeVersionInfo(pass: TCmdLinePass) =
var var
helpWritten: bool helpWritten: bool
proc writeCommandLineUsage() = proc writeCommandLineUsage() =
if not helpWritten: if not helpWritten:
msgWriteln(getCommandLineDesc()) msgWriteln(getCommandLineDesc())
helpWritten = true helpWritten = true
@ -101,51 +101,51 @@ proc addPrefix(switch: string): string =
if len(switch) == 1: result = "-" & switch if len(switch) == 1: result = "-" & switch
else: result = "--" & switch else: result = "--" & switch
proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) = proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
if switch == " ": localError(info, errInvalidCmdLineOption, "-") if switch == " ": localError(info, errInvalidCmdLineOption, "-")
else: localError(info, errInvalidCmdLineOption, addPrefix(switch)) else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
info: TLineInfo) = info: TLineInfo) =
cmd = "" cmd = ""
var i = 0 var i = 0
if i < len(switch) and switch[i] == '-': inc(i) if i < len(switch) and switch[i] == '-': inc(i)
if i < len(switch) and switch[i] == '-': inc(i) if i < len(switch) and switch[i] == '-': inc(i)
while i < len(switch): while i < len(switch):
case switch[i] case switch[i]
of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i]) of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
else: break else: break
inc(i) inc(i)
if i >= len(switch): arg = "" if i >= len(switch): arg = ""
elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1) elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
else: invalidCmdLineOption(pass, switch, info) else: invalidCmdLineOption(pass, switch, info)
proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass, proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
info: TLineInfo) = info: TLineInfo) =
case whichKeyword(arg) case whichKeyword(arg)
of wOn: gOptions = gOptions + op of wOn: gOptions = gOptions + op
of wOff: gOptions = gOptions - op of wOff: gOptions = gOptions - op
else: localError(info, errOnOrOffExpectedButXFound, arg) else: localError(info, errOnOrOffExpectedButXFound, arg)
proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass, proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
info: TLineInfo) = info: TLineInfo) =
case whichKeyword(arg) case whichKeyword(arg)
of wOn: gGlobalOptions = gGlobalOptions + op of wOn: gGlobalOptions = gGlobalOptions + op
of wOff: gGlobalOptions = gGlobalOptions - op of wOff: gGlobalOptions = gGlobalOptions - op
else: localError(info, errOnOrOffExpectedButXFound, arg) else: localError(info, errOnOrOffExpectedButXFound, arg)
proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch)) if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch)) if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass, proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo; orig: string) = info: TLineInfo; orig: string) =
var id = "" # arg = "X]:on|off" var id = "" # arg = "X]:on|off"
var i = 0 var i = 0
var n = hintMin var n = hintMin
while i < len(arg) and (arg[i] != ']'): while i < len(arg) and (arg[i] != ']'):
add(id, arg[i]) add(id, arg[i])
inc(i) inc(i)
if i < len(arg) and (arg[i] == ']'): inc(i) if i < len(arg) and (arg[i] == ']'): inc(i)
@ -165,7 +165,7 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
of wOff: excl(gNotes, n) of wOff: excl(gNotes, n)
else: localError(info, errOnOrOffExpectedButXFound, arg) else: localError(info, errOnOrOffExpectedButXFound, arg)
proc processCompile(filename: string) = proc processCompile(filename: string) =
var found = findFile(filename) var found = findFile(filename)
if found == "": found = filename if found == "": found = filename
var trunc = changeFileExt(found, "") var trunc = changeFileExt(found, "")
@ -191,7 +191,7 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
else: invalidCmdLineOption(passCmd1, switch, info) else: invalidCmdLineOption(passCmd1, switch, info)
proc testCompileOption*(switch: string, info: TLineInfo): bool = proc testCompileOption*(switch: string, info: TLineInfo): bool =
case switch.normalize case switch.normalize
of "debuginfo": result = contains(gGlobalOptions, optCDebug) of "debuginfo": result = contains(gGlobalOptions, optCDebug)
of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly) of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly)
@ -228,11 +228,11 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
of "patterns": result = contains(gOptions, optPatterns) of "patterns": result = contains(gOptions, optPatterns)
of "experimental": result = gExperimentalMode of "experimental": result = gExperimentalMode
else: invalidCmdLineOption(passCmd1, switch, info) else: invalidCmdLineOption(passCmd1, switch, info)
proc processPath(path: string, notRelativeToProj = false): string = proc processPath(path: string, notRelativeToProj = false): string =
let p = if notRelativeToProj or os.isAbsolute(path) or let p = if notRelativeToProj or os.isAbsolute(path) or
'$' in path or path[0] == '.': '$' in path or path[0] == '.':
path path
else: else:
options.gProjectPath / path options.gProjectPath / path
result = unixToNativePath(p % ["nimrod", getPrefixDir(), result = unixToNativePath(p % ["nimrod", getPrefixDir(),
@ -251,14 +251,14 @@ proc trackDirty(arg: string, info: TLineInfo) =
localError(info, errInvalidNumber, a[1]) localError(info, errInvalidNumber, a[1])
if parseUtils.parseInt(a[3], column) <= 0: if parseUtils.parseInt(a[3], column) <= 0:
localError(info, errInvalidNumber, a[2]) localError(info, errInvalidNumber, a[2])
let dirtyOriginalIdx = a[1].fileInfoIdx let dirtyOriginalIdx = a[1].fileInfoIdx
if dirtyOriginalIdx >= 0: if dirtyOriginalIdx >= 0:
msgs.setDirtyFile(dirtyOriginalIdx, a[0]) msgs.setDirtyFile(dirtyOriginalIdx, a[0])
gTrackPos = newLineInfo(dirtyOriginalIdx, line, column) gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
proc track(arg: string, info: TLineInfo) = proc track(arg: string, info: TLineInfo) =
var a = arg.split(',') var a = arg.split(',')
if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN") if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
var line, column: int var line, column: int
@ -273,13 +273,13 @@ proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
options.inclDynlibOverride(arg) options.inclDynlibOverride(arg)
proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
var var
theOS: TSystemOS theOS: TSystemOS
cpu: TSystemCPU cpu: TSystemCPU
key, val: string key, val: string
case switch.normalize case switch.normalize
of "path", "p": of "path", "p":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
addPath(processPath(arg), info) addPath(processPath(arg), info)
of "nimblepath", "babelpath": of "nimblepath", "babelpath":
@ -303,7 +303,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "nimcache": of "nimcache":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
options.nimcacheDir = processPath(arg) options.nimcacheDir = processPath(arg)
of "out", "o": of "out", "o":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
options.outFile = arg options.outFile = arg
of "docseesrcurl": of "docseesrcurl":
@ -311,19 +311,19 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
options.docSeeSrcUrl = arg options.docSeeSrcUrl = arg
of "mainmodule", "m": of "mainmodule", "m":
discard "allow for backwards compatibility, but don't do anything" discard "allow for backwards compatibility, but don't do anything"
of "define", "d": of "define", "d":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
defineSymbol(arg) defineSymbol(arg)
of "undef", "u": of "undef", "u":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
undefSymbol(arg) undefSymbol(arg)
of "symbol": of "symbol":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
declareSymbol(arg) declareSymbol(arg)
of "compile": of "compile":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: processCompile(arg) if pass in {passCmd2, passPP}: processCompile(arg)
of "link": of "link":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: addFileToLink(arg) if pass in {passCmd2, passPP}: addFileToLink(arg)
of "debuginfo": of "debuginfo":
@ -332,25 +332,25 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "embedsrc": of "embedsrc":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optEmbedOrigSrc) incl(gGlobalOptions, optEmbedOrigSrc)
of "compileonly", "c": of "compileonly", "c":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optCompileOnly) incl(gGlobalOptions, optCompileOnly)
of "nolinking": of "nolinking":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optNoLinking) incl(gGlobalOptions, optNoLinking)
of "nomain": of "nomain":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optNoMain) incl(gGlobalOptions, optNoMain)
of "forcebuild", "f": of "forcebuild", "f":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optForceFullMake) incl(gGlobalOptions, optForceFullMake)
of "project": of "project":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
gWholeProject = true gWholeProject = true
of "gc": of "gc":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
case arg.normalize case arg.normalize
of "boehm": of "boehm":
gSelectedGC = gcBoehm gSelectedGC = gcBoehm
defineSymbol("boehmgc") defineSymbol("boehmgc")
of "refc": of "refc":
@ -388,7 +388,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
undefSymbol("endb") undefSymbol("endb")
else: else:
localError(info, "expected endb|gdb but found " & arg) localError(info, "expected endb|gdb but found " & arg)
of "profiler": of "profiler":
processOnOffSwitch({optProfiler}, arg, pass, info) processOnOffSwitch({optProfiler}, arg, pass, info)
if optProfiler in gOptions: defineSymbol("profiler") if optProfiler in gOptions: defineSymbol("profiler")
else: undefSymbol("profiler") else: undefSymbol("profiler")
@ -407,7 +407,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info) of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
of "threads": of "threads":
processOnOffSwitchG({optThreads}, arg, pass, info) processOnOffSwitchG({optThreads}, arg, pass, info)
if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe) #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info) of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info) of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
of "implicitstatic": of "implicitstatic":
@ -417,17 +417,17 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "opt": of "opt":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
case arg.normalize case arg.normalize
of "speed": of "speed":
incl(gOptions, optOptimizeSpeed) incl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize) excl(gOptions, optOptimizeSize)
of "size": of "size":
excl(gOptions, optOptimizeSpeed) excl(gOptions, optOptimizeSpeed)
incl(gOptions, optOptimizeSize) incl(gOptions, optOptimizeSize)
of "none": of "none":
excl(gOptions, optOptimizeSpeed) excl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize) excl(gOptions, optOptimizeSize)
else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
of "app": of "app":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
case arg.normalize case arg.normalize
of "gui": of "gui":
@ -449,10 +449,10 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
defineSymbol("library") defineSymbol("library")
defineSymbol("staticlib") defineSymbol("staticlib")
else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg) else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
of "passc", "t": of "passc", "t":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg) if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
of "passl", "l": of "passl", "l":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg) if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
of "cincludes": of "cincludes":
@ -475,52 +475,52 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "include": of "include":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: implicitIncludes.add arg if pass in {passCmd2, passPP}: implicitIncludes.add arg
of "listcmd": of "listcmd":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optListCmd) incl(gGlobalOptions, optListCmd)
of "genmapping": of "genmapping":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optGenMapping) incl(gGlobalOptions, optGenMapping)
of "os": of "os":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
if pass in {passCmd1, passPP}: if pass in {passCmd1, passPP}:
theOS = platform.nameToOS(arg) theOS = platform.nameToOS(arg)
if theOS == osNone: localError(info, errUnknownOS, arg) if theOS == osNone: localError(info, errUnknownOS, arg)
elif theOS != platform.hostOS: elif theOS != platform.hostOS:
setTarget(theOS, targetCPU) setTarget(theOS, targetCPU)
condsyms.initDefines() condsyms.initDefines()
of "cpu": of "cpu":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
if pass in {passCmd1, passPP}: if pass in {passCmd1, passPP}:
cpu = platform.nameToCPU(arg) cpu = platform.nameToCPU(arg)
if cpu == cpuNone: localError(info, errUnknownCPU, arg) if cpu == cpuNone: localError(info, errUnknownCPU, arg)
elif cpu != platform.hostCPU: elif cpu != platform.hostCPU:
setTarget(targetOS, cpu) setTarget(targetOS, cpu)
condsyms.initDefines() condsyms.initDefines()
of "run", "r": of "run", "r":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optRun) incl(gGlobalOptions, optRun)
of "verbosity": of "verbosity":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
gVerbosity = parseInt(arg) gVerbosity = parseInt(arg)
of "parallelbuild": of "parallelbuild":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
gNumberOfProcessors = parseInt(arg) gNumberOfProcessors = parseInt(arg)
of "version", "v": of "version", "v":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
writeVersionInfo(pass) writeVersionInfo(pass)
of "advanced": of "advanced":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
writeAdvancedUsage(pass) writeAdvancedUsage(pass)
of "help", "h": of "help", "h":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
helpOnError(pass) helpOnError(pass)
of "symbolfiles": of "symbolfiles":
processOnOffSwitchG({optSymbolFiles}, arg, pass, info) processOnOffSwitchG({optSymbolFiles}, arg, pass, info)
of "skipcfg": of "skipcfg":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optSkipConfigFile) incl(gGlobalOptions, optSkipConfigFile)
of "skipprojcfg": of "skipprojcfg":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optSkipProjConfigFile) incl(gGlobalOptions, optSkipProjConfigFile)
of "skipusercfg": of "skipusercfg":
@ -529,17 +529,17 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "skipparentcfg": of "skipparentcfg":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optSkipParentConfigFiles) incl(gGlobalOptions, optSkipParentConfigFiles)
of "genscript": of "genscript":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
incl(gGlobalOptions, optGenScript) incl(gGlobalOptions, optGenScript)
of "lib": of "lib":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
libpath = processPath(arg, notRelativeToProj=true) libpath = processPath(arg, notRelativeToProj=true)
of "putenv": of "putenv":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
splitSwitch(arg, key, val, pass, info) splitSwitch(arg, key, val, pass, info)
os.putEnv(key, val) os.putEnv(key, val)
of "cc": of "cc":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
setCC(arg) setCC(arg)
of "track": of "track":
@ -548,7 +548,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
of "trackdirty": of "trackdirty":
expectArg(switch, arg, pass, info) expectArg(switch, arg, pass, info)
trackDirty(arg, info) trackDirty(arg, info)
of "suggest": of "suggest":
expectNoArg(switch, arg, pass, info) expectNoArg(switch, arg, pass, info)
gIdeCmd = ideSug gIdeCmd = ideSug
of "def": of "def":
@ -584,7 +584,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
else: else:
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
else: invalidCmdLineOption(pass, switch, info) else: invalidCmdLineOption(pass, switch, info)
proc processCommand(switch: string, pass: TCmdLinePass) = proc processCommand(switch: string, pass: TCmdLinePass) =
var cmd, arg: string var cmd, arg: string
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
@ -600,14 +600,14 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
# we fix this here # we fix this here
var bracketLe = strutils.find(p.key, '[') var bracketLe = strutils.find(p.key, '[')
if bracketLe >= 0: if bracketLe >= 0:
var key = substr(p.key, 0, bracketLe - 1) var key = substr(p.key, 0, bracketLe - 1)
var val = substr(p.key, bracketLe + 1) & ':' & p.val var val = substr(p.key, bracketLe + 1) & ':' & p.val
processSwitch(key, val, pass, gCmdLineInfo) processSwitch(key, val, pass, gCmdLineInfo)
else: else:
processSwitch(p.key, p.val, pass, gCmdLineInfo) processSwitch(p.key, p.val, pass, gCmdLineInfo)
proc processArgument*(pass: TCmdLinePass; p: OptParser; proc processArgument*(pass: TCmdLinePass; p: OptParser;
argsCount: var int): bool = argsCount: var int): bool =
if argsCount == 0: if argsCount == 0:
options.command = p.key options.command = p.key

View file

@ -9,41 +9,41 @@
# This module implements a dependency file generator. # This module implements a dependency file generator.
import import
os, options, ast, astalgo, msgs, ropes, idents, passes, importer os, options, ast, astalgo, msgs, ropes, idents, passes, importer
proc generateDot*(project: string) proc generateDot*(project: string)
type type
TGen = object of TPassContext TGen = object of TPassContext
module*: PSym module*: PSym
PGen = ref TGen PGen = ref TGen
var gDotGraph: PRope # the generated DOT file; we need a global variable var gDotGraph: Rope # the generated DOT file; we need a global variable
proc addDependencyAux(importing, imported: string) = proc addDependencyAux(importing, imported: string) =
appf(gDotGraph, "$1 -> $2;$n", [toRope(importing), toRope(imported)]) addf(gDotGraph, "$1 -> $2;$n", [rope(importing), rope(imported)])
# s1 -> s2_4[label="[0-9]"]; # s1 -> s2_4[label="[0-9]"];
proc addDotDependency(c: PPassContext, n: PNode): PNode = proc addDotDependency(c: PPassContext, n: PNode): PNode =
result = n result = n
var g = PGen(c) var g = PGen(c)
case n.kind case n.kind
of nkImportStmt: of nkImportStmt:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var imported = getModuleName(n.sons[i]) var imported = getModuleName(n.sons[i])
addDependencyAux(g.module.name.s, imported) addDependencyAux(g.module.name.s, imported)
of nkFromStmt, nkImportExceptStmt: of nkFromStmt, nkImportExceptStmt:
var imported = getModuleName(n.sons[0]) var imported = getModuleName(n.sons[0])
addDependencyAux(g.module.name.s, imported) addDependencyAux(g.module.name.s, imported)
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr: of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i]) for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
else: else:
discard discard
proc generateDot(project: string) = proc generateDot(project: string) =
writeRope(ropef("digraph $1 {$n$2}$n", [ writeRope("digraph $1 {$n$2}$n" % [
toRope(changeFileExt(extractFilename(project), "")), gDotGraph]), rope(changeFileExt(extractFilename(project), "")), gDotGraph],
changeFileExt(project, "dot")) changeFileExt(project, "dot"))
proc myOpen(module: PSym): PPassContext = proc myOpen(module: PSym): PPassContext =

View file

@ -17,9 +17,9 @@ import
importer, sempass2, json, xmltree, cgi, typesrenderer importer, sempass2, json, xmltree, cgi, typesrenderer
type type
TSections = array[TSymKind, PRope] TSections = array[TSymKind, Rope]
TDocumentor = object of rstgen.TRstGenerator TDocumentor = object of rstgen.TRstGenerator
modDesc: PRope # module description modDesc: Rope # module description
id: int # for generating IDs id: int # for generating IDs
toc, section: TSections toc, section: TSections
indexValFilename: string indexValFilename: string
@ -82,9 +82,9 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
result.seenSymbols = newStringTable(modeCaseInsensitive) result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100 result.id = 100
proc dispA(dest: var PRope, xml, tex: string, args: openArray[PRope]) = proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
if gCmd != cmdRst2tex: appf(dest, xml, args) if gCmd != cmdRst2tex: addf(dest, xml, args)
else: appf(dest, tex, args) else: addf(dest, tex, args)
proc getVarIdx(varnames: openArray[string], id: string): int = proc getVarIdx(varnames: openArray[string], id: string): int =
for i in countup(0, high(varnames)): for i in countup(0, high(varnames)):
@ -92,8 +92,8 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
return i return i
result = -1 result = -1
proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string], proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
varvalues: openArray[PRope]): PRope = varvalues: openArray[Rope]): Rope =
var i = 0 var i = 0
var L = len(frmt) var L = len(frmt)
result = nil result = nil
@ -103,11 +103,11 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
inc(i) # skip '$' inc(i) # skip '$'
case frmt[i] case frmt[i]
of '#': of '#':
app(result, varvalues[num]) add(result, varvalues[num])
inc(num) inc(num)
inc(i) inc(i)
of '$': of '$':
app(result, "$") add(result, "$")
inc(i) inc(i)
of '0'..'9': of '0'..'9':
var j = 0 var j = 0
@ -117,7 +117,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
if j > high(varvalues) + 1: internalError("ropeFormatNamedVars") if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
num = j num = j
app(result, varvalues[j - 1]) add(result, varvalues[j - 1])
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF': of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
var id = "" var id = ""
while true: while true:
@ -125,7 +125,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
inc(i) inc(i)
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
var idx = getVarIdx(varnames, id) var idx = getVarIdx(varnames, id)
if idx >= 0: app(result, varvalues[idx]) if idx >= 0: add(result, varvalues[idx])
else: rawMessage(errUnknownSubstitionVar, id) else: rawMessage(errUnknownSubstitionVar, id)
of '{': of '{':
var id = "" var id = ""
@ -137,14 +137,14 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
inc(i) # skip } inc(i) # skip }
# search for the variable: # search for the variable:
var idx = getVarIdx(varnames, id) var idx = getVarIdx(varnames, id)
if idx >= 0: app(result, varvalues[idx]) if idx >= 0: add(result, varvalues[idx])
else: rawMessage(errUnknownSubstitionVar, id) else: rawMessage(errUnknownSubstitionVar, id)
else: internalError("ropeFormatNamedVars") else: internalError("ropeFormatNamedVars")
var start = i var start = i
while i < L: while i < L:
if frmt[i] != '$': inc(i) if frmt[i] != '$': inc(i)
else: break else: break
if i - 1 >= start: app(result, substr(frmt, start, i - 1)) if i - 1 >= start: add(result, substr(frmt, start, i - 1))
proc genComment(d: PDoc, n: PNode): string = proc genComment(d: PDoc, n: PNode): string =
result = "" result = ""
@ -154,9 +154,9 @@ proc genComment(d: PDoc, n: PNode): string =
toLinenumber(n.info), toColumn(n.info), toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options + {roSkipPounds}), result) dummyHasToc, d.options + {roSkipPounds}), result)
proc genRecComment(d: PDoc, n: PNode): PRope = proc genRecComment(d: PDoc, n: PNode): Rope =
if n == nil: return nil if n == nil: return nil
result = genComment(d, n).toRope result = genComment(d, n).rope
if result == nil: if result == nil:
if n.kind notin {nkEmpty..nkNilLit}: if n.kind notin {nkEmpty..nkNilLit}:
for i in countup(0, len(n)-1): for i in countup(0, len(n)-1):
@ -331,9 +331,9 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
if not isVisible(nameNode): return if not isVisible(nameNode): return
let let
name = getName(d, nameNode) name = getName(d, nameNode)
nameRope = name.toRope nameRope = name.rope
plainDocstring = getPlainDocstring(n) # call here before genRecComment! plainDocstring = getPlainDocstring(n) # call here before genRecComment!
var result: PRope = nil var result: Rope = nil
var literal, plainName = "" var literal, plainName = ""
var kind = tkEof var kind = tkEof
var comm = genRecComment(d, n) # call this here for the side-effect! var comm = genRecComment(d, n) # call this here for the side-effect!
@ -356,69 +356,69 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
break break
of tkComment: of tkComment:
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}", dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
[toRope(esc(d.target, literal))]) [rope(esc(d.target, literal))])
of tokKeywordLow..tokKeywordHigh: of tokKeywordLow..tokKeywordHigh:
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}", dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
[toRope(literal)]) [rope(literal)])
of tkOpr: of tkOpr:
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}", dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
[toRope(esc(d.target, literal))]) [rope(esc(d.target, literal))])
of tkStrLit..tkTripleStrLit: of tkStrLit..tkTripleStrLit:
dispA(result, "<span class=\"StringLit\">$1</span>", dispA(result, "<span class=\"StringLit\">$1</span>",
"\\spanStringLit{$1}", [toRope(esc(d.target, literal))]) "\\spanStringLit{$1}", [rope(esc(d.target, literal))])
of tkCharLit: of tkCharLit:
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}", dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
[toRope(esc(d.target, literal))]) [rope(esc(d.target, literal))])
of tkIntLit..tkUInt64Lit: of tkIntLit..tkUInt64Lit:
dispA(result, "<span class=\"DecNumber\">$1</span>", dispA(result, "<span class=\"DecNumber\">$1</span>",
"\\spanDecNumber{$1}", [toRope(esc(d.target, literal))]) "\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
of tkFloatLit..tkFloat128Lit: of tkFloatLit..tkFloat128Lit:
dispA(result, "<span class=\"FloatNumber\">$1</span>", dispA(result, "<span class=\"FloatNumber\">$1</span>",
"\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))]) "\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
of tkSymbol: of tkSymbol:
dispA(result, "<span class=\"Identifier\">$1</span>", dispA(result, "<span class=\"Identifier\">$1</span>",
"\\spanIdentifier{$1}", [toRope(esc(d.target, literal))]) "\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
of tkSpaces, tkInvalid: of tkSpaces, tkInvalid:
app(result, literal) add(result, literal)
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi, of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe, tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
tkAccent, tkColonColon, tkAccent, tkColonColon,
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr: tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}", dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[toRope(esc(d.target, literal))]) [rope(esc(d.target, literal))])
inc(d.id) inc(d.id)
let let
plainNameRope = toRope(xmltree.escape(plainName.strip)) plainNameRope = rope(xmltree.escape(plainName.strip))
cleanPlainSymbol = renderPlainSymbolName(nameNode) cleanPlainSymbol = renderPlainSymbolName(nameNode)
complexSymbol = complexName(k, n, cleanPlainSymbol) complexSymbol = complexName(k, n, cleanPlainSymbol)
plainSymbolRope = toRope(cleanPlainSymbol) plainSymbolRope = rope(cleanPlainSymbol)
plainSymbolEncRope = toRope(encodeUrl(cleanPlainSymbol)) plainSymbolEncRope = rope(encodeUrl(cleanPlainSymbol))
itemIDRope = toRope(d.id) itemIDRope = rope(d.id)
symbolOrId = d.newUniquePlainSymbol(complexSymbol) symbolOrId = d.newUniquePlainSymbol(complexSymbol)
symbolOrIdRope = symbolOrId.toRope symbolOrIdRope = symbolOrId.rope
symbolOrIdEncRope = encodeUrl(symbolOrId).toRope symbolOrIdEncRope = encodeUrl(symbolOrId).rope
var seeSrcRope: PRope = nil var seeSrcRope: Rope = nil
let docItemSeeSrc = getConfigVar("doc.item.seesrc") let docItemSeeSrc = getConfigVar("doc.item.seesrc")
if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0: if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0:
# XXX toFilename doesn't really work. We need to ensure that this keeps # XXX toFilename doesn't really work. We need to ensure that this keeps
# returning a relative path. # returning a relative path.
let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl, let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl,
["path", "line"], [n.info.toFilename.toRope, toRope($n.info.line)]) ["path", "line"], [n.info.toFilename.rope, rope($n.info.line)])
dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc, dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
["path", "line", "url"], [n.info.toFilename.toRope, ["path", "line", "url"], [n.info.toFilename.rope,
toRope($n.info.line), urlRope])]) rope($n.info.line), urlRope])])
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"), add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
["name", "header", "desc", "itemID", "header_plain", "itemSym", ["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"], "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
[nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope, [nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope])) symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope]))
app(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"), add(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
["name", "header", "desc", "itemID", "header_plain", "itemSym", ["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc"], "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc"],
[toRope(getName(d, nameNode, d.splitAfter)), result, comm, [rope(getName(d, nameNode, d.splitAfter)), result, comm,
itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope, itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope,
plainSymbolEncRope, symbolOrIdEncRope])) plainSymbolEncRope, symbolOrIdEncRope]))
@ -436,7 +436,7 @@ proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
if not isVisible(nameNode): return if not isVisible(nameNode): return
var var
name = getName(d, nameNode) name = getName(d, nameNode)
comm = genRecComment(d, n).ropeToStr() comm = $genRecComment(d, n)
r: TSrcGen r: TSrcGen
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments}) initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
@ -453,14 +453,14 @@ proc checkForFalse(n: PNode): bool =
proc traceDeps(d: PDoc, n: PNode) = proc traceDeps(d: PDoc, n: PNode) =
const k = skModule const k = skModule
if d.section[k] != nil: app(d.section[k], ", ") if d.section[k] != nil: add(d.section[k], ", ")
dispA(d.section[k], dispA(d.section[k],
"<a class=\"reference external\" href=\"$1.html\">$1</a>", "<a class=\"reference external\" href=\"$1.html\">$1</a>",
"$1", [toRope(getModuleName(n))]) "$1", [rope(getModuleName(n))])
proc generateDoc*(d: PDoc, n: PNode) = proc generateDoc*(d: PDoc, n: PNode) =
case n.kind case n.kind
of nkCommentStmt: app(d.modDesc, genComment(d, n)) of nkCommentStmt: add(d.modDesc, genComment(d, n))
of nkProcDef: of nkProcDef:
when useEffectSystem: documentRaises(n) when useEffectSystem: documentRaises(n)
genItem(d, n, n.sons[namePos], skProc) genItem(d, n, n.sons[namePos], skProc)
@ -540,28 +540,28 @@ proc genSection(d: PDoc, kind: TSymKind) =
"Iterators", "Iterators", "Converters", "Macros", "Templates" "Iterators", "Iterators", "Converters", "Macros", "Templates"
] ]
if d.section[kind] == nil: return if d.section[kind] == nil: return
var title = sectionNames[kind].toRope var title = sectionNames[kind].rope
d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [ d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
"sectionid", "sectionTitle", "sectionTitleID", "content"], [ "sectionid", "sectionTitle", "sectionTitleID", "content"], [
ord(kind).toRope, title, toRope(ord(kind) + 50), d.section[kind]]) ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]])
d.toc[kind] = ropeFormatNamedVars(getConfigVar("doc.section.toc"), [ d.toc[kind] = ropeFormatNamedVars(getConfigVar("doc.section.toc"), [
"sectionid", "sectionTitle", "sectionTitleID", "content"], [ "sectionid", "sectionTitle", "sectionTitleID", "content"], [
ord(kind).toRope, title, toRope(ord(kind) + 50), d.toc[kind]]) ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]])
proc genOutFile(d: PDoc): PRope = proc genOutFile(d: PDoc): Rope =
var var
code, content: PRope code, content: Rope
title = "" title = ""
var j = 0 var j = 0
var tmp = "" var tmp = ""
renderTocEntries(d[], j, 1, tmp) renderTocEntries(d[], j, 1, tmp)
var toc = tmp.toRope var toc = tmp.rope
for i in countup(low(TSymKind), high(TSymKind)): for i in countup(low(TSymKind), high(TSymKind)):
genSection(d, i) genSection(d, i)
app(toc, d.toc[i]) add(toc, d.toc[i])
if toc != nil: if toc != nil:
toc = ropeFormatNamedVars(getConfigVar("doc.toc"), ["content"], [toc]) toc = ropeFormatNamedVars(getConfigVar("doc.toc"), ["content"], [toc])
for i in countup(low(TSymKind), high(TSymKind)): app(code, d.section[i]) for i in countup(low(TSymKind), high(TSymKind)): add(code, d.section[i])
# Extract the title. Non API modules generate an entry in the index table. # Extract the title. Non API modules generate an entry in the index table.
if d.meta[metaTitle].len != 0: if d.meta[metaTitle].len != 0:
@ -574,16 +574,16 @@ proc genOutFile(d: PDoc): PRope =
let bodyname = if d.hasToc: "doc.body_toc" else: "doc.body_no_toc" let bodyname = if d.hasToc: "doc.body_toc" else: "doc.body_no_toc"
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title", content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
"tableofcontents", "moduledesc", "date", "time", "content"], "tableofcontents", "moduledesc", "date", "time", "content"],
[title.toRope, toc, d.modDesc, toRope(getDateStr()), [title.rope, toc, d.modDesc, rope(getDateStr()),
toRope(getClockStr()), code]) rope(getClockStr()), code])
if optCompileOnly notin gGlobalOptions: if optCompileOnly notin gGlobalOptions:
# XXX what is this hack doing here? 'optCompileOnly' means raw output!? # XXX what is this hack doing here? 'optCompileOnly' means raw output!?
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title", code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
"tableofcontents", "moduledesc", "date", "time", "tableofcontents", "moduledesc", "date", "time",
"content", "author", "version", "analytics"], "content", "author", "version", "analytics"],
[title.toRope, toc, d.modDesc, toRope(getDateStr()), [title.rope, toc, d.modDesc, rope(getDateStr()),
toRope(getClockStr()), content, d.meta[metaAuthor].toRope, rope(getClockStr()), content, d.meta[metaAuthor].rope,
d.meta[metaVersion].toRope, d.analytics.toRope]) d.meta[metaVersion].rope, d.analytics.rope])
else: else:
code = content code = content
result = code result = code
@ -618,7 +618,7 @@ proc commandRstAux(filename, outExt: string) =
#d.modDesc = newMutableRope(30_000) #d.modDesc = newMutableRope(30_000)
renderRstToOut(d[], rst, modDesc) renderRstToOut(d[], rst, modDesc)
#freezeMutableRope(d.modDesc) #freezeMutableRope(d.modDesc)
d.modDesc = toRope(modDesc) d.modDesc = rope(modDesc)
writeOutput(d, filename, outExt) writeOutput(d, filename, outExt)
generateIndex(d) generateIndex(d)
@ -635,7 +635,7 @@ proc commandJSON*() =
var d = newDocumentor(gProjectFull, options.gConfigVars) var d = newDocumentor(gProjectFull, options.gConfigVars)
d.hasToc = true d.hasToc = true
var json = generateJson(d, ast) var json = generateJson(d, ast)
var content = newRope(pretty(json)) var content = rope(pretty(json))
if optStdout in gGlobalOptions: if optStdout in gGlobalOptions:
writeRope(stdout, content) writeRope(stdout, content)
@ -644,12 +644,12 @@ proc commandJSON*() =
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false) writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
proc commandBuildIndex*() = proc commandBuildIndex*() =
var content = mergeIndexes(gProjectFull).toRope var content = mergeIndexes(gProjectFull).rope
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title", let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
"tableofcontents", "moduledesc", "date", "time", "tableofcontents", "moduledesc", "date", "time",
"content", "author", "version", "analytics"], "content", "author", "version", "analytics"],
["Index".toRope, nil, nil, toRope(getDateStr()), ["Index".rope, nil, nil, rope(getDateStr()),
toRope(getClockStr()), content, nil, nil, nil]) rope(getClockStr()), content, nil, nil, nil])
# no analytics because context is not available # no analytics because context is not available
writeRope(code, getOutFile("theindex", HtmlExt)) writeRope(code, getOutFile("theindex", HtmlExt))

View file

@ -449,7 +449,7 @@ proc execExternalProgram*(cmd: string, prettyCmd = "") =
if execWithEcho(cmd, prettyCmd) != 0: if execWithEcho(cmd, prettyCmd) != 0:
rawMessage(errExecutionOfProgramFailed, "") rawMessage(errExecutionOfProgramFailed, "")
proc generateScript(projectFile: string, script: PRope) = proc generateScript(projectFile: string, script: Rope) =
let (dir, name, ext) = splitFile(projectFile) let (dir, name, ext) = splitFile(projectFile)
writeRope(script, dir / addFileExt("compile_" & name, writeRope(script, dir / addFileExt("compile_" & name,
platform.OS[targetOS].scriptExt)) platform.OS[targetOS].scriptExt))
@ -604,7 +604,7 @@ proc addExternalFileToCompile*(filename: string) =
if optForceFullMake in gGlobalOptions or externalFileChanged(filename): if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
appendStr(externalToCompile, filename) appendStr(externalToCompile, filename)
proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq, proc compileCFile(list: TLinkedList, script: var Rope, cmds: var TStringSeq,
prettyCmds: var TStringSeq, isExternal: bool) = prettyCmds: var TStringSeq, isExternal: bool) =
var it = PStrEntry(list.head) var it = PStrEntry(list.head)
while it != nil: while it != nil:
@ -615,8 +615,8 @@ proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
let (dir, name, ext) = splitFile(it.data) let (dir, name, ext) = splitFile(it.data)
add(prettyCmds, "CC: " & name) add(prettyCmds, "CC: " & name)
if optGenScript in gGlobalOptions: if optGenScript in gGlobalOptions:
app(script, compileCmd) add(script, compileCmd)
app(script, tnl) add(script, tnl)
it = PStrEntry(it.next) it = PStrEntry(it.next)
proc callCCompiler*(projectfile: string) = proc callCCompiler*(projectfile: string) =
@ -627,7 +627,7 @@ proc callCCompiler*(projectfile: string) =
# generated # generated
fileCounter = 0 fileCounter = 0
var c = cCompiler var c = cCompiler
var script: PRope = nil var script: Rope = nil
var cmds: TStringSeq = @[] var cmds: TStringSeq = @[]
var prettyCmds: TStringSeq = @[] var prettyCmds: TStringSeq = @[]
let prettyCb = proc (idx: int) = let prettyCb = proc (idx: int) =
@ -710,30 +710,30 @@ proc callCCompiler*(projectfile: string) =
else: else:
linkCmd = "" linkCmd = ""
if optGenScript in gGlobalOptions: if optGenScript in gGlobalOptions:
app(script, linkCmd) add(script, linkCmd)
app(script, tnl) add(script, tnl)
generateScript(projectfile, script) generateScript(projectfile, script)
proc genMappingFiles(list: TLinkedList): PRope = proc genMappingFiles(list: TLinkedList): Rope =
var it = PStrEntry(list.head) var it = PStrEntry(list.head)
while it != nil: while it != nil:
appf(result, "--file:r\"$1\"$N", [toRope(it.data)]) addf(result, "--file:r\"$1\"$N", [rope(it.data)])
it = PStrEntry(it.next) it = PStrEntry(it.next)
proc writeMapping*(gSymbolMapping: PRope) = proc writeMapping*(gSymbolMapping: Rope) =
if optGenMapping notin gGlobalOptions: return if optGenMapping notin gGlobalOptions: return
var code = toRope("[C_Files]\n") var code = rope("[C_Files]\n")
app(code, genMappingFiles(toCompile)) add(code, genMappingFiles(toCompile))
app(code, genMappingFiles(externalToCompile)) add(code, genMappingFiles(externalToCompile))
app(code, "\n[C_Compiler]\nFlags=") add(code, "\n[C_Compiler]\nFlags=")
app(code, strutils.escape(getCompileOptions())) add(code, strutils.escape(getCompileOptions()))
app(code, "\n[Linker]\nFlags=") add(code, "\n[Linker]\nFlags=")
app(code, strutils.escape(getLinkOptions() & " " & add(code, strutils.escape(getLinkOptions() & " " &
getConfigVar(cCompiler, ".options.linker"))) getConfigVar(cCompiler, ".options.linker")))
app(code, "\n[Environment]\nlibpath=") add(code, "\n[Environment]\nlibpath=")
app(code, strutils.escape(libpath)) add(code, strutils.escape(libpath))
appf(code, "\n[Symbols]$n$1", [gSymbolMapping]) addf(code, "\n[Symbols]$n$1", [gSymbolMapping])
writeRope(code, joinPath(gProjectPath, "mapping.txt")) writeRope(code, joinPath(gProjectPath, "mapping.txt"))

View file

@ -62,7 +62,7 @@ Files: "icons/koch_icon.o"
Files: "compiler/readme.txt" Files: "compiler/readme.txt"
Files: "compiler/installer.ini" Files: "compiler/installer.ini"
Files: "compiler/nim.nimrod.cfg" Files: "compiler/nim.nim.cfg"
Files: "compiler/*.nim" Files: "compiler/*.nim"
Files: "doc/*.txt" Files: "doc/*.txt"
Files: "doc/manual/*.txt" Files: "doc/manual/*.txt"

File diff suppressed because it is too large Load diff

View file

@ -9,138 +9,138 @@
## Type info generation for the JS backend. ## Type info generation for the JS backend.
proc genTypeInfo(p: PProc, typ: PType): PRope proc genTypeInfo(p: PProc, typ: PType): Rope
proc genObjectFields(p: PProc, typ: PType, n: PNode): PRope = proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
var var
s, u: PRope s, u: Rope
length: int length: int
field: PSym field: PSym
b: PNode b: PNode
result = nil result = nil
case n.kind case n.kind
of nkRecList: of nkRecList:
length = sonsLen(n) length = sonsLen(n)
if length == 1: if length == 1:
result = genObjectFields(p, typ, n.sons[0]) result = genObjectFields(p, typ, n.sons[0])
else: else:
s = nil s = nil
for i in countup(0, length - 1): for i in countup(0, length - 1):
if i > 0: app(s, ", " & tnl) if i > 0: add(s, ", " & tnl)
app(s, genObjectFields(p, typ, n.sons[i])) add(s, genObjectFields(p, typ, n.sons[i]))
result = ropef("{kind: 2, len: $1, offset: 0, " & result = ("{kind: 2, len: $1, offset: 0, " &
"typ: null, name: null, sons: [$2]}", [toRope(length), s]) "typ: null, name: null, sons: [$2]}") % [rope(length), s]
of nkSym: of nkSym:
field = n.sym field = n.sym
s = genTypeInfo(p, field.typ) s = genTypeInfo(p, field.typ)
result = ropef("{kind: 1, offset: \"$1\", len: 0, " & result = ("{kind: 1, offset: \"$1\", len: 0, " &
"typ: $2, name: $3, sons: null}", "typ: $2, name: $3, sons: null}") %
[mangleName(field), s, makeJSString(field.name.s)]) [mangleName(field), s, makeJSString(field.name.s)]
of nkRecCase: of nkRecCase:
length = sonsLen(n) length = sonsLen(n)
if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields") if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
field = n.sons[0].sym field = n.sons[0].sym
s = genTypeInfo(p, field.typ) s = genTypeInfo(p, field.typ)
for i in countup(1, length - 1): for i in countup(1, length - 1):
b = n.sons[i] # branch b = n.sons[i] # branch
u = nil u = nil
case b.kind case b.kind
of nkOfBranch: of nkOfBranch:
if sonsLen(b) < 2: if sonsLen(b) < 2:
internalError(b.info, "genObjectFields; nkOfBranch broken") internalError(b.info, "genObjectFields; nkOfBranch broken")
for j in countup(0, sonsLen(b) - 2): for j in countup(0, sonsLen(b) - 2):
if u != nil: app(u, ", ") if u != nil: add(u, ", ")
if b.sons[j].kind == nkRange: if b.sons[j].kind == nkRange:
appf(u, "[$1, $2]", [toRope(getOrdValue(b.sons[j].sons[0])), addf(u, "[$1, $2]", [rope(getOrdValue(b.sons[j].sons[0])),
toRope(getOrdValue(b.sons[j].sons[1]))]) rope(getOrdValue(b.sons[j].sons[1]))])
else: else:
app(u, toRope(getOrdValue(b.sons[j]))) add(u, rope(getOrdValue(b.sons[j])))
of nkElse: of nkElse:
u = toRope(lengthOrd(field.typ)) u = rope(lengthOrd(field.typ))
else: internalError(n.info, "genObjectFields(nkRecCase)") else: internalError(n.info, "genObjectFields(nkRecCase)")
if result != nil: app(result, ", " & tnl) if result != nil: add(result, ", " & tnl)
appf(result, "[SetConstr($1), $2]", addf(result, "[SetConstr($1), $2]",
[u, genObjectFields(p, typ, lastSon(b))]) [u, genObjectFields(p, typ, lastSon(b))])
result = ropef("{kind: 3, offset: \"$1\", len: $3, " & result = ("{kind: 3, offset: \"$1\", len: $3, " &
"typ: $2, name: $4, sons: [$5]}", [mangleName(field), s, "typ: $2, name: $4, sons: [$5]}") % [mangleName(field), s,
toRope(lengthOrd(field.typ)), makeJSString(field.name.s), result]) rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
else: internalError(n.info, "genObjectFields") else: internalError(n.info, "genObjectFields")
proc genObjectInfo(p: PProc, typ: PType, name: PRope) = proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
"finalizer: null};$n", [name, toRope(ord(typ.kind))]) "finalizer: null};$n") % [name, rope(ord(typ.kind))]
prepend(p.g.typeInfo, s) prepend(p.g.typeInfo, s)
appf(p.g.typeInfo, "var NNI$1 = $2;$n", addf(p.g.typeInfo, "var NNI$1 = $2;$n",
[toRope(typ.id), genObjectFields(p, typ, typ.n)]) [rope(typ.id), genObjectFields(p, typ, typ.n)])
appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
if (typ.kind == tyObject) and (typ.sons[0] != nil): if (typ.kind == tyObject) and (typ.sons[0] != nil):
appf(p.g.typeInfo, "$1.base = $2;$n", addf(p.g.typeInfo, "$1.base = $2;$n",
[name, genTypeInfo(p, typ.sons[0])]) [name, genTypeInfo(p, typ.sons[0])])
proc genTupleFields(p: PProc, typ: PType): PRope = proc genTupleFields(p: PProc, typ: PType): Rope =
var s: PRope = nil var s: Rope = nil
for i in 0 .. <typ.len: for i in 0 .. <typ.len:
if i > 0: app(s, ", " & tnl) if i > 0: add(s, ", " & tnl)
s.appf("{kind: 1, offset: \"Field$1\", len: 0, " & s.addf("{kind: 1, offset: \"Field$1\", len: 0, " &
"typ: $2, name: \"Field$1\", sons: null}", "typ: $2, name: \"Field$1\", sons: null}",
[i.toRope, genTypeInfo(p, typ.sons[i])]) [i.rope, genTypeInfo(p, typ.sons[i])])
result = ropef("{kind: 2, len: $1, offset: 0, " & result = ("{kind: 2, len: $1, offset: 0, " &
"typ: null, name: null, sons: [$2]}", [toRope(typ.len), s]) "typ: null, name: null, sons: [$2]}") % [rope(typ.len), s]
proc genTupleInfo(p: PProc, typ: PType, name: PRope) = proc genTupleInfo(p: PProc, typ: PType, name: Rope) =
var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
"finalizer: null};$n", [name, toRope(ord(typ.kind))]) "finalizer: null};$n") % [name, rope(ord(typ.kind))]
prepend(p.g.typeInfo, s) prepend(p.g.typeInfo, s)
appf(p.g.typeInfo, "var NNI$1 = $2;$n", addf(p.g.typeInfo, "var NNI$1 = $2;$n",
[toRope(typ.id), genTupleFields(p, typ)]) [rope(typ.id), genTupleFields(p, typ)])
appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
proc genEnumInfo(p: PProc, typ: PType, name: PRope) = proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
let length = sonsLen(typ.n) let length = sonsLen(typ.n)
var s: PRope = nil var s: Rope = nil
for i in countup(0, length - 1): for i in countup(0, length - 1):
if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo") if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
let field = typ.n.sons[i].sym let field = typ.n.sons[i].sym
if i > 0: app(s, ", " & tnl) if i > 0: add(s, ", " & tnl)
let extName = if field.ast == nil: field.name.s else: field.ast.strVal let extName = if field.ast == nil: field.name.s else: field.ast.strVal
appf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}", addf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
[toRope(field.position), name, makeJSString(extName)]) [rope(field.position), name, makeJSString(extName)])
var n = ropef("var NNI$1 = {kind: 2, offset: 0, typ: null, " & var n = ("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
"name: null, len: $2, sons: [$3]};$n", [toRope(typ.id), toRope(length), s]) "name: null, len: $2, sons: [$3]};$n") % [rope(typ.id), rope(length), s]
s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
"finalizer: null};$n", [name, toRope(ord(typ.kind))]) "finalizer: null};$n") % [name, rope(ord(typ.kind))]
prepend(p.g.typeInfo, s) prepend(p.g.typeInfo, s)
app(p.g.typeInfo, n) add(p.g.typeInfo, n)
appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
if typ.sons[0] != nil: if typ.sons[0] != nil:
appf(p.g.typeInfo, "$1.base = $2;$n", addf(p.g.typeInfo, "$1.base = $2;$n",
[name, genTypeInfo(p, typ.sons[0])]) [name, genTypeInfo(p, typ.sons[0])])
proc genTypeInfo(p: PProc, typ: PType): PRope = proc genTypeInfo(p: PProc, typ: PType): Rope =
var t = typ var t = typ
if t.kind == tyGenericInst: t = lastSon(t) if t.kind == tyGenericInst: t = lastSon(t)
result = ropef("NTI$1", [toRope(t.id)]) result = "NTI$1" % [rope(t.id)]
if containsOrIncl(p.g.typeInfoGenerated, t.id): return if containsOrIncl(p.g.typeInfoGenerated, t.id): return
case t.kind case t.kind
of tyDistinct: of tyDistinct:
result = genTypeInfo(p, typ.sons[0]) result = genTypeInfo(p, typ.sons[0])
of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64: of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64:
var s = ropef( var s =
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
[result, toRope(ord(t.kind))]) [result, rope(ord(t.kind))]
prepend(p.g.typeInfo, s) prepend(p.g.typeInfo, s)
of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet: of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet:
var s = ropef( var s =
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
[result, toRope(ord(t.kind))]) [result, rope(ord(t.kind))]
prepend(p.g.typeInfo, s) prepend(p.g.typeInfo, s)
appf(p.g.typeInfo, "$1.base = $2;$n", addf(p.g.typeInfo, "$1.base = $2;$n",
[result, genTypeInfo(p, typ.lastSon)]) [result, genTypeInfo(p, typ.lastSon)])
of tyArrayConstr, tyArray: of tyArrayConstr, tyArray:
var s = ropef( var s =
"var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
[result, toRope(ord(t.kind))]) [result, rope(ord(t.kind))]
prepend(p.g.typeInfo, s) prepend(p.g.typeInfo, s)
appf(p.g.typeInfo, "$1.base = $2;$n", addf(p.g.typeInfo, "$1.base = $2;$n",
[result, genTypeInfo(p, typ.sons[1])]) [result, genTypeInfo(p, typ.sons[1])])
of tyEnum: genEnumInfo(p, t, result) of tyEnum: genEnumInfo(p, t, result)
of tyObject: genObjectInfo(p, t, result) of tyObject: genObjectInfo(p, t, result)

View file

@ -9,92 +9,92 @@
# This include file implements lambda lifting for the transformator. # This include file implements lambda lifting for the transformator.
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, magicsys, rodread, lowerings idents, renderer, types, magicsys, rodread, lowerings
discard """ discard """
The basic approach is that captured vars need to be put on the heap and The basic approach is that captured vars need to be put on the heap and
that the calling chain needs to be explicitly modelled. Things to consider: that the calling chain needs to be explicitly modelled. Things to consider:
proc a = proc a =
var v = 0 var v = 0
proc b = proc b =
var w = 2 var w = 2
for x in 0..3: for x in 0..3:
proc c = capture v, w, x proc c = capture v, w, x
c() c()
b() b()
for x in 0..4: for x in 0..4:
proc d = capture x proc d = capture x
d() d()
Needs to be translated into: Needs to be translated into:
proc a = proc a =
var cl: * var cl: *
new cl new cl
cl.v = 0 cl.v = 0
proc b(cl) = proc b(cl) =
var bcl: * var bcl: *
new bcl new bcl
bcl.w = 2 bcl.w = 2
bcl.up = cl bcl.up = cl
for x in 0..3: for x in 0..3:
var bcl2: * var bcl2: *
new bcl2 new bcl2
bcl2.up = bcl bcl2.up = bcl
bcl2.up2 = cl bcl2.up2 = cl
bcl2.x = x bcl2.x = x
proc c(cl) = capture cl.up2.v, cl.up.w, cl.x proc c(cl) = capture cl.up2.v, cl.up.w, cl.x
c(bcl2) c(bcl2)
c(bcl) c(bcl)
b(cl) b(cl)
for x in 0..4: for x in 0..4:
var acl2: * var acl2: *
new acl2 new acl2
acl2.x = x acl2.x = x
proc d(cl) = capture cl.x proc d(cl) = capture cl.x
d(acl2) d(acl2)
Closures as interfaces: Closures as interfaces:
proc outer: T = proc outer: T =
var captureMe: TObject # value type required for efficiency var captureMe: TObject # value type required for efficiency
proc getter(): int = result = captureMe.x proc getter(): int = result = captureMe.x
proc setter(x: int) = captureMe.x = x proc setter(x: int) = captureMe.x = x
result = (getter, setter) result = (getter, setter)
Is translated to: Is translated to:
proc outer: T = proc outer: T =
var cl: * var cl: *
new cl new cl
proc getter(cl): int = result = cl.captureMe.x proc getter(cl): int = result = cl.captureMe.x
proc setter(cl: *, x: int) = cl.captureMe.x = x proc setter(cl: *, x: int) = cl.captureMe.x = x
result = ((cl, getter), (cl, setter)) result = ((cl, getter), (cl, setter))
For 'byref' capture, the outer proc needs to access the captured var through For 'byref' capture, the outer proc needs to access the captured var through
the indirection too. For 'bycopy' capture, the outer proc accesses the var the indirection too. For 'bycopy' capture, the outer proc accesses the var
not through the indirection. not through the indirection.
Possible optimizations: Possible optimizations:
1) If the closure contains a single 'ref' and this 1) If the closure contains a single 'ref' and this
reference is not re-assigned (check ``sfAddrTaken`` flag) make this the reference is not re-assigned (check ``sfAddrTaken`` flag) make this the
closure. This is an important optimization if closures are used as closure. This is an important optimization if closures are used as
interfaces. interfaces.
2) If the closure does not escape, put it onto the stack, not on the heap. 2) If the closure does not escape, put it onto the stack, not on the heap.
3) Dataflow analysis would help to eliminate the 'up' indirections. 3) Dataflow analysis would help to eliminate the 'up' indirections.
@ -126,7 +126,7 @@ type
fn, closureParam, state, resultSym: PSym # most are only valid if fn, closureParam, state, resultSym: PSym # most are only valid if
# fn.kind == skClosureIterator # fn.kind == skClosureIterator
obj: PType obj: PType
PEnv = ref TEnv PEnv = ref TEnv
TEnv {.final.} = object of RootObj TEnv {.final.} = object of RootObj
attachedNode, replacementNode: PNode attachedNode, replacementNode: PNode
@ -141,7 +141,7 @@ type
# if up.fn != fn then we cross function boundaries. # if up.fn != fn then we cross function boundaries.
# This is an important case to consider. # This is an important case to consider.
vars: IntSet # variables belonging to this environment vars: IntSet # variables belonging to this environment
TOuterContext = object TOuterContext = object
fn: PSym # may also be a module! fn: PSym # may also be a module!
head: PEnv head: PEnv
@ -284,7 +284,7 @@ proc addClosureParam(fn: PSym; e: PEnv) =
#assert e.obj.kind == tyObject #assert e.obj.kind == tyObject
proc illegalCapture(s: PSym): bool {.inline.} = proc illegalCapture(s: PSym): bool {.inline.} =
result = skipTypes(s.typ, abstractInst).kind in result = skipTypes(s.typ, abstractInst).kind in
{tyVar, tyOpenArray, tyVarargs} or {tyVar, tyOpenArray, tyVarargs} or
s.kind == skResult s.kind == skResult
@ -344,7 +344,7 @@ proc createUpField(obj, fieldType: PType): PSym =
#rawAddField(obj, result) #rawAddField(obj, result)
addField(obj, result) addField(obj, result)
proc captureVar(o: POuterContext; top: PEnv; local: PSym; proc captureVar(o: POuterContext; top: PEnv; local: PSym;
info: TLineInfo): bool = info: TLineInfo): bool =
# first check if we should be concerned at all: # first check if we should be concerned at all:
var it = top var it = top
@ -408,7 +408,7 @@ proc gatherVars(o: POuterContext; e: PEnv; n: PNode): int =
var s = n.sym var s = n.sym
if interestingVar(s) and e.fn != s.owner: if interestingVar(s) and e.fn != s.owner:
if captureVar(o, e, s, n.info): result = 1 if captureVar(o, e, s, n.info): result = 1
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure, nkProcDef, of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure, nkProcDef,
nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkTypeSection: nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkTypeSection:
discard discard
else: else:
@ -418,7 +418,7 @@ proc gatherVars(o: POuterContext; e: PEnv; n: PNode): int =
proc generateThunk(prc: PNode, dest: PType): PNode = proc generateThunk(prc: PNode, dest: PType): PNode =
## Converts 'prc' into '(thunk, nil)' so that it's compatible with ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
## a closure. ## a closure.
# we cannot generate a proper thunk here for GC-safety reasons (see internal # we cannot generate a proper thunk here for GC-safety reasons (see internal
# documentation): # documentation):
if gCmd == cmdCompileToJS: return prc if gCmd == cmdCompileToJS: return prc
@ -515,7 +515,7 @@ proc closureCreationPoint(n: PNode): PNode =
proc addParamsToEnv(fn: PSym; env: PEnv) = proc addParamsToEnv(fn: PSym; env: PEnv) =
let params = fn.typ.n let params = fn.typ.n
for i in 1.. <params.len: for i in 1.. <params.len:
if params.sons[i].kind != nkSym: if params.sons[i].kind != nkSym:
internalError(params.info, "liftLambdas: strange params") internalError(params.info, "liftLambdas: strange params")
let param = params.sons[i].sym let param = params.sons[i].sym
@ -541,7 +541,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
addParamsToEnv(fn, envB) addParamsToEnv(fn, envB)
searchForInnerProcs(o, body, envB) searchForInnerProcs(o, body, envB)
fn.ast.sons[bodyPos] = ex fn.ast.sons[bodyPos] = ex
let capturedCounter = gatherVars(o, envB, body) let capturedCounter = gatherVars(o, envB, body)
# dummy closure param needed? # dummy closure param needed?
if capturedCounter == 0 and fn.typ.callConv == ccClosure: if capturedCounter == 0 and fn.typ.callConv == ccClosure:
@ -560,7 +560,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt: of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
# some nodes open a new scope, so they are candidates for the insertion # some nodes open a new scope, so they are candidates for the insertion
# of closure creation; however for simplicity we merge closures between # of closure creation; however for simplicity we merge closures between
# branches, in fact, only loop bodies are of interest here as only they # branches, in fact, only loop bodies are of interest here as only they
# yield observable changes in semantics. For Zahary we also # yield observable changes in semantics. For Zahary we also
# include ``nkBlock``. We don't do this for closure iterators because # include ``nkBlock``. We don't do this for closure iterators because
# 'yield' can produce wrong code otherwise (XXX show example): # 'yield' can produce wrong code otherwise (XXX show example):
@ -598,7 +598,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
internalError(it.info, "searchForInnerProcs") internalError(it.info, "searchForInnerProcs")
of nkClosure: of nkClosure:
searchForInnerProcs(o, n.sons[0], env) searchForInnerProcs(o, n.sons[0], env)
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkTypeSection: nkTypeSection:
# don't recurse here: # don't recurse here:
discard discard
@ -606,7 +606,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
searchForInnerProcs(o, n.sons[i], env) searchForInnerProcs(o, n.sons[i], env)
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode = proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would # Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
# mean to be able to capture string literals which have no GC header. # mean to be able to capture string literals which have no GC header.
# However this can only happen if the capture happens through a parameter, # However this can only happen if the capture happens through a parameter,
@ -624,7 +624,7 @@ proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PNode): PNode =
result.add(v) result.add(v)
# add 'new' statement: # add 'new' statement:
result.add(newCall(getSysSym"internalNew", env)) result.add(newCall(getSysSym"internalNew", env))
# add assignment statements: # add assignment statements:
for local in scope.capturedVars: for local in scope.capturedVars:
let fieldAccess = indirectAccess(env, local, env.info) let fieldAccess = indirectAccess(env, local, env.info)
@ -696,10 +696,10 @@ proc transformYield(c: POuterContext, n: PNode, it: TIter): PNode =
retStmt.add(a) retStmt.add(a)
else: else:
retStmt.add(emptyNode) retStmt.add(emptyNode)
var stateLabelStmt = newNodeI(nkState, n.info) var stateLabelStmt = newNodeI(nkState, n.info)
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt))) stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
result.add(stateAsgnStmt) result.add(stateAsgnStmt)
result.add(retStmt) result.add(retStmt)
@ -725,7 +725,7 @@ proc liftIterSym(n: PNode; owner: PSym): PNode =
assert iter.kind == skClosureIterator assert iter.kind == skClosureIterator
result = newNodeIT(nkStmtListExpr, n.info, n.typ) result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let hp = getHiddenParam(iter) let hp = getHiddenParam(iter)
let env = newSym(skLet, iter.name, owner, n.info) let env = newSym(skLet, iter.name, owner, n.info)
env.typ = hp.typ env.typ = hp.typ
@ -800,7 +800,7 @@ proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
# with some rather primitive check for now: # with some rather primitive check for now:
if n.kind == nkStmtList and n.len > 0: if n.kind == nkStmtList and n.len > 0:
if n.sons[0].kind == nkGotoState: return nil if n.sons[0].kind == nkGotoState: return nil
if n.len > 1 and n[1].kind == nkStmtList and n[1].len > 0 and if n.len > 1 and n[1].kind == nkStmtList and n[1].len > 0 and
n[1][0].kind == nkGotoState: n[1][0].kind == nkGotoState:
return nil return nil
result = newNodeI(nkStmtList, it.fn.info) result = newNodeI(nkStmtList, it.fn.info)
@ -812,7 +812,7 @@ proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
var state0 = newNodeI(nkState, it.fn.info) var state0 = newNodeI(nkState, it.fn.info)
state0.add(newIntNode(nkIntLit, 0)) state0.add(newIntNode(nkIntLit, 0))
result.add(state0) result.add(state0)
let newBody = transformOuterProc(o, n, it) let newBody = transformOuterProc(o, n, it)
if newBody != nil: if newBody != nil:
result.add(newBody) result.add(newBody)
@ -899,7 +899,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
let x = closure.createdVar let x = closure.createdVar
assert x != nil assert x != nil
return makeClosure(local, x, n.info) return makeClosure(local, x, n.info)
if not contains(o.capturedVars, local.id): return if not contains(o.capturedVars, local.id): return
# change 'local' to 'closure.local', unless it's a 'byCopy' variable: # change 'local' to 'closure.local', unless it's a 'byCopy' variable:
# if sfByCopy notin local.flags: # if sfByCopy notin local.flags:
@ -946,7 +946,7 @@ proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
proc liftLambdas*(fn: PSym, body: PNode): PNode = proc liftLambdas*(fn: PSym, body: PNode): PNode =
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ... # the transformation even when compiling to JS ...
if body.kind == nkEmpty or gCmd == cmdCompileToJS or if body.kind == nkEmpty or gCmd == cmdCompileToJS or
fn.skipGenericOwner.kind != skModule: fn.skipGenericOwner.kind != skModule:
# ignore forward declaration: # ignore forward declaration:
result = body result = body
@ -985,17 +985,17 @@ proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
proc liftForLoop*(body: PNode): PNode = proc liftForLoop*(body: PNode): PNode =
# problem ahead: the iterator could be invoked indirectly, but then # problem ahead: the iterator could be invoked indirectly, but then
# we don't know what environment to create here: # we don't know what environment to create here:
# #
# iterator count(): int = # iterator count(): int =
# yield 0 # yield 0
# #
# iterator count2(): int = # iterator count2(): int =
# var x = 3 # var x = 3
# yield x # yield x
# inc x # inc x
# yield x # yield x
# #
# proc invoke(iter: iterator(): int) = # proc invoke(iter: iterator(): int) =
# for x in iter(): echo x # for x in iter(): echo x
# #
@ -1004,7 +1004,7 @@ proc liftForLoop*(body: PNode): PNode =
for i in foo(): ... for i in foo(): ...
Is transformed to: Is transformed to:
cl = createClosure() cl = createClosure()
while true: while true:
let i = foo(cl) let i = foo(cl)
@ -1016,7 +1016,7 @@ proc liftForLoop*(body: PNode): PNode =
var call = body[L-2] var call = body[L-2]
result = newNodeI(nkStmtList, body.info) result = newNodeI(nkStmtList, body.info)
# static binding? # static binding?
var env: PSym var env: PSym
if call[0].kind == nkSym and call[0].sym.kind == skClosureIterator: if call[0].kind == nkSym and call[0].sym.kind == skClosureIterator:
@ -1030,18 +1030,18 @@ proc liftForLoop*(body: PNode): PNode =
result.add(v) result.add(v)
# add 'new' statement: # add 'new' statement:
result.add(newCall(getSysSym"internalNew", env.newSymNode)) result.add(newCall(getSysSym"internalNew", env.newSymNode))
var loopBody = newNodeI(nkStmtList, body.info, 3) var loopBody = newNodeI(nkStmtList, body.info, 3)
var whileLoop = newNodeI(nkWhileStmt, body.info, 2) var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool)) whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool))
whileLoop.sons[1] = loopBody whileLoop.sons[1] = loopBody
result.add whileLoop result.add whileLoop
# setup loopBody: # setup loopBody:
# gather vars in a tuple: # gather vars in a tuple:
var v2 = newNodeI(nkLetSection, body.info) var v2 = newNodeI(nkLetSection, body.info)
var vpart = newNodeI(if L == 3: nkIdentDefs else: nkVarTuple, body.info) var vpart = newNodeI(if L == 3: nkIdentDefs else: nkVarTuple, body.info)
for i in 0 .. L-3: for i in 0 .. L-3:
assert body[i].kind == nkSym assert body[i].kind == nkSym
body[i].sym.kind = skLet body[i].sym.kind = skLet
addSon(vpart, body[i]) addSon(vpart, body[i])

View file

@ -131,24 +131,10 @@ type
var gLinesCompiled*: int # all lines that have been compiled var gLinesCompiled*: int # all lines that have been compiled
proc isKeyword*(kind: TTokType): bool
proc openLexer*(lex: var TLexer, fileidx: int32, inputstream: PLLStream)
proc rawGetTok*(L: var TLexer, tok: var TToken)
# reads in the next token into tok and skips it
proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} = proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
newLineInfo(L.fileIdx, tok.line, tok.col) newLineInfo(L.fileIdx, tok.line, tok.col)
proc closeLexer*(lex: var TLexer) proc isKeyword*(kind: TTokType): bool =
proc printTok*(tok: TToken)
proc tokToStr*(tok: TToken): string
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
openLexer(lex, filename.fileInfoIdx, inputstream)
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
proc isKeyword(kind: TTokType): bool =
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
proc isNimIdentifier*(s: string): bool = proc isNimIdentifier*(s: string): bool =
@ -206,14 +192,17 @@ proc fillToken(L: var TToken) =
L.base = base10 L.base = base10
L.ident = dummyIdent L.ident = dummyIdent
proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) = proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
openBaseLexer(lex, inputstream) openBaseLexer(lex, inputstream)
lex.fileIdx = fileidx lex.fileIdx = fileidx
lex.indentAhead = - 1 lex.indentAhead = - 1
lex.currLineIndent = 0 lex.currLineIndent = 0
inc(lex.lineNumber, inputstream.lineOffset) inc(lex.lineNumber, inputstream.lineOffset)
proc closeLexer(lex: var TLexer) = proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
openLexer(lex, filename.fileInfoIdx, inputstream)
proc closeLexer*(lex: var TLexer) =
inc(gLinesCompiled, lex.lineNumber) inc(gLinesCompiled, lex.lineNumber)
closeBaseLexer(lex) closeBaseLexer(lex)
@ -229,7 +218,7 @@ proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
else: else:
L.errorHandler(info, msg, arg) L.errorHandler(info, msg, arg)
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") = proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
L.dispMessage(getLineInfo(L), msg, arg) L.dispMessage(getLineInfo(L), msg, arg)
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
@ -785,7 +774,7 @@ proc skip(L: var TLexer, tok: var TToken) =
break # EndOfFile also leaves the loop break # EndOfFile also leaves the loop
L.bufpos = pos L.bufpos = pos
proc rawGetTok(L: var TLexer, tok: var TToken) = proc rawGetTok*(L: var TLexer, tok: var TToken) =
fillToken(tok) fillToken(tok)
if L.indentAhead >= 0: if L.indentAhead >= 0:
tok.indent = L.indentAhead tok.indent = L.indentAhead

View file

@ -382,11 +382,11 @@ proc getRoot*(n: PNode): PSym =
if getMagic(n) == mSlice: result = getRoot(n.sons[1]) if getMagic(n) == mSlice: result = getRoot(n.sons[1])
else: discard else: discard
proc newIntLit(value: BiggestInt): PNode = proc newIntLit*(value: BiggestInt): PNode =
result = nkIntLit.newIntNode(value) result = nkIntLit.newIntNode(value)
result.typ = getSysType(tyInt) result.typ = getSysType(tyInt)
proc genHigh(n: PNode): PNode = proc genHigh*(n: PNode): PNode =
if skipTypes(n.typ, abstractVar).kind in {tyArrayConstr, tyArray}: if skipTypes(n.typ, abstractVar).kind in {tyArrayConstr, tyArray}:
result = newIntLit(lastOrd(skipTypes(n.typ, abstractVar))) result = newIntLit(lastOrd(skipTypes(n.typ, abstractVar)))
else: else:

View file

@ -54,6 +54,7 @@ proc commandDoc2 =
finishDoc2Pass(gProjectName) finishDoc2Pass(gProjectName)
proc commandCompileToC = proc commandCompileToC =
extccomp.initVars()
semanticPasses() semanticPasses()
registerPass(cgenPass) registerPass(cgenPass)
rodPass() rodPass()

View file

@ -387,7 +387,7 @@ const
warnProveField: "cannot prove that field '$1' is accessible [ProveField]", warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]", warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]", warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.", warnGcUnsafe2: "$1",
warnUninit: "'$1' might not have been initialized [Uninit]", warnUninit: "'$1' might not have been initialized [Uninit]",
warnGcMem: "'$1' uses GC'ed memory [GcMem]", warnGcMem: "'$1' uses GC'ed memory [GcMem]",
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]", warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
@ -449,10 +449,10 @@ type
fullPath: string # This is a canonical full filesystem path fullPath: string # This is a canonical full filesystem path
projPath*: string # This is relative to the project's root projPath*: string # This is relative to the project's root
shortName*: string # short name of the module shortName*: string # short name of the module
quotedName*: PRope # cached quoted short name for codegen quotedName*: Rope # cached quoted short name for codegen
# purposes # purposes
lines*: seq[PRope] # the source code of the module lines*: seq[Rope] # the source code of the module
# used for better error messages and # used for better error messages and
# embedding the original source in the # embedding the original source in the
# generated code # generated code
@ -493,24 +493,20 @@ proc toCChar*(c: char): string =
of '\'', '\"', '\\': result = '\\' & c of '\'', '\"', '\\': result = '\\' & c
else: result = $(c) else: result = $(c)
proc makeCString*(s: string): PRope = proc makeCString*(s: string): Rope =
# BUGFIX: We have to split long strings into many ropes. Otherwise
# this could trigger an internalError(). See the ropes module for
# further information.
const const
MaxLineLength = 64 MaxLineLength = 64
result = nil result = nil
var res = "\"" var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
add(res, "\"")
for i in countup(0, len(s) - 1): for i in countup(0, len(s) - 1):
if (i + 1) mod MaxLineLength == 0: if (i + 1) mod MaxLineLength == 0:
add(res, '\"') add(res, '\"')
add(res, tnl) add(res, tnl)
app(result, toRope(res)) # reset: add(res, '\"')
setLen(res, 1)
res[0] = '\"'
add(res, toCChar(s[i])) add(res, toCChar(s[i]))
add(res, '\"') add(res, '\"')
app(result, toRope(res)) add(result, rope(res))
proc newFileInfo(fullPath, projPath: string): TFileInfo = proc newFileInfo(fullPath, projPath: string): TFileInfo =
@ -568,7 +564,7 @@ var gCodegenLineInfo* = newLineInfo(int32(1), 1, 1)
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} = proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
raise newException(ERecoverableError, msg) raise newException(ERecoverableError, msg)
proc sourceLine*(i: TLineInfo): PRope proc sourceLine*(i: TLineInfo): Rope
var var
gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} - gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
@ -776,7 +772,7 @@ proc rawMessage*(msg: TMsgKind, arg: string) =
proc writeSurroundingSrc(info: TLineInfo) = proc writeSurroundingSrc(info: TLineInfo) =
const indent = " " const indent = " "
msgWriteln(indent & info.sourceLine.ropeToStr) msgWriteln(indent & $info.sourceLine)
msgWriteln(indent & spaces(info.col) & '^') msgWriteln(indent & spaces(info.col) & '^')
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string = proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
@ -852,9 +848,9 @@ template internalAssert*(e: bool): stmt =
if not e: internalError($instantiationInfo()) if not e: internalError($instantiationInfo())
proc addSourceLine*(fileIdx: int32, line: string) = proc addSourceLine*(fileIdx: int32, line: string) =
fileInfos[fileIdx].lines.add line.toRope fileInfos[fileIdx].lines.add line.rope
proc sourceLine*(i: TLineInfo): PRope = proc sourceLine*(i: TLineInfo): Rope =
if i.fileIndex < 0: return nil if i.fileIndex < 0: return nil
if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0: if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
@ -869,16 +865,14 @@ proc sourceLine*(i: TLineInfo): PRope =
result = fileInfos[i.fileIndex].lines[i.line-1] result = fileInfos[i.fileIndex].lines[i.line-1]
proc quotedFilename*(i: TLineInfo): PRope = proc quotedFilename*(i: TLineInfo): Rope =
internalAssert i.fileIndex >= 0 internalAssert i.fileIndex >= 0
result = fileInfos[i.fileIndex].quotedName result = fileInfos[i.fileIndex].quotedName
ropes.errorHandler = proc (err: TRopesError, msg: string, useWarning: bool) = ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
case err case err
of rInvalidFormatStr: of rInvalidFormatStr:
internalError("ropes: invalid format string: " & msg) internalError("ropes: invalid format string: " & msg)
of rTokenTooLong:
internalError("ropes: token too long: " & msg)
of rCannotOpenFile: of rCannotOpenFile:
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg) rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)

View file

@ -215,24 +215,25 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1) if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1)
template considerAsgn(value: expr) = template considerAsgn(value: expr) =
result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value) result = if tok.ident.s[L-1] == '=': 1 else: value
case relevantChar case relevantChar
of '$', '^': considerAsgn(10) of '$', '^': considerAsgn(10)
of '*', '%', '/', '\\': considerAsgn(9) of '*', '%', '/', '\\': considerAsgn(9)
of '~': result = considerStrongSpaces(8) of '~': result = 8
of '+', '-', '|': considerAsgn(8) of '+', '-', '|': considerAsgn(8)
of '&': considerAsgn(7) of '&': considerAsgn(7)
of '=', '<', '>', '!': result = considerStrongSpaces(5) of '=', '<', '>', '!': result = 5
of '.': considerAsgn(6) of '.': considerAsgn(6)
of '?': result = considerStrongSpaces(2) of '?': result = 2
else: considerAsgn(2) else: considerAsgn(2)
of tkDiv, tkMod, tkShl, tkShr: result = 9 of tkDiv, tkMod, tkShl, tkShr: result = 9
of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5 of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
of tkDotDot: result = considerStrongSpaces(6) of tkDotDot: result = 6
of tkAnd: result = 4 of tkAnd: result = 4
of tkOr, tkXor, tkPtr, tkRef: result = 3 of tkOr, tkXor, tkPtr, tkRef: result = 3
else: result = -10 else: return -10
result = considerStrongSpaces(result)
proc isOperator(tok: TToken): bool = proc isOperator(tok: TToken): bool =
## Determines if the given token is an operator type token. ## Determines if the given token is an operator type token.
@ -2030,8 +2031,8 @@ proc parseString*(s: string; filename: string = ""; line: int = 0;
var parser: TParser var parser: TParser
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
# spaces... # spaces...
openParser(parser, filename, stream, false)
parser.lex.errorHandler = errorHandler parser.lex.errorHandler = errorHandler
openParser(parser, filename, stream, false)
result = parser.parseAll result = parser.parseAll
closeParser(parser) closeParser(parser)

View file

@ -89,7 +89,7 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
invalidPragma(it) invalidPragma(it)
proc setExternName(s: PSym, extname: string) = proc setExternName(s: PSym, extname: string) =
s.loc.r = toRope(extname % s.name.s) s.loc.r = rope(extname % s.name.s)
if gCmd == cmdPretty and '$' notin extname: if gCmd == cmdPretty and '$' notin extname:
# note that '{.importc.}' is transformed into '{.importc: "$1".}' # note that '{.importc.}' is transformed into '{.importc: "$1".}'
s.loc.flags.incl(lfFullExternalName) s.loc.flags.incl(lfFullExternalName)
@ -105,7 +105,7 @@ proc validateExternCName(s: PSym, info: TLineInfo) =
## Valid identifiers are those alphanumeric including the underscore not ## Valid identifiers are those alphanumeric including the underscore not
## starting with a number. If the check fails, a generic error will be ## starting with a number. If the check fails, a generic error will be
## displayed to the user. ## displayed to the user.
let target = ropeToStr(s.loc.r) let target = $s.loc.r
if target.len < 1 or target[0] notin IdentStartChars or if target.len < 1 or target[0] notin IdentStartChars or
not target.allCharsInSet(IdentChars): not target.allCharsInSet(IdentChars):
localError(info, errGenerated, "invalid exported symbol") localError(info, errGenerated, "invalid exported symbol")
@ -677,7 +677,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
incl(sym.loc.flags, lfHeader) incl(sym.loc.flags, lfHeader)
incl(sym.loc.flags, lfNoDecl) incl(sym.loc.flags, lfNoDecl)
# implies nodecl, because otherwise header would not make sense # implies nodecl, because otherwise header would not make sense
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s) if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
of wDestructor: of wDestructor:
sym.flags.incl sfOverriden sym.flags.incl sfOverriden
if sym.name.s.normalize != "destroy": if sym.name.s.normalize != "destroy":
@ -865,9 +865,11 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
while it != nil: while it != nil:
let o = it.otherPragmas let o = it.otherPragmas
if not o.isNil: if not o.isNil:
pushInfoContext(n.info)
for i in countup(0, sonsLen(o) - 1): for i in countup(0, sonsLen(o) - 1):
if singlePragma(c, sym, o, i, validPragmas): if singlePragma(c, sym, o, i, validPragmas):
internalError(n.info, "implicitPragmas") internalError(n.info, "implicitPragmas")
popInfoContext()
it = it.next.POptionEntry it = it.next.POptionEntry
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags: if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
@ -877,7 +879,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
sfImportc in sym.flags and lib != nil: sfImportc in sym.flags and lib != nil:
incl(sym.loc.flags, lfDynamicLib) incl(sym.loc.flags, lfDynamicLib)
addToLib(lib, sym) addToLib(lib, sym)
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s) if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool = proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
if n == nil or n.sons == nil: if n == nil or n.sons == nil:

View file

@ -277,7 +277,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
loc.t = nil loc.t = nil
if r.s[r.pos] == '!': if r.s[r.pos] == '!':
inc(r.pos) inc(r.pos)
loc.r = toRope(decodeStr(r.s, r.pos)) loc.r = rope(decodeStr(r.s, r.pos))
else: else:
loc.r = nil loc.r = nil
if r.s[r.pos] == '>': inc(r.pos) if r.s[r.pos] == '>': inc(r.pos)
@ -344,7 +344,7 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
result.kind = TLibKind(decodeVInt(r.s, r.pos)) result.kind = TLibKind(decodeVInt(r.s, r.pos))
if r.s[r.pos] != '|': internalError("decodeLib: 1") if r.s[r.pos] != '|': internalError("decodeLib: 1")
inc(r.pos) inc(r.pos)
result.name = toRope(decodeStr(r.s, r.pos)) result.name = rope(decodeStr(r.s, r.pos))
if r.s[r.pos] != '|': internalError("decodeLib: 2") if r.s[r.pos] != '|': internalError("decodeLib: 2")
inc(r.pos) inc(r.pos)
result.path = decodeNode(r, info) result.path = decodeNode(r, info)

View file

@ -186,7 +186,7 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
pushType(w, loc.t) pushType(w, loc.t)
if loc.r != nil: if loc.r != nil:
add(result, '!') add(result, '!')
encodeStr(ropeToStr(loc.r), result) encodeStr($loc.r, result)
if oldLen + 1 == result.len: if oldLen + 1 == result.len:
# no data was necessary, so remove the '<' again: # no data was necessary, so remove the '<' again:
setLen(result, oldLen) setLen(result, oldLen)
@ -241,7 +241,7 @@ proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
add(result, '|') add(result, '|')
encodeVInt(ord(lib.kind), result) encodeVInt(ord(lib.kind), result)
add(result, '|') add(result, '|')
encodeStr(ropeToStr(lib.name), result) encodeStr($lib.name, result)
add(result, '|') add(result, '|')
encodeNode(w, info, lib.path, result) encodeNode(w, info, lib.path, result)

View file

@ -56,77 +56,59 @@
# To cache them they are inserted in a `cache` array. # To cache them they are inserted in a `cache` array.
import import
strutils, platform, hashes, crc, options platform, hashes
type type
TFormatStr* = string # later we may change it to CString for better FormatStr* = string # later we may change it to CString for better
# performance of the code generator (assignments # performance of the code generator (assignments
# copy the format strings # copy the format strings
# though it is not necessary) # though it is not necessary)
PRope* = ref TRope Rope* = ref RopeObj
TRope*{.acyclic.} = object of RootObj # the empty rope is represented RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
# by nil to safe space # by nil to safe space
left*, right*: PRope left*, right*: Rope
length*: int length*: int
data*: string # != nil if a leaf data*: string # != nil if a leaf
TRopeSeq* = seq[PRope] RopeSeq* = seq[Rope]
TRopesError* = enum RopesError* = enum
rCannotOpenFile rCannotOpenFile
rInvalidFormatStr rInvalidFormatStr
rTokenTooLong
proc con*(a, b: PRope): PRope
proc con*(a: PRope, b: string): PRope
proc con*(a: string, b: PRope): PRope
proc con*(a: varargs[PRope]): PRope
proc app*(a: var PRope, b: PRope)
proc app*(a: var PRope, b: string)
proc prepend*(a: var PRope, b: PRope)
proc toRope*(s: string): PRope
proc toRope*(i: BiggestInt): PRope
proc ropeLen*(a: PRope): int
proc writeRopeIfNotEqual*(r: PRope, filename: string): bool
proc ropeToStr*(p: PRope): string
proc ropef*(frmt: TFormatStr, args: varargs[PRope]): PRope
proc appf*(c: var PRope, frmt: TFormatStr, args: varargs[PRope])
proc ropeEqualsFile*(r: PRope, f: string): bool
# returns true if the rope r is the same as the contents of file f
proc ropeInvariant*(r: PRope): bool
# exported for debugging
# implementation # implementation
var errorHandler*: proc(err: TRopesError, msg: string, useWarning = false) var errorHandler*: proc(err: RopesError, msg: string, useWarning = false)
# avoid dependency on msgs.nim # avoid dependency on msgs.nim
proc ropeLen(a: PRope): int = proc len*(a: Rope): int =
## the rope's length
if a == nil: result = 0 if a == nil: result = 0
else: result = a.length else: result = a.length
proc newRope*(data: string = nil): PRope = proc newRope(data: string = nil): Rope =
new(result) new(result)
if data != nil: if data != nil:
result.length = len(data) result.length = len(data)
result.data = data result.data = data
proc newMutableRope*(capacity = 30): PRope = proc newMutableRope*(capacity = 30): Rope =
## creates a new rope that supports direct modifications of the rope's ## creates a new rope that supports direct modifications of the rope's
## 'data' and 'length' fields. ## 'data' and 'length' fields.
new(result) new(result)
result.data = newStringOfCap(capacity) result.data = newStringOfCap(capacity)
proc freezeMutableRope*(r: PRope) {.inline.} = proc freezeMutableRope*(r: Rope) {.inline.} =
r.length = r.data.len r.length = r.data.len
var var
cache: array[0..2048*2 - 1, PRope] cache: array[0..2048*2 - 1, Rope]
proc resetRopeCache* = proc resetRopeCache* =
for i in low(cache)..high(cache): for i in low(cache)..high(cache):
cache[i] = nil cache[i] = nil
proc ropeInvariant(r: PRope): bool = proc ropeInvariant(r: Rope): bool =
if r == nil: if r == nil:
result = true result = true
else: else:
@ -143,7 +125,7 @@ var gCacheTries* = 0
var gCacheMisses* = 0 var gCacheMisses* = 0
var gCacheIntTries* = 0 var gCacheIntTries* = 0
proc insertInCache(s: string): PRope = proc insertInCache(s: string): Rope =
inc gCacheTries inc gCacheTries
var h = hash(s) and high(cache) var h = hash(s) and high(cache)
result = cache[h] result = cache[h]
@ -152,82 +134,77 @@ proc insertInCache(s: string): PRope =
result = newRope(s) result = newRope(s)
cache[h] = result cache[h] = result
proc toRope(s: string): PRope = proc rope*(s: string): Rope =
## Converts a string to a rope.
if s.len == 0: if s.len == 0:
result = nil result = nil
else: else:
result = insertInCache(s) result = insertInCache(s)
assert(ropeInvariant(result)) assert(ropeInvariant(result))
proc ropeSeqInsert(rs: var TRopeSeq, r: PRope, at: Natural) = proc rope*(i: BiggestInt): Rope =
var length = len(rs) ## Converts an int to a rope.
if at > length: inc gCacheIntTries
setLen(rs, at + 1) result = rope($i)
else:
setLen(rs, length + 1) # move old rope elements:
for i in countdown(length, at + 1):
rs[i] = rs[i - 1] # this is correct, I used pen and paper to validate it
rs[at] = r
proc newRecRopeToStr(result: var string, resultLen: var int, r: PRope) = proc rope*(f: BiggestFloat): Rope =
var stack = @[r] ## Converts a float to a rope.
while len(stack) > 0: result = rope($f)
var it = pop(stack)
while it.data == nil:
add(stack, it.right)
it = it.left
assert(it.data != nil)
copyMem(addr(result[resultLen]), addr(it.data[0]), it.length)
inc(resultLen, it.length)
assert(resultLen <= len(result))
proc ropeToStr(p: PRope): string = proc `&`*(a, b: Rope): Rope =
if p == nil: if a == nil:
result = "" result = b
else: elif b == nil:
result = newString(p.length) result = a
var resultLen = 0
newRecRopeToStr(result, resultLen, p)
proc con(a, b: PRope): PRope =
if a == nil: result = b
elif b == nil: result = a
else: else:
result = newRope() result = newRope()
result.length = a.length + b.length result.length = a.length + b.length
result.left = a result.left = a
result.right = b result.right = b
proc con(a: PRope, b: string): PRope = result = con(a, toRope(b)) proc `&`*(a: Rope, b: string): Rope =
proc con(a: string, b: PRope): PRope = result = con(toRope(a), b) ## the concatenation operator for ropes.
result = a & rope(b)
proc con(a: varargs[PRope]): PRope = proc `&`*(a: string, b: Rope): Rope =
for i in countup(0, high(a)): result = con(result, a[i]) ## the concatenation operator for ropes.
result = rope(a) & b
proc ropeConcat*(a: varargs[PRope]): PRope = proc `&`*(a: openArray[Rope]): Rope =
# not overloaded version of concat to speed-up `rfmt` a little bit ## the concatenation operator for an openarray of ropes.
for i in countup(0, high(a)): result = con(result, a[i]) for i in countup(0, high(a)): result = result & a[i]
proc toRope(i: BiggestInt): PRope = proc add*(a: var Rope, b: Rope) =
inc gCacheIntTries ## adds `b` to the rope `a`.
result = toRope($i) a = a & b
proc app(a: var PRope, b: PRope) = a = con(a, b) proc add*(a: var Rope, b: string) =
proc app(a: var PRope, b: string) = a = con(a, b) ## adds `b` to the rope `a`.
proc prepend(a: var PRope, b: PRope) = a = con(b, a) a = a & b
proc writeRope*(f: File, c: PRope) = iterator leaves*(r: Rope): string =
var stack = @[c] ## iterates over any leaf string in the rope `r`.
while len(stack) > 0: if r != nil:
var it = pop(stack) var stack = @[r]
while it.data == nil: while stack.len > 0:
add(stack, it.right) var it = stack.pop
it = it.left while isNil(it.data):
assert(it != nil) stack.add(it.right)
assert(it.data != nil) it = it.left
write(f, it.data) assert(it != nil)
assert(it.data != nil)
yield it.data
proc writeRope*(head: PRope, filename: string, useWarning = false) = iterator items*(r: Rope): char =
## iterates over any character in the rope `r`.
for s in leaves(r):
for c in items(s): yield c
proc writeRope*(f: File, r: Rope) =
## writes a rope to a file.
for s in leaves(r): write(f, s)
proc writeRope*(head: Rope, filename: string, useWarning = false) =
var f: File var f: File
if open(f, filename, fmWrite): if open(f, filename, fmWrite):
if head != nil: writeRope(f, head) if head != nil: writeRope(f, head)
@ -235,42 +212,69 @@ proc writeRope*(head: PRope, filename: string, useWarning = false) =
else: else:
errorHandler(rCannotOpenFile, filename, useWarning) errorHandler(rCannotOpenFile, filename, useWarning)
proc `$`*(r: Rope): string =
## converts a rope back to a string.
result = newString(r.len)
setLen(result, 0)
for s in leaves(r): add(result, s)
proc ropeConcat*(a: varargs[Rope]): Rope =
# not overloaded version of concat to speed-up `rfmt` a little bit
for i in countup(0, high(a)): result = result & a[i]
proc prepend*(a: var Rope, b: Rope) = a = b & a
proc prepend*(a: var Rope, b: string) = a = b & a
var var
rnl* = tnl.newRope rnl* = tnl.newRope
softRnl* = tnl.newRope softRnl* = tnl.newRope
proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope = proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
var i = 0 var i = 0
var length = len(frmt) var length = len(frmt)
result = nil result = nil
var num = 0 var num = 0
while i <= length - 1: while i < length:
if frmt[i] == '$': if frmt[i] == '$':
inc(i) # skip '$' inc(i) # skip '$'
case frmt[i] case frmt[i]
of '$': of '$':
app(result, "$") add(result, "$")
inc(i) inc(i)
of '#': of '#':
inc(i) inc(i)
app(result, args[num]) add(result, args[num])
inc(num) inc(num)
of '0'..'9': of '0'..'9':
var j = 0 var j = 0
while true: while true:
j = (j * 10) + ord(frmt[i]) - ord('0') j = j * 10 + ord(frmt[i]) - ord('0')
inc(i) inc(i)
if (i > length + 0 - 1) or not (frmt[i] in {'0'..'9'}): break if frmt[i] notin {'0'..'9'}: break
num = j num = j
if j > high(args) + 1: if j > high(args) + 1:
errorHandler(rInvalidFormatStr, $(j)) errorHandler(rInvalidFormatStr, $(j))
else: else:
app(result, args[j - 1]) add(result, args[j-1])
of '{':
inc(i)
var j = 0
while frmt[i] in {'0'..'9'}:
j = j * 10 + ord(frmt[i]) - ord('0')
inc(i)
num = j
if frmt[i] == '}': inc(i)
else: errorHandler(rInvalidFormatStr, $(frmt[i]))
if j > high(args) + 1:
errorHandler(rInvalidFormatStr, $(j))
else:
add(result, args[j-1])
of 'n': of 'n':
app(result, softRnl) add(result, softRnl)
inc i inc(i)
of 'N': of 'N':
app(result, rnl) add(result, rnl)
inc(i) inc(i)
else: else:
errorHandler(rInvalidFormatStr, $(frmt[i])) errorHandler(rInvalidFormatStr, $(frmt[i]))
@ -279,83 +283,67 @@ proc ropef(frmt: TFormatStr, args: varargs[PRope]): PRope =
if frmt[i] != '$': inc(i) if frmt[i] != '$': inc(i)
else: break else: break
if i - 1 >= start: if i - 1 >= start:
app(result, substr(frmt, start, i - 1)) add(result, substr(frmt, start, i - 1))
assert(ropeInvariant(result)) assert(ropeInvariant(result))
proc addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
## shortcut for ``add(c, frmt % args)``.
add(c, frmt % args)
when true: when true:
template `~`*(r: string): PRope = r.ropef template `~`*(r: string): Rope = r % []
else: else:
{.push stack_trace: off, line_trace: off.} {.push stack_trace: off, line_trace: off.}
proc `~`*(r: static[string]): PRope = proc `~`*(r: static[string]): Rope =
# this is the new optimized "to rope" operator # this is the new optimized "to rope" operator
# the mnemonic is that `~` looks a bit like a rope :) # the mnemonic is that `~` looks a bit like a rope :)
var r {.global.} = r.ropef var r {.global.} = r % []
return r return r
{.pop.} {.pop.}
proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
app(c, ropef(frmt, args))
const const
bufSize = 1024 # 1 KB is reasonable bufSize = 1024 # 1 KB is reasonable
proc auxRopeEqualsFile(r: PRope, bin: var File, buf: pointer): bool = proc equalsFile*(r: Rope, f: File): bool =
if r.data != nil: ## returns true if the contents of the file `f` equal `r`.
if r.length > bufSize: var
errorHandler(rTokenTooLong, r.data) buf: array[bufSize, char]
return bpos = buf.len
var readBytes = readBuffer(bin, buf, r.length) blen = buf.len
result = readBytes == r.length and
equalMem(buf, addr(r.data[0]), r.length) # BUGFIX
else:
result = auxRopeEqualsFile(r.left, bin, buf)
if result: result = auxRopeEqualsFile(r.right, bin, buf)
proc ropeEqualsFile(r: PRope, f: string): bool = for s in leaves(r):
var bin: File var spos = 0
result = open(bin, f) let slen = s.len
if not result: while spos < slen:
return # not equal if file does not exist if bpos == blen:
var buf = alloc(bufSize) # Read more data
result = auxRopeEqualsFile(r, bin, buf) bpos = 0
blen = readBuffer(f, addr(buf[0]), buf.len)
if blen == 0: # no more data in file
result = false
return
let n = min(blen - bpos, slen - spos)
# TODO There's gotta be a better way of comparing here...
if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n):
result = false
return
spos += n
bpos += n
result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all
proc equalsFile*(r: Rope, filename: string): bool =
## returns true if the contents of the file `f` equal `r`. If `f` does not
## exist, false is returned.
var f: File
result = open(f, filename)
if result: if result:
result = readBuffer(bin, buf, bufSize) == 0 # really at the end of file? result = equalsFile(r, f)
dealloc(buf) close(f)
close(bin)
proc crcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 = proc writeRopeIfNotEqual*(r: Rope, filename: string): bool =
if r.data != nil:
result = startVal
for i in countup(0, len(r.data) - 1):
result = updateCrc32(r.data[i], result)
else:
result = crcFromRopeAux(r.left, startVal)
result = crcFromRopeAux(r.right, result)
proc newCrcFromRopeAux(r: PRope, startVal: TCrc32): TCrc32 =
# XXX profiling shows this is actually expensive
var stack: TRopeSeq = @[r]
result = startVal
while len(stack) > 0:
var it = pop(stack)
while it.data == nil:
add(stack, it.right)
it = it.left
assert(it.data != nil)
var i = 0
var L = len(it.data)
while i < L:
result = updateCrc32(it.data[i], result)
inc(i)
proc crcFromRope(r: PRope): TCrc32 =
result = newCrcFromRopeAux(r, InitCrc32)
proc writeRopeIfNotEqual(r: PRope, filename: string): bool =
# returns true if overwritten # returns true if overwritten
var c: TCrc32 if not equalsFile(r, filename):
c = crcFromFile(filename)
if c != crcFromRope(r):
writeRope(r, filename) writeRope(r, filename)
result = true result = true
else: else:

View file

@ -398,7 +398,7 @@ proc myOpen(module: PSym): PPassContext =
c.semInferredLambda = semInferredLambda c.semInferredLambda = semInferredLambda
c.semGenerateInstance = generateInstance c.semGenerateInstance = generateInstance
c.semTypeNode = semTypeNode c.semTypeNode = semTypeNode
c.instDeepCopy = sigmatch.instDeepCopy c.instTypeBoundOp = sigmatch.instTypeBoundOp
pushProcCon(c, module) pushProcCon(c, module)
pushOwner(c.module) pushOwner(c.module)

View file

@ -7,111 +7,84 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## This module implements lifting for assignments and ``deepCopy``. ## This module implements lifting for assignments. Later versions of this code
## will be able to also lift ``=deepCopy`` and ``=destroy``.
# included from sem.nim # included from sem.nim
type type
TTypeAttachedOp = enum
attachedDestructor,
attachedAsgn,
attachedDeepCopy
TLiftCtx = object TLiftCtx = object
c: PContext c: PContext
info: TLineInfo # for construction info: TLineInfo # for construction
result: PNode
kind: TTypeAttachedOp kind: TTypeAttachedOp
fn: PSym
asgnForType: PType
recurse: bool
type proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode)
TFieldInstCtx = object # either 'tup[i]' or 'field' is valid proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym
tupleType: PType # if != nil we're traversing a tuple
tupleIndex: int
field: PSym
replaceByFieldName: bool
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = proc at(a, i: PNode, elemType: PType): PNode =
result = newNodeI(nkBracketExpr, a.info, 2)
result.sons[0] = a
result.sons[1] = i
result.typ = elemType
proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
for i in 0 .. <t.len:
let lit = lowerings.newIntLit(i)
liftBodyAux(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i]))
proc dotField(x: PNode, f: PSym): PNode =
result = newNodeI(nkDotExpr, x.info, 2)
result.sons[0] = x
result.sons[1] = newSymNode(f, x.info)
result.typ = f.typ
proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
case n.kind case n.kind
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
of nkIdent:
result = n
var L = sonsLen(forLoop)
if c.replaceByFieldName:
if n.ident.id == forLoop[0].ident.id:
let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
result = newStrNode(nkStrLit, fieldName)
return
# other fields:
for i in ord(c.replaceByFieldName)..L-3:
if n.ident.id == forLoop[i].ident.id:
var call = forLoop.sons[L-2]
var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
if c.field.isNil:
result = newNodeI(nkBracketExpr, n.info)
result.add(tupl)
result.add(newIntNode(nkIntLit, c.tupleIndex))
else:
result = newNodeI(nkDotExpr, n.info)
result.add(tupl)
result.add(newSymNode(c.field, n.info))
break
else:
if n.kind == nkContinueStmt:
localError(n.info, errGenerated,
"'continue' not supported in a 'fields' loop")
result = copyNode(n)
newSons(result, sonsLen(n))
for i in countup(0, sonsLen(n)-1):
result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
proc liftBodyObj(c: TLiftCtx; typ, x, y: PNode) =
case typ.kind
of nkSym: of nkSym:
var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid let f = n.sym
fc.field = typ.sym liftBodyAux(c, f.typ, body, x.dotField(f), y.dotField(f))
fc.replaceByFieldName = c.m == mFieldPairs
openScope(c.c)
inc c.c.inUnrolledContext
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
father.add(semStmt(c.c, body))
dec c.c.inUnrolledContext
closeScope(c.c)
of nkNilLit: discard of nkNilLit: discard
of nkRecCase: of nkRecCase:
let L = forLoop.len # copy the selector:
let call = forLoop.sons[L-2] liftBodyObj(c, n[0], body, x, y)
if call.len > 2:
localError(forLoop.info, errGenerated,
"parallel 'fields' iterator does not work for 'case' objects")
return
# iterate over the selector:
asgnForObjectFields(c, typ[0], forLoop, father)
# we need to generate a case statement: # we need to generate a case statement:
var caseStmt = newNodeI(nkCaseStmt, c.info) var caseStmt = newNodeI(nkCaseStmt, c.info)
# XXX generate 'if' that checks same branches
# generate selector: # generate selector:
var access = newNodeI(nkDotExpr, forLoop.info, 2) var access = dotField(x, n[0].sym)
access.sons[0] = call.sons[1] caseStmt.add(access)
access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
caseStmt.add(semExprWithType(c.c, access))
# copy the branches over, but replace the fields with the for loop body: # copy the branches over, but replace the fields with the for loop body:
for i in 1 .. <typ.len: for i in 1 .. <n.len:
var branch = copyTree(typ[i]) var branch = copyTree(n[i])
let L = branch.len let L = branch.len
branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info) branch.sons[L-1] = newNodeI(nkStmtList, c.info)
semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
caseStmt.add(branch)
father.add(caseStmt)
of nkRecList:
for t in items(typ): liftBodyObj(c, t, x, y)
else:
illFormedAstLocal(typ)
proc newAsgnCall(op: PSym; x, y: PNode): PNode = liftBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y)
caseStmt.add(branch)
body.add(caseStmt)
localError(c.info, "cannot lift assignment operator to 'case' object")
of nkRecList:
for t in items(n): liftBodyObj(c, t, body, x, y)
else:
illFormedAstLocal(n)
proc genAddr(c: PContext; x: PNode): PNode =
if x.kind == nkHiddenDeref:
checkSonsLen(x, 1)
result = x.sons[0]
else:
result = newNodeIT(nkHiddenAddr, x.info, makeVarType(c, x.typ))
addSon(result, x)
proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode =
if sfError in op.flags:
localError(x.info, errWrongSymbolX, op.name.s)
result = newNodeI(nkCall, x.info) result = newNodeI(nkCall, x.info)
result.add(newSymNode(op)) result.add newSymNode(op)
result.add x result.add genAddr(c, x)
result.add y result.add y
proc newAsgnStmt(le, ri: PNode): PNode = proc newAsgnStmt(le, ri: PNode): PNode =
@ -127,63 +100,124 @@ proc newDestructorCall(op: PSym; x: PNode): PNode =
proc newDeepCopyCall(op: PSym; x, y: PNode): PNode = proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newDestructorCall(op, y)) result = newAsgnStmt(x, newDestructorCall(op, y))
proc considerOverloadedOp(c: TLiftCtx; t: PType; x, y: PNode): bool = proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
let op = t.attachedOps[c.kind] case c.kind
if op != nil: of attachedDestructor:
markUsed(c.info, op) let op = t.destructor
styleCheckUse(c.info, op) if op != nil:
case c.kind markUsed(c.info, op)
of attachedDestructor: styleCheckUse(c.info, op)
c.result.add newDestructorCall(op, x) body.add newDestructorCall(op, x)
of attachedAsgn: result = true
c.result.add newAsgnCall(op, x, y) of attachedAsgn:
of attachedDeepCopy: if tfHasAsgn in t.flags:
c.result.add newDeepCopyCall(op, x, y) var op: PSym
result = true if sameType(t, c.asgnForType):
# generate recursive call:
if c.recurse:
op = c.fn
else:
c.recurse = true
return false
else:
op = t.assignment
if op == nil:
op = liftBody(c.c, t, c.info)
markUsed(c.info, op)
styleCheckUse(c.info, op)
body.add newAsgnCall(c.c, op, x, y)
result = true
of attachedDeepCopy:
let op = t.deepCopy
if op != nil:
markUsed(c.info, op)
styleCheckUse(c.info, op)
body.add newDeepCopyCall(op, x, y)
result = true
proc defaultOp(c: TLiftCtx; t: PType; x, y: PNode) = proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.kind != attachedDestructor: if c.kind != attachedDestructor:
c.result.add newAsgnStmt(x, y) body.add newAsgnStmt(x, y)
proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) = proc addVar(father, v, value: PNode) =
const hasAttachedOp: array[TTypeAttachedOp, TTypeIter] = [ var vpart = newNodeI(nkIdentDefs, v.info, 3)
(proc (t: PType, closure: PObject): bool = vpart.sons[0] = v
t.attachedOp[attachedDestructor] != nil), vpart.sons[1] = ast.emptyNode
(proc (t: PType, closure: PObject): bool = vpart.sons[2] = value
t.attachedOp[attachedAsgn] != nil), addSon(father, vpart)
(proc (t: PType, closure: PObject): bool =
t.attachedOp[attachedDeepCopy] != nil)] proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(lowerings.genPrefix), c.fn, c.info)
temp.typ = getSysType(tyInt)
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info)
result = newSymNode(temp)
v.addVar(result, lowerings.newIntLit(first))
body.add v
proc genBuiltin(magic: TMagic; name: string; i: PNode): PNode =
result = newNodeI(nkCall, i.info)
result.add createMagic(name, magic).newSymNode
result.add i
proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
result = newNodeI(nkWhileStmt, c.info, 2)
let cmp = genBuiltin(mLeI, "<=", i)
cmp.add genHigh(dest)
cmp.typ = getSysType(tyBool)
result.sons[0] = cmp
result.sons[1] = newNodeI(nkStmtList, c.info)
proc addIncStmt(body, i: PNode) =
let incCall = genBuiltin(mInc, "inc", i)
incCall.add lowerings.newIntLit(1)
body.add incCall
proc newSeqCall(c: PContext; x, y: PNode): PNode =
# don't call genAddr(c, x) here:
result = genBuiltin(mNewSeq, "newSeq", x)
let lenCall = genBuiltin(mLengthSeq, "len", y)
lenCall.typ = getSysType(tyInt)
result.add lenCall
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind case t.kind
of tyNone, tyEmpty: discard of tyNone, tyEmpty: discard
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString: of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
defaultOp(c, t, x, y) tyPtr, tyString, tyRef:
of tyPtr, tyString: defaultOp(c, t, body, x, y)
if not considerOverloadedOp(c, t, x, y):
defaultOp(c, t, x, y)
of tyArrayConstr, tyArray, tySequence: of tyArrayConstr, tyArray, tySequence:
if iterOverType(lastSon(t), hasAttachedOp[c.kind], nil): if tfHasAsgn in t.flags:
# generate loop and call the attached Op: if t.kind == tySequence:
# XXX add 'nil' handling here
body.add newSeqCall(c.c, x, y)
let i = declareCounter(c, body, firstOrd(t))
let whileLoop = genWhileLoop(c, i, x)
let elemType = t.lastSon
liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
y.at(i, elemType))
addIncStmt(whileLoop.sons[1], i)
body.add whileLoop
else: else:
defaultOp(c, t, x, y) defaultOp(c, t, body, x, y)
of tyObject: of tyObject, tyDistinct:
liftBodyObj(c, t.n, x, y) if not considerOverloadedOp(c, t, body, x, y):
if t.sons[0] != nil: liftBodyAux(c, t.sons[0], body, x, y)
if t.kind == tyObject: liftBodyObj(c, t.n, body, x, y)
of tyTuple: of tyTuple:
liftBodyTup(c, t, x, y) liftBodyTup(c, t, body, x, y)
of tyRef:
# we MUST NOT check for acyclic here as a DAG might still share nodes:
of tyProc: of tyProc:
if t.callConv != ccClosure or c.kind != attachedDeepCopy: if t.callConv != ccClosure or c.kind != attachedDeepCopy:
defaultOp(c, t, x, y) defaultOp(c, t, body, x, y)
else: else:
# a big problem is that we don't know the enviroment's type here, so we # a big problem is that we don't know the enviroment's type here, so we
# have to go through some indirection; we delegate this to the codegen: # have to go through some indirection; we delegate this to the codegen:
call = newNodeI(nkCall, n.info, 2) let call = newNodeI(nkCall, c.info, 2)
call.typ = t call.typ = t
call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy)) call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
call.sons[1] = y call.sons[1] = y
c.result.add newAsgnStmt(x, call) body.add newAsgnStmt(x, call)
of tyVarargs, tyOpenArray: of tyVarargs, tyOpenArray:
localError(c.info, errGenerated, "cannot copy openArray") localError(c.info, errGenerated, "cannot copy openArray")
of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
@ -191,13 +225,60 @@ proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) =
tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt, tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
tyTypeDesc, tyGenericInvocation, tyBigNum, tyConst, tyForward: tyTypeDesc, tyGenericInvocation, tyBigNum, tyConst, tyForward:
internalError(c.info, "assignment requested for type: " & typeToString(t)) internalError(c.info, "assignment requested for type: " & typeToString(t))
of tyDistinct, tyOrdinal, tyRange, of tyOrdinal, tyRange,
tyGenericInst, tyFieldAccessor, tyStatic, tyVar: tyGenericInst, tyFieldAccessor, tyStatic, tyVar:
liftBodyAux(c, lastSon(t)) liftBodyAux(c, lastSon(t), body, x, y)
proc liftBody(c: PContext; typ: PType; info: TLineInfo): PNode = proc newProcType(info: TLineInfo; owner: PSym): PType =
result = newType(tyProc, owner)
result.n = newNodeI(nkFormalParams, info)
rawAddSon(result, nil) # return type
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because
# the effects are now stored in there too ... this is a bit hacky, but as
# usual we desperately try to save memory:
addSon(result.n, newNodeI(nkEffectList, info))
proc addParam(procType: PType; param: PSym) =
param.position = procType.len-1
addSon(procType.n, newSymNode(param))
rawAddSon(procType, param.typ)
proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
var a: TLiftCtx var a: TLiftCtx
a.info = info a.info = info
a.result = newNodeI(nkStmtList, info) let body = newNodeI(nkStmtList, info)
liftBodyAux(a, typ) result = newSym(skProc, getIdent":lifted=", typ.owner, info)
result = a.result a.fn = result
a.asgnForType = typ
let dest = newSym(skParam, getIdent"dest", result, info)
let src = newSym(skParam, getIdent"src", result, info)
dest.typ = makeVarType(c, typ)
src.typ = typ
result.typ = newProcType(info, typ.owner)
result.typ.addParam dest
result.typ.addParam src
liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src))
var n = newNodeI(nkProcDef, info, bodyPos+1)
for i in 0 .. < n.len: n.sons[i] = emptyNode
n.sons[namePos] = newSymNode(result)
n.sons[paramsPos] = result.typ.n
n.sons[bodyPos] = body
result.ast = n
# register late as recursion is handled differently
typ.assignment = result
#echo "Produced this ", n
proc getAsgnOrLiftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
let t = typ.skipTypes({tyGenericInst, tyVar})
result = t.assignment
if result.isNil:
result = liftBody(c, t, info)
proc overloadedAsgn(c: PContext; dest, src: PNode): PNode =
let a = getAsgnOrLiftBody(c, dest.typ, dest.info)
result = newAsgnCall(c, a, dest, src)

View file

@ -43,10 +43,16 @@ type
inst*: PInstantiation inst*: PInstantiation
TExprFlag* = enum TExprFlag* = enum
efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType, efLValue, efWantIterator, efInTypeof,
efWantStmt, efAllowStmt, efDetermineType,
efAllowDestructor, efWantValue, efOperand, efNoSemCheck efAllowDestructor, efWantValue, efOperand, efNoSemCheck
TExprFlags* = set[TExprFlag] TExprFlags* = set[TExprFlag]
TTypeAttachedOp* = enum
attachedAsgn,
attachedDeepCopy,
attachedDestructor
PContext* = ref TContext PContext* = ref TContext
TContext* = object of TPassContext # a context represents a module TContext* = object of TPassContext # a context represents a module
module*: PSym # the module sym belonging to the context module*: PSym # the module sym belonging to the context
@ -93,8 +99,8 @@ type
lastGenericIdx*: int # used for the generics stack lastGenericIdx*: int # used for the generics stack
hloLoopDetector*: int # used to prevent endless loops in the HLO hloLoopDetector*: int # used to prevent endless loops in the HLO
inParallelStmt*: int inParallelStmt*: int
instDeepCopy*: proc (c: PContext; dc: PSym; t: PType; instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
info: TLineInfo): PSym {.nimcall.} op: TTypeAttachedOp): PSym {.nimcall.}
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =

View file

@ -31,7 +31,7 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ != nil: if result.typ != nil:
# XXX tyGenericInst here? # XXX tyGenericInst here?
if result.typ.kind == tyVar: result = newDeref(result) if result.typ.kind == tyVar: result = newDeref(result)
elif efWantStmt in flags: elif {efWantStmt, efAllowStmt} * flags != {}:
result.typ = newTypeS(tyEmpty, c) result.typ = newTypeS(tyEmpty, c)
else: else:
localError(n.info, errExprXHasNoType, localError(n.info, errExprXHasNoType,
@ -1298,6 +1298,9 @@ proc semAsgn(c: PContext, n: PNode): PNode =
typeMismatch(n, lhs.typ, rhs.typ) typeMismatch(n, lhs.typ, rhs.typ)
n.sons[1] = fitNode(c, le, rhs) n.sons[1] = fitNode(c, le, rhs)
if tfHasAsgn in lhs.typ.flags and not lhsIsResult:
return overloadedAsgn(c, lhs, n.sons[1])
fixAbstractType(c, n) fixAbstractType(c, n)
asgnToResultVar(c, n, n.sons[0], n.sons[1]) asgnToResultVar(c, n, n.sons[0], n.sons[1])
result = n result = n

View file

@ -170,13 +170,19 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
let a = n.sons[1].typ let a = n.sons[1].typ
if isFloatRange(a): if isFloatRange(a):
# abs(-5.. 1) == (1..5) # abs(-5.. 1) == (1..5)
result = makeRangeF(a, abs(getFloat(a.n.sons[1])), if a.n[0].floatVal <= 0.0:
abs(getFloat(a.n.sons[0]))) result = makeRangeF(a, 0.0, abs(getFloat(a.n.sons[0])))
else:
result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
abs(getFloat(a.n.sons[0])))
of mAbsI, mAbsI64: of mAbsI, mAbsI64:
let a = n.sons[1].typ let a = n.sons[1].typ
if isIntRange(a): if isIntRange(a):
result = makeRange(a, `|abs|`(getInt(a.n.sons[1])), if a.n[0].intVal <= 0:
`|abs|`(getInt(a.n.sons[0]))) result = makeRange(a, 0, `|abs|`(getInt(a.n.sons[0])))
else:
result = makeRange(a, `|abs|`(getInt(a.n.sons[1])),
`|abs|`(getInt(a.n.sons[0])))
of mSucc: of mSucc:
let a = n.sons[1].typ let a = n.sons[1].typ
let b = n.sons[2].typ let b = n.sons[2].typ

View file

@ -194,8 +194,38 @@ proc warnAboutGcUnsafe(n: PNode) =
#assert false #assert false
message(n.info, warnGcUnsafe, renderTree(n)) message(n.info, warnGcUnsafe, renderTree(n))
template markGcUnsafe(a: PEffects) = proc markGcUnsafe(a: PEffects; reason: PSym) =
a.gcUnsafe = true a.gcUnsafe = true
if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
proc markGcUnsafe(a: PEffects; reason: PNode) =
a.gcUnsafe = true
if a.owner.kind in routineKinds:
if reason.kind == nkSym:
a.owner.gcUnsafetyReason = reason.sym
else:
a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
a.owner, reason.info)
proc listGcUnsafety(s: PSym; onlyWarning: bool) =
let u = s.gcUnsafetyReason
if u != nil:
let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
if u.kind in {skLet, skVar}:
message(s.info, msgKind,
("'$#' is not GC-safe as it accesses '$#'" &
" which is a global using GC'ed memory") % [s.name.s, u.name.s])
elif u.kind in routineKinds:
# recursive call *always* produces only a warning so the full error
# message is printed:
listGcUnsafety(u, true)
message(s.info, msgKind,
"'$#' is not GC-safe as it calls '$#'" %
[s.name.s, u.name.s])
else:
internalAssert u.kind == skUnknown
message(u.info, msgKind,
"'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
proc useVar(a: PEffects, n: PNode) = proc useVar(a: PEffects, n: PNode) =
let s = n.sym let s = n.sym
@ -210,8 +240,8 @@ proc useVar(a: PEffects, n: PNode) =
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}: if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
if s.guard != nil: guardGlobal(a, n, s.guard) if s.guard != nil: guardGlobal(a, n, s.guard)
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem): if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) #if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
markGcUnsafe(a) markGcUnsafe(a, s)
type type
TIntersection = seq[tuple[id, count: int]] # a simple count table TIntersection = seq[tuple[id, count: int]] # a simple count table
@ -450,7 +480,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
if notGcSafe(s.typ) and sfImportc notin s.flags: if notGcSafe(s.typ) and sfImportc notin s.flags:
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
markGcUnsafe(tracked) markGcUnsafe(tracked, s)
mergeLockLevels(tracked, n, s.getLockLevel) mergeLockLevels(tracked, n, s.getLockLevel)
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
@ -504,13 +534,13 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
# assume GcUnsafe unless in its type; 'forward' does not matter: # assume GcUnsafe unless in its type; 'forward' does not matter:
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner): if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
markGcUnsafe(tracked) markGcUnsafe(tracked, a)
else: else:
mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n)
if notGcSafe(op): if notGcSafe(op):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
markGcUnsafe(tracked) markGcUnsafe(tracked, a)
notNilCheck(tracked, n, paramType) notNilCheck(tracked, n, paramType)
proc breaksBlock(n: PNode): bool = proc breaksBlock(n: PNode): bool =
@ -658,7 +688,7 @@ proc track(tracked: PEffects, n: PNode) =
# and it's not a recursive call: # and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner): if not (a.kind == nkSym and a.sym == tracked.owner):
warnAboutGcUnsafe(n) warnAboutGcUnsafe(n)
markGcUnsafe(tracked) markGcUnsafe(tracked, a)
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i)) for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}: if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
# may not look like an assignment, but it is: # may not look like an assignment, but it is:
@ -853,9 +883,11 @@ proc trackProc*(s: PSym, body: PNode) =
if sfThread in s.flags and t.gcUnsafe: if sfThread in s.flags and t.gcUnsafe:
if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions: if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
localError(s.info, "'$1' is not GC-safe" % s.name.s) #localError(s.info, "'$1' is not GC-safe" % s.name.s)
listGcUnsafety(s, onlyWarning=false)
else: else:
localError(s.info, warnGcUnsafe2, s.name.s) listGcUnsafety(s, onlyWarning=true)
#localError(s.info, warnGcUnsafe2, s.name.s)
if not t.gcUnsafe: if not t.gcUnsafe:
s.typ.flags.incl tfGcSafe s.typ.flags.incl tfGcSafe
if s.typ.lockLevel == UnspecifiedLockLevel: if s.typ.lockLevel == UnspecifiedLockLevel:

View file

@ -340,6 +340,39 @@ proc checkNilable(v: PSym) =
elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags: elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
message(v.info, warnProveInit, v.name.s) message(v.info, warnProveInit, v.name.s)
include semasgn
proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
# consider this:
# var
# x = 0
# withOverloadedAssignment = foo()
# y = use(withOverloadedAssignment)
# We need to split this into a statement list with multiple 'var' sections
# in order for this transformation to be correct.
let L = identDefs.len
let value = identDefs[L-1]
if value.typ != nil and tfHasAsgn in value.typ.flags:
# the spec says we need to rewrite 'var x = T()' to 'var x: T; x = T()':
identDefs.sons[L-1] = emptyNode
if result.kind != nkStmtList:
let oldResult = result
oldResult.add identDefs
result = newNodeI(nkStmtList, result.info)
result.add oldResult
else:
let o = copyNode(orig)
o.add identDefs
result.add o
for i in 0 .. L-3:
result.add overloadedAsgn(c, identDefs[i], value)
elif result.kind == nkStmtList:
let o = copyNode(orig)
o.add identDefs
result.add o
else:
result.add identDefs
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode var b: PNode
result = copyNode(n) result = copyNode(n)
@ -396,7 +429,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
newSons(b, length) newSons(b, length)
b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
b.sons[length-1] = def b.sons[length-1] = def
addSon(result, b) addToVarSection(c, result, n, b)
elif tup.kind == tyTuple and def.kind == nkPar and elif tup.kind == tyTuple and def.kind == nkPar and
a.kind == nkIdentDefs and a.len > 3: a.kind == nkIdentDefs and a.len > 3:
message(a.info, warnEachIdentIsTuple) message(a.info, warnEachIdentIsTuple)
@ -429,7 +462,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
addSon(b, newSymNode(v)) addSon(b, newSymNode(v))
addSon(b, a.sons[length-2]) # keep type desc for doc generator addSon(b, a.sons[length-2]) # keep type desc for doc generator
addSon(b, copyTree(def)) addSon(b, copyTree(def))
addSon(result, b) addToVarSection(c, result, n, b)
else: else:
if def.kind == nkPar: v.ast = def[j] if def.kind == nkPar: v.ast = def[j]
v.typ = tup.sons[j] v.typ = tup.sons[j]
@ -909,11 +942,12 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
proc semOverride(c: PContext, s: PSym, n: PNode) = proc semOverride(c: PContext, s: PSym, n: PNode) =
case s.name.s.normalize case s.name.s.normalize
of "destroy": of "destroy", "=destroy":
doDestructorStuff(c, s, n) doDestructorStuff(c, s, n)
if not experimentalMode(c): if not experimentalMode(c):
localError n.info, "use the {.experimental.} pragma to enable destructors" localError n.info, "use the {.experimental.} pragma to enable destructors"
of "deepcopy": incl(s.flags, sfUsed)
of "deepcopy", "=deepcopy":
if s.typ.len == 2 and if s.typ.len == 2 and
s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
sameType(s.typ.sons[1], s.typ.sons[0]): sameType(s.typ.sons[1], s.typ.sons[0]):
@ -935,10 +969,35 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
else: else:
localError(n.info, errGenerated, localError(n.info, errGenerated,
"signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T") "signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
of "=": discard incl(s.flags, sfUsed)
else: localError(n.info, errGenerated, of "=":
"'destroy' or 'deepCopy' expected for 'override'") incl(s.flags, sfUsed)
incl(s.flags, sfUsed) let t = s.typ
if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
var obj = t.sons[1].sons[0]
while true:
incl(obj.flags, tfHasAsgn)
if obj.kind == tyGenericBody: obj = obj.lastSon
elif obj.kind == tyGenericInvocation: obj = obj.sons[0]
else: break
var objB = t.sons[2]
while true:
if objB.kind == tyGenericBody: objB = objB.lastSon
elif objB.kind == tyGenericInvocation: objB = objB.sons[0]
else: break
if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
if obj.assignment.isNil:
obj.assignment = s
else:
localError(n.info, errGenerated,
"cannot bind another '=' to: " & typeToString(obj))
return
localError(n.info, errGenerated,
"signature for '=' must be proc[T: object](x: var T; y: T)")
else:
if sfOverriden in s.flags:
localError(n.info, errGenerated,
"'destroy' or 'deepCopy' expected for 'override'")
type type
TProcCompilationSteps = enum TProcCompilationSteps = enum
@ -970,7 +1029,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
s = semIdentDef(c, n.sons[0], kind) s = semIdentDef(c, n.sons[0], kind)
n.sons[namePos] = newSymNode(s) n.sons[namePos] = newSymNode(s)
s.ast = n s.ast = n
s.scope = c.currentScope #s.scope = c.currentScope
if sfNoForward in c.module.flags and if sfNoForward in c.module.flags and
sfSystemModule notin c.module.flags: sfSystemModule notin c.module.flags:
@ -982,14 +1041,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
s.owner = getCurrOwner() s.owner = getCurrOwner()
typeIsDetermined = s.typ == nil typeIsDetermined = s.typ == nil
s.ast = n s.ast = n
s.scope = c.currentScope #s.scope = c.currentScope
# if typeIsDetermined: assert phase == stepCompileBody # if typeIsDetermined: assert phase == stepCompileBody
# else: assert phase == stepDetermineType # else: assert phase == stepDetermineType
# before compiling the proc body, set as current the scope # before compiling the proc body, set as current the scope
# where the proc was declared # where the proc was declared
let oldScope = c.currentScope let oldScope = c.currentScope
c.currentScope = s.scope #c.currentScope = s.scope
pushOwner(s) pushOwner(s)
openScope(c) openScope(c)
var gp: PNode var gp: PNode
@ -1014,7 +1073,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if s.kind in skIterators: if s.kind in skIterators:
s.typ.flags.incl(tfIterator) s.typ.flags.incl(tfIterator)
var proto = searchForProc(c, s.scope, s) var proto = searchForProc(c, oldScope, s)
if proto == nil: if proto == nil:
if s.kind == skClosureIterator: s.typ.callConv = ccClosure if s.kind == skClosureIterator: s.typ.callConv = ccClosure
else: s.typ.callConv = lastOptionEntry(c).defaultCC else: s.typ.callConv = lastOptionEntry(c).defaultCC
@ -1022,10 +1081,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
if sfGenSym in s.flags: discard if sfGenSym in s.flags: discard
elif kind in OverloadableSyms: elif kind in OverloadableSyms:
if not typeIsDetermined: if not typeIsDetermined:
addInterfaceOverloadableSymAt(c, s.scope, s) addInterfaceOverloadableSymAt(c, oldScope, s)
else: else:
if not typeIsDetermined: if not typeIsDetermined:
addInterfaceDeclAt(c, s.scope, s) addInterfaceDeclAt(c, oldScope, s)
if n.sons[pragmasPos].kind != nkEmpty: if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, s, n.sons[pragmasPos], validPragmas) pragma(c, s, n.sons[pragmasPos], validPragmas)
else: else:
@ -1055,7 +1114,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
popOwner() popOwner()
pushOwner(s) pushOwner(s)
s.options = gOptions s.options = gOptions
if sfOverriden in s.flags: semOverride(c, s, n) if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
if n.sons[bodyPos].kind != nkEmpty: if n.sons[bodyPos].kind != nkEmpty:
# for DLL generation it is annoying to check for sfImportc! # for DLL generation it is annoying to check for sfImportc!
if sfBorrow in s.flags: if sfBorrow in s.flags:
@ -1093,7 +1152,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
elif sfBorrow in s.flags: semBorrow(c, n, s) elif sfBorrow in s.flags: semBorrow(c, n, s)
sideEffectsCheck(c, s) sideEffectsCheck(c, s)
closeScope(c) # close scope for parameters closeScope(c) # close scope for parameters
c.currentScope = oldScope # c.currentScope = oldScope
popOwner() popOwner()
if n.sons[patternPos].kind != nkEmpty: if n.sons[patternPos].kind != nkEmpty:
c.patterns.add(s) c.patterns.add(s)

View file

@ -482,7 +482,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
s = semIdentVis(c, skTemplate, n.sons[0], {}) s = semIdentVis(c, skTemplate, n.sons[0], {})
styleCheckDef(s) styleCheckDef(s)
# check parameter list: # check parameter list:
s.scope = c.currentScope #s.scope = c.currentScope
pushOwner(s) pushOwner(s)
openScope(c) openScope(c)
n.sons[namePos] = newSymNode(s, n.sons[namePos].info) n.sons[namePos] = newSymNode(s, n.sons[namePos].info)

View file

@ -593,7 +593,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
f.position = pos f.position = pos
if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and
(f.loc.r == nil): (f.loc.r == nil):
f.loc.r = toRope(f.name.s) f.loc.r = rope(f.name.s)
f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags) f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags)
inc(pos) inc(pos)
if containsOrIncl(check, f.name.id): if containsOrIncl(check, f.name.id):

View file

@ -16,9 +16,9 @@ const
proc sharedPtrCheck(info: TLineInfo, t: PType) = proc sharedPtrCheck(info: TLineInfo, t: PType) =
if t.kind == tyPtr and t.len > 1: if t.kind == tyPtr and t.len > 1:
if t.sons[0].sym.magic in {mShared, mGuarded}: if t.sons[0].sym.magic == mShared:
incl(t.flags, tfShared) incl(t.flags, tfShared)
if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded) #if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
if tfHasGCedMem in t.flags or t.isGCedMem: if tfHasGCedMem in t.flags or t.isGCedMem:
localError(info, errGenerated, localError(info, errGenerated,
"shared memory may not refer to GC'ed thread local memory") "shared memory may not refer to GC'ed thread local memory")
@ -307,7 +307,13 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags: if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
# 'deepCopy' needs to be instantiated for # 'deepCopy' needs to be instantiated for
# generics *when the type is constructed*: # generics *when the type is constructed*:
newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info) newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
attachedDeepCopy)
let asgn = newbody.assignment
if asgn != nil and sfFromGeneric notin asgn.flags:
# '=' needs to be instantiated for generics when the type is constructed:
newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
attachedAsgn)
proc eraseVoidParams*(t: PType) = proc eraseVoidParams*(t: PType) =
# transform '(): void' into '()' because old parts of the compiler really # transform '(): void' into '()' because old parts of the compiler really

View file

@ -99,9 +99,12 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
c.calleeSym = callee c.calleeSym = callee
if callee.kind in skProcKinds and calleeScope == -1: if callee.kind in skProcKinds and calleeScope == -1:
if callee.originatingModule == ctx.module: if callee.originatingModule == ctx.module:
let rootSym = if sfFromGeneric notin callee.flags: callee c.calleeScope = 2
else: callee.owner var owner = callee
c.calleeScope = rootSym.scope.depthLevel while true:
owner = owner.skipGenericOwner
if owner.kind == skModule: break
inc c.calleeScope
else: else:
c.calleeScope = 1 c.calleeScope = 1
else: else:
@ -1419,9 +1422,12 @@ proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
# a.typ == nil is valid # a.typ == nil is valid
result = a result = a
elif a.typ.isNil: elif a.typ.isNil:
# XXX This is unsound! 'formal' can differ from overloaded routine to
# overloaded routine!
let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator} let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator}
elif formal.kind == tyStmt: {efDetermineType, efWantStmt} else: {efDetermineType, efAllowStmt}
else: {efDetermineType} #elif formal.kind == tyStmt: {efDetermineType, efWantStmt}
#else: {efDetermineType}
result = c.semOperand(c, a, flags) result = c.semOperand(c, a, flags)
else: else:
result = a result = a
@ -1627,12 +1633,15 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
# instantiate generic converters for that # instantiate generic converters for that
result = res != nil result = res != nil
proc instDeepCopy*(c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {. proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
procvar.} = op: TTypeAttachedOp): PSym {.procvar.} =
var m: TCandidate var m: TCandidate
initCandidate(c, m, dc.typ) initCandidate(c, m, dc.typ)
var f = dc.typ.sons[1] var f = dc.typ.sons[1]
if f.kind in {tyRef, tyPtr}: f = f.lastSon if op == attachedDeepCopy:
if f.kind in {tyRef, tyPtr}: f = f.lastSon
else:
if f.kind == tyVar: f = f.lastSon
if typeRel(m, f, t) == isNone: if typeRel(m, f, t) == isNone:
localError(info, errGenerated, "cannot instantiate 'deepCopy'") localError(info, errGenerated, "cannot instantiate 'deepCopy'")
else: else:

View file

@ -368,7 +368,7 @@ proc sameConstant*(a, b: PNode): bool =
case a.kind case a.kind
of nkSym: result = a.sym == b.sym of nkSym: result = a.sym == b.sym
of nkIdent: result = a.ident.id == b.ident.id of nkIdent: result = a.ident.id == b.ident.id
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
of nkType, nkNilLit: result = a.typ == b.typ of nkType, nkNilLit: result = a.typ == b.typ

View file

@ -219,7 +219,7 @@ Concepts are written in the following form:
(x < y) is bool (x < y) is bool
Container[T] = concept c Container[T] = concept c
c.len is ordinal c.len is Ordinal
items(c) is iterator items(c) is iterator
for value in c: for value in c:
type(value) is T type(value) is T

View file

@ -21,27 +21,49 @@ helper distinct or object type has to be used for one pointer type.
operator `=` operator `=`
------------ ------------
This operator is the assignment operator. Note that in the contexts This operator is the assignment operator. Note that in the contexts
like ``let v = expr``, ``var v = expr``, ``parameter = defaultValue`` or for ``result = expr``, ``parameter = defaultValue`` or for
parameter passing no assignment is performed. The ``override`` pragma is parameter passing no assignment is performed. For a type ``T`` that has an
optional for overriding ``=``. overloaded assignment operator ``var v = T()`` is rewritten
to ``var v: T; v = T()``; in other words ``var`` and ``let`` contexts do count
as assignments.
The assignment operator needs to be attached to an object or distinct
type ``T``. Its signature has to be ``(var T, T)``. Example:
.. code-block:: nim
type
Concrete = object
a, b: string
proc `=`(d: var Concrete; src: Concrete) =
shallowCopy(d.a, src.a)
shallowCopy(d.b, src.b)
echo "Concrete '=' called"
var x, y: array[0..2, Concrete]
var cA, cB: Concrete
var cATup, cBTup: tuple[x: int, ha: Concrete]
x = y
cA = cB
cATup = cBTup
**Note**: Overriding of operator ``=`` is not yet implemented.
destructors destructors
----------- -----------
A destructor must have a single parameter with a concrete type (the name of a A destructor must have a single parameter with a concrete type (the name of a
generic type is allowed too). The name of the destructor has to be ``destroy`` generic type is allowed too). The name of the destructor has to be ``=destroy``.
and it need to be annotated with the ``override`` pragma.
``destroy(v)`` will be automatically invoked for every local stack ``=destroy(v)`` will be automatically invoked for every local stack
variable ``v`` that goes out of scope. variable ``v`` that goes out of scope.
If a structured type features a field with destructable type and If a structured type features a field with destructable type and
the user has not provided an explicit implementation, a destructor for the the user has not provided an explicit implementation, a destructor for the
structured type will be automatically generated. Calls to any base class structured type will be automatically generated. Calls to any base class
destructors in both user-defined and generated destructors will be inserted. destructors in both user-defined and generated destructors will be inserted.
A destructor is attached to the type it destructs; expressions of this type A destructor is attached to the type it destructs; expressions of this type
@ -52,13 +74,13 @@ can then only be used in *destructible contexts* and as parameters:
MyObj = object MyObj = object
x, y: int x, y: int
p: pointer p: pointer
proc destroy(o: var MyObj) {.override.} = proc `=destroy`(o: var MyObj) =
if o.p != nil: dealloc o.p if o.p != nil: dealloc o.p
proc open: MyObj = proc open: MyObj =
result = MyObj(x: 1, y: 2, p: alloc(3)) result = MyObj(x: 1, y: 2, p: alloc(3))
proc work(o: MyObj) = proc work(o: MyObj) =
echo o.x echo o.x
# No destructor invoked here for 'o' as 'o' is a parameter. # No destructor invoked here for 'o' as 'o' is a parameter.
@ -68,7 +90,7 @@ can then only be used in *destructible contexts* and as parameters:
var x = open() var x = open()
# valid: pass 'x' to some other proc: # valid: pass 'x' to some other proc:
work(x) work(x)
# Error: usage of a type with a destructor in a non destructible context # Error: usage of a type with a destructor in a non destructible context
echo open() echo open()
@ -85,7 +107,7 @@ be destructed at its scope exit. Later versions of the language will improve
the support of destructors. the support of destructors.
Be aware that destructors are not called for objects allocated with ``new``. Be aware that destructors are not called for objects allocated with ``new``.
This may change in future versions of language, but for now the ``finalizer`` This may change in future versions of language, but for now the `finalizer`:idx:
parameter to ``new`` has to be used. parameter to ``new`` has to be used.
**Note**: Destructors are still experimental and the spec might change **Note**: Destructors are still experimental and the spec might change
@ -95,7 +117,7 @@ significantly in order to incorporate an escape analysis.
deepCopy deepCopy
-------- --------
``deepCopy`` is a builtin that is invoked whenever data is passed to ``=deepCopy`` is a builtin that is invoked whenever data is passed to
a ``spawn``'ed proc to ensure memory safety. The programmer can override its a ``spawn``'ed proc to ensure memory safety. The programmer can override its
behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the
language may weaken this restriction.) language may weaken this restriction.)
@ -103,7 +125,7 @@ language may weaken this restriction.)
The signature has to be: The signature has to be:
.. code-block:: nim .. code-block:: nim
proc deepCopy(x: T): T {.override.} proc `=deepCopy`(x: T): T
This mechanism is used by most data structures that support shared memory like This mechanism is used by most data structures that support shared memory like
channels to implement thread safe automatic memory management. channels to implement thread safe automatic memory management.

View file

@ -864,7 +864,9 @@ Future directions:
* Builtin regions like ``private``, ``global`` and ``local`` will * Builtin regions like ``private``, ``global`` and ``local`` will
prove very useful for the upcoming OpenCL target. prove very useful for the upcoming OpenCL target.
* Builtin "regions" can model ``lent`` and ``unique`` pointers. * Builtin "regions" can model ``lent`` and ``unique`` pointers.
* An assignment operator can be attached to a region so that proper write
barriers can be generated. This would imply that the GC can be implemented
completely in user-space.
Procedural type Procedural type

View file

@ -36,25 +36,25 @@ const
type type
RegexFlag* = enum ## options for regular expressions RegexFlag* = enum ## options for regular expressions
reIgnoreCase = 0, ## do caseless matching reIgnoreCase = 0, ## do caseless matching
reMultiLine = 1, ## ``^`` and ``$`` match newlines within data reMultiLine = 1, ## ``^`` and ``$`` match newlines within data
reDotAll = 2, ## ``.`` matches anything including NL reDotAll = 2, ## ``.`` matches anything including NL
reExtended = 3, ## ignore whitespace and ``#`` comments reExtended = 3, ## ignore whitespace and ``#`` comments
reStudy = 4 ## study the expression (may be omitted if the reStudy = 4 ## study the expression (may be omitted if the
## expression will be used only once) ## expression will be used only once)
RegexDesc = object RegexDesc = object
h: PPcre h: PPcre
e: ptr TExtra e: ptr TExtra
Regex* = ref RegexDesc ## a compiled regular expression Regex* = ref RegexDesc ## a compiled regular expression
RegexError* = object of ValueError RegexError* = object of ValueError
## is raised if the pattern is no valid regular expression. ## is raised if the pattern is no valid regular expression.
{.deprecated: [TRegexFlag: RegexFlag, TRegexDesc: RegexDesc, TRegex: Regex, {.deprecated: [TRegexFlag: RegexFlag, TRegexDesc: RegexDesc, TRegex: Regex,
EInvalidRegEx: RegexError].} EInvalidRegEx: RegexError].}
proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} = proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
var e: ref RegexError var e: ref RegexError
new(e) new(e)
e.msg = msg e.msg = msg
@ -68,10 +68,10 @@ proc rawCompile(pattern: string, flags: cint): PPcre =
if result == nil: if result == nil:
raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n") raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
proc finalizeRegEx(x: Regex) = proc finalizeRegEx(x: Regex) =
# XXX This is a hack, but PCRE does not export its "free" function properly. # XXX This is a hack, but PCRE does not export its "free" function properly.
# Sigh. The hack relies on PCRE's implementation (see ``pcre_get.c``). # Sigh. The hack relies on PCRE's implementation (see ``pcre_get.c``).
# Fortunately the implementation is unlikely to change. # Fortunately the implementation is unlikely to change.
pcre.free_substring(cast[cstring](x.h)) pcre.free_substring(cast[cstring](x.h))
if not isNil(x.e): if not isNil(x.e):
pcre.free_substring(cast[cstring](x.e)) pcre.free_substring(cast[cstring](x.e))
@ -101,10 +101,10 @@ proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string],
if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1) if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
else: matches[i-1] = nil else: matches[i-1] = nil
return rawMatches[1] - rawMatches[0] return rawMatches[1] - rawMatches[0]
proc findBounds*(s: string, pattern: Regex, matches: var openArray[string], proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
start = 0): tuple[first, last: int] = start = 0): tuple[first, last: int] =
## returns the starting position and end position of `pattern` in `s` ## returns the starting position and end position of `pattern` in `s`
## and the captured ## and the captured
## substrings in the array `matches`. If it does not match, nothing ## substrings in the array `matches`. If it does not match, nothing
## is written into `matches` and ``(-1,0)`` is returned. ## is written into `matches` and ``(-1,0)`` is returned.
@ -120,12 +120,12 @@ proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1) if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
else: matches[i-1] = nil else: matches[i-1] = nil
return (rawMatches[0].int, rawMatches[1].int - 1) return (rawMatches[0].int, rawMatches[1].int - 1)
proc findBounds*(s: string, pattern: Regex, proc findBounds*(s: string, pattern: Regex,
matches: var openArray[tuple[first, last: int]], matches: var openArray[tuple[first, last: int]],
start = 0): tuple[first, last: int] = start = 0): tuple[first, last: int] =
## returns the starting position and end position of ``pattern`` in ``s`` ## returns the starting position and end position of ``pattern`` in ``s``
## and the captured substrings in the array `matches`. ## and the captured substrings in the array `matches`.
## If it does not match, nothing is written into `matches` and ## If it does not match, nothing is written into `matches` and
## ``(-1,0)`` is returned. ## ``(-1,0)`` is returned.
var var
@ -141,7 +141,7 @@ proc findBounds*(s: string, pattern: Regex,
else: matches[i-1] = (-1,0) else: matches[i-1] = (-1,0)
return (rawMatches[0].int, rawMatches[1].int - 1) return (rawMatches[0].int, rawMatches[1].int - 1)
proc findBounds*(s: string, pattern: Regex, proc findBounds*(s: string, pattern: Regex,
start = 0): tuple[first, last: int] = start = 0): tuple[first, last: int] =
## returns the starting position of `pattern` in `s`. If it does not ## returns the starting position of `pattern` in `s`. If it does not
## match, ``(-1,0)`` is returned. ## match, ``(-1,0)`` is returned.
@ -152,7 +152,7 @@ proc findBounds*(s: string, pattern: Regex,
cast[ptr cint](rawMatches), 3) cast[ptr cint](rawMatches), 3)
if res < 0'i32: return (int(res), 0) if res < 0'i32: return (int(res), 0)
return (int(rawMatches[0]), int(rawMatches[1]-1)) return (int(rawMatches[0]), int(rawMatches[1]-1))
proc matchOrFind(s: string, pattern: Regex, start, flags: cint): cint = proc matchOrFind(s: string, pattern: Regex, start, flags: cint): cint =
var var
rtarray = initRtArray[cint](3) rtarray = initRtArray[cint](3)
@ -172,7 +172,7 @@ proc matchLen*(s: string, pattern: Regex, matches: var openArray[string],
proc matchLen*(s: string, pattern: Regex, start = 0): int = proc matchLen*(s: string, pattern: Regex, start = 0): int =
## the same as ``match``, but it returns the length of the match, ## the same as ``match``, but it returns the length of the match,
## if there is no match, -1 is returned. Note that a match length ## if there is no match, -1 is returned. Note that a match length
## of zero can happen. ## of zero can happen.
return matchOrFind(s, pattern, start.cint, pcre.ANCHORED) return matchOrFind(s, pattern, start.cint, pcre.ANCHORED)
proc match*(s: string, pattern: Regex, start = 0): bool = proc match*(s: string, pattern: Regex, start = 0): bool =
@ -216,7 +216,7 @@ proc find*(s: string, pattern: Regex, start = 0): int =
if res < 0'i32: return res if res < 0'i32: return res
return rawMatches[0] return rawMatches[0]
iterator findAll*(s: string, pattern: Regex, start = 0): string = iterator findAll*(s: string, pattern: Regex, start = 0): string =
## Yields all matching *substrings* of `s` that match `pattern`. ## Yields all matching *substrings* of `s` that match `pattern`.
## ##
## Note that since this is an iterator you should not modify the string you ## Note that since this is an iterator you should not modify the string you
@ -231,10 +231,11 @@ iterator findAll*(s: string, pattern: Regex, start = 0): string =
if res < 0'i32: break if res < 0'i32: break
let a = rawMatches[0] let a = rawMatches[0]
let b = rawMatches[1] let b = rawMatches[1]
if a == b and a == i: break
yield substr(s, int(a), int(b)-1) yield substr(s, int(a), int(b)-1)
i = b i = b
proc findAll*(s: string, pattern: Regex, start = 0): seq[string] = proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
## returns all matching *substrings* of `s` that match `pattern`. ## returns all matching *substrings* of `s` that match `pattern`.
## If it does not match, @[] is returned. ## If it does not match, @[] is returned.
accumulateResult(findAll(s, pattern, start)) accumulateResult(findAll(s, pattern, start))
@ -242,13 +243,13 @@ proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
when not defined(nimhygiene): when not defined(nimhygiene):
{.pragma: inject.} {.pragma: inject.}
template `=~` *(s: string, pattern: Regex): expr = template `=~` *(s: string, pattern: Regex): expr =
## This calls ``match`` with an implicit declared ``matches`` array that ## This calls ``match`` with an implicit declared ``matches`` array that
## can be used in the scope of the ``=~`` call: ## can be used in the scope of the ``=~`` call:
## ##
## .. code-block:: nim ## .. code-block:: nim
## ##
## if line =~ re"\s*(\w+)\s*\=\s*(\w+)": ## if line =~ re"\s*(\w+)\s*\=\s*(\w+)":
## # matches a key=value pair: ## # matches a key=value pair:
## echo("Key: ", matches[0]) ## echo("Key: ", matches[0])
## echo("Value: ", matches[1]) ## echo("Value: ", matches[1])
@ -260,9 +261,9 @@ template `=~` *(s: string, pattern: Regex): expr =
## else: ## else:
## echo("syntax error") ## echo("syntax error")
## ##
bind MaxSubPatterns bind MaxSubpatterns
when not declaredInScope(matches): when not declaredInScope(matches):
var matches {.inject.}: array[0..MaxSubpatterns-1, string] var matches {.inject.}: array[MaxSubpatterns, string]
match(s, pattern, matches) match(s, pattern, matches)
# ------------------------- more string handling ------------------------------ # ------------------------- more string handling ------------------------------
@ -286,7 +287,7 @@ proc endsWith*(s: string, suffix: Regex): bool =
if matchLen(s, suffix, i) == s.len - i: return true if matchLen(s, suffix, i) == s.len - i: return true
proc replace*(s: string, sub: Regex, by = ""): string = proc replace*(s: string, sub: Regex, by = ""): string =
## Replaces `sub` in `s` by the string `by`. Captures cannot be ## Replaces `sub` in `s` by the string `by`. Captures cannot be
## accessed in `by`. Examples: ## accessed in `by`. Examples:
## ##
## .. code-block:: nim ## .. code-block:: nim
@ -306,7 +307,7 @@ proc replace*(s: string, sub: Regex, by = ""): string =
add(result, by) add(result, by)
prev = match.last + 1 prev = match.last + 1
add(result, substr(s, prev)) add(result, substr(s, prev))
proc replacef*(s: string, sub: Regex, by: string): string = proc replacef*(s: string, sub: Regex, by: string): string =
## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by` ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples: ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
@ -320,7 +321,7 @@ proc replacef*(s: string, sub: Regex, by: string): string =
## ##
## "var1<-keykey; val2<-key2key2" ## "var1<-keykey; val2<-key2key2"
result = "" result = ""
var caps: array[0..MaxSubpatterns-1, string] var caps: array[MaxSubpatterns, string]
var prev = 0 var prev = 0
while true: while true:
var match = findBounds(s, sub, caps, prev) var match = findBounds(s, sub, caps, prev)
@ -338,7 +339,7 @@ proc parallelReplace*(s: string, subs: openArray[
## applied in parallel. ## applied in parallel.
result = "" result = ""
var i = 0 var i = 0
var caps: array[0..MaxSubpatterns-1, string] var caps: array[MaxSubpatterns, string]
while i < s.len: while i < s.len:
block searchSubs: block searchSubs:
for j in 0..high(subs): for j in 0..high(subs):
@ -359,7 +360,7 @@ proc transformFile*(infile, outfile: string,
## error occurs. This is supposed to be used for quick scripting. ## error occurs. This is supposed to be used for quick scripting.
var x = readFile(infile).string var x = readFile(infile).string
writeFile(outfile, x.parallelReplace(subs)) writeFile(outfile, x.parallelReplace(subs))
iterator split*(s: string, sep: Regex): string = iterator split*(s: string, sep: Regex): string =
## Splits the string `s` into substrings. ## Splits the string `s` into substrings.
## ##
@ -373,41 +374,44 @@ iterator split*(s: string, sep: Regex): string =
## Results in: ## Results in:
## ##
## .. code-block:: nim ## .. code-block:: nim
## ""
## "this" ## "this"
## "is" ## "is"
## "an" ## "an"
## "example" ## "example"
## ""
## ##
var var
first = 0 first = -1
last = 0 last = -1
while last < len(s): while last < len(s):
var x = matchLen(s, sep, last) var x = matchLen(s, sep, last)
if x > 0: inc(last, x) if x > 0: inc(last, x)
first = last first = last
if x == 0: inc(last)
while last < len(s): while last < len(s):
inc(last)
x = matchLen(s, sep, last) x = matchLen(s, sep, last)
if x > 0: break if x >= 0: break
if first < last: inc(last)
if first <= last:
yield substr(s, first, last-1) yield substr(s, first, last-1)
proc split*(s: string, sep: Regex): seq[string] = proc split*(s: string, sep: Regex): seq[string] =
## Splits the string `s` into substrings. ## Splits the string `s` into substrings.
accumulateResult(split(s, sep)) accumulateResult(split(s, sep))
proc escapeRe*(s: string): string = proc escapeRe*(s: string): string =
## escapes `s` so that it is matched verbatim when used as a regular ## escapes `s` so that it is matched verbatim when used as a regular
## expression. ## expression.
result = "" result = ""
for c in items(s): for c in items(s):
case c case c
of 'a'..'z', 'A'..'Z', '0'..'9', '_': of 'a'..'z', 'A'..'Z', '0'..'9', '_':
result.add(c) result.add(c)
else: else:
result.add("\\x") result.add("\\x")
result.add(toHex(ord(c), 2)) result.add(toHex(ord(c), 2))
const ## common regular expressions const ## common regular expressions
reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b" ## describes an identifier reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b" ## describes an identifier
reNatural* = r"\b\d+\b" ## describes a natural number reNatural* = r"\b\d+\b" ## describes a natural number
@ -430,7 +434,7 @@ const ## common regular expressions
when isMainModule: when isMainModule:
assert match("(a b c)", re"\( .* \)") assert match("(a b c)", re"\( .* \)")
assert match("WHiLe", re("while", {reIgnoreCase})) assert match("WHiLe", re("while", {reIgnoreCase}))
assert "0158787".match(re"\d+") assert "0158787".match(re"\d+")
assert "ABC 0232".match(re"\w+\s+\d+") assert "ABC 0232".match(re"\w+\s+\d+")
assert "ABC".match(re"\d+ | \w+") assert "ABC".match(re"\d+ | \w+")
@ -439,21 +443,21 @@ when isMainModule:
var pattern = re"[a-z0-9]+\s*=\s*[a-z0-9]+" var pattern = re"[a-z0-9]+\s*=\s*[a-z0-9]+"
assert matchLen("key1= cal9", pattern) == 11 assert matchLen("key1= cal9", pattern) == 11
assert find("_____abc_______", re"abc") == 5 assert find("_____abc_______", re"abc") == 5
var matches: array[0..5, string] var matches: array[6, string]
if match("abcdefg", re"c(d)ef(g)", matches, 2): if match("abcdefg", re"c(d)ef(g)", matches, 2):
assert matches[0] == "d" assert matches[0] == "d"
assert matches[1] == "g" assert matches[1] == "g"
else: else:
assert false assert false
if "abc" =~ re"(a)bcxyz|(\w+)": if "abc" =~ re"(a)bcxyz|(\w+)":
assert matches[1] == "abc" assert matches[1] == "abc"
else: else:
assert false assert false
if "abc" =~ re"(cba)?.*": if "abc" =~ re"(cba)?.*":
assert matches[0] == nil assert matches[0] == nil
else: assert false else: assert false
@ -461,7 +465,7 @@ when isMainModule:
if "abc" =~ re"().*": if "abc" =~ re"().*":
assert matches[0] == "" assert matches[0] == ""
else: assert false else: assert false
assert "var1=key; var2=key2".endsWith(re"\w+=\w+") assert "var1=key; var2=key2".endsWith(re"\w+=\w+")
assert("var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2") == assert("var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2") ==
"var1<-keykey; var2<-key2key2") "var1<-keykey; var2<-key2key2")
@ -471,7 +475,12 @@ when isMainModule:
var accum: seq[string] = @[] var accum: seq[string] = @[]
for word in split("00232this02939is39an22example111", re"\d+"): for word in split("00232this02939is39an22example111", re"\d+"):
accum.add(word) accum.add(word)
assert(accum == @["this", "is", "an", "example"]) assert(accum == @["", "this", "is", "an", "example", ""])
accum = @[]
for word in split("AAA : : BBB", re"\s*:\s*"):
accum.add(word)
assert(accum == @["AAA", "", "BBB"])
for x in findAll("abcdef", re"^{.}", 3): for x in findAll("abcdef", re"^{.}", 3):
assert x == "d" assert x == "d"
@ -484,7 +493,7 @@ when isMainModule:
assert("XYZ".match(re"^\d*") == true) assert("XYZ".match(re"^\d*") == true)
block: block:
var matches: array[0..15, string] var matches: array[16, string]
if match("abcdefghijklmnop", re"(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)", matches): if match("abcdefghijklmnop", re"(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)", matches):
for i in 0..matches.high: for i in 0..matches.high:
assert matches[i] == $chr(i + 'a'.ord) assert matches[i] == $chr(i + 'a'.ord)

View file

@ -36,8 +36,11 @@ type
onsubmit*: proc (event: ref TEvent) {.nimcall.} onsubmit*: proc (event: ref TEvent) {.nimcall.}
onunload*: proc (event: ref TEvent) {.nimcall.} onunload*: proc (event: ref TEvent) {.nimcall.}
TWindow* {.importc.} = object of TEventHandlers addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent), useCapture: bool = false) {.nimcall.}
document*: ref TDocument
Window* = ref WindowObj
WindowObj {.importc.} = object of TEventHandlers
document*: Document
event*: ref TEvent event*: ref TEvent
history*: ref THistory history*: ref THistory
location*: ref TLocation location*: ref TLocation
@ -55,7 +58,6 @@ type
status*: cstring status*: cstring
toolbar*: ref TToolBar toolbar*: ref TToolBar
addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent) ) {.nimcall.}
alert*: proc (msg: cstring) {.nimcall.} alert*: proc (msg: cstring) {.nimcall.}
back*: proc () {.nimcall.} back*: proc () {.nimcall.}
blur*: proc () {.nimcall.} blur*: proc () {.nimcall.}
@ -66,7 +68,7 @@ type
confirm*: proc (msg: cstring): bool {.nimcall.} confirm*: proc (msg: cstring): bool {.nimcall.}
disableExternalCapture*: proc () {.nimcall.} disableExternalCapture*: proc () {.nimcall.}
enableExternalCapture*: proc () {.nimcall.} enableExternalCapture*: proc () {.nimcall.}
find*: proc (text: cstring, caseSensitive = false, find*: proc (text: cstring, caseSensitive = false,
backwards = false) {.nimcall.} backwards = false) {.nimcall.}
focus*: proc () {.nimcall.} focus*: proc () {.nimcall.}
forward*: proc () {.nimcall.} forward*: proc () {.nimcall.}
@ -75,7 +77,7 @@ type
moveBy*: proc (x, y: int) {.nimcall.} moveBy*: proc (x, y: int) {.nimcall.}
moveTo*: proc (x, y: int) {.nimcall.} moveTo*: proc (x, y: int) {.nimcall.}
open*: proc (uri, windowname: cstring, open*: proc (uri, windowname: cstring,
properties: cstring = nil): ref TWindow {.nimcall.} properties: cstring = nil): Window {.nimcall.}
print*: proc () {.nimcall.} print*: proc () {.nimcall.}
prompt*: proc (text, default: cstring): cstring {.nimcall.} prompt*: proc (text, default: cstring): cstring {.nimcall.}
releaseEvents*: proc (eventMask: int) {.nimcall.} releaseEvents*: proc (eventMask: int) {.nimcall.}
@ -89,115 +91,8 @@ type
stop*: proc () {.nimcall.} stop*: proc () {.nimcall.}
frames*: seq[TFrame] frames*: seq[TFrame]
TFrame* {.importc.} = object of TWindow Frame* = ref FrameObj
FrameObj {.importc.} = object of WindowObj
TDocument* {.importc.} = object of TEventHandlers
addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent) ) {.nimcall.}
alinkColor*: cstring
bgColor*: cstring
charset*: cstring
cookie*: cstring
defaultCharset*: cstring
fgColor*: cstring
lastModified*: cstring
linkColor*: cstring
referrer*: cstring
title*: cstring
URL*: cstring
vlinkColor*: cstring
captureEvents*: proc (eventMask: int) {.nimcall.}
createAttribute*: proc (identifier: cstring): ref TNode {.nimcall.}
createElement*: proc (identifier: cstring): ref TNode {.nimcall.}
createTextNode*: proc (identifier: cstring): ref TNode {.nimcall.}
getElementById*: proc (id: cstring): ref TNode {.nimcall.}
getElementsByName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
getSelection*: proc (): cstring {.nimcall.}
handleEvent*: proc (event: ref TEvent) {.nimcall.}
open*: proc () {.nimcall.}
releaseEvents*: proc (eventMask: int) {.nimcall.}
routeEvent*: proc (event: ref TEvent) {.nimcall.}
write*: proc (text: cstring) {.nimcall.}
writeln*: proc (text: cstring) {.nimcall.}
anchors*: seq[ref TAnchor]
forms*: seq[ref TForm]
images*: seq[ref TImage]
applets*: seq[ref TApplet]
embeds*: seq[ref TEmbed]
links*: seq[ref TLink]
TLink* {.importc.} = object of RootObj
name*: cstring
target*: cstring
text*: cstring
x*: int
y*: int
TEmbed* {.importc.} = object of RootObj
height*: int
hspace*: int
name*: cstring
src*: cstring
width*: int
`type`*: cstring
vspace*: int
play*: proc () {.nimcall.}
stop*: proc () {.nimcall.}
TAnchor* {.importc.} = object of RootObj
name*: cstring
text*: cstring
x*, y*: int
TApplet* {.importc.} = object of RootObj
TElement* {.importc.} = object of TEventHandlers
checked*: bool
defaultChecked*: bool
defaultValue*: cstring
disabled*: bool
form*: ref TForm
name*: cstring
readOnly*: bool
`type`*: cstring
value*: cstring
blur*: proc () {.nimcall.}
click*: proc () {.nimcall.}
focus*: proc () {.nimcall.}
handleEvent*: proc (event: ref TEvent) {.nimcall.}
select*: proc () {.nimcall.}
options*: seq[ref TOption]
TOption* {.importc.} = object of RootObj
defaultSelected*: bool
selected*: bool
selectedIndex*: int
text*: cstring
value*: cstring
TForm* {.importc.} = object of TEventHandlers
action*: cstring
encoding*: cstring
`method`*: cstring
name*: cstring
target*: cstring
handleEvent*: proc (event: ref TEvent) {.nimcall.}
reset*: proc () {.nimcall.}
submit*: proc () {.nimcall.}
elements*: seq[ref TElement]
TImage* {.importc.} = object of TEventHandlers
border*: int
complete*: bool
height*: int
hspace*: int
lowsrc*: cstring
name*: cstring
src*: cstring
vspace*: int
width*: int
handleEvent*: proc (event: ref TEvent) {.nimcall.}
ClassList* {.importc.} = object of RootObj ClassList* {.importc.} = object of RootObj
add*: proc (class: cstring) {.nimcall.} add*: proc (class: cstring) {.nimcall.}
@ -218,43 +113,151 @@ type
DocumentTypeNode, DocumentTypeNode,
DocumentFragmentNode, DocumentFragmentNode,
NotationNode NotationNode
TNode* {.importc.} = object of RootObj
attributes*: seq[ref TNode] Node* = ref NodeObj
childNodes*: seq[ref TNode] NodeObj {.importc.} = object of TEventHandlers
children*: seq[ref TNode] attributes*: seq[Node]
classList*: ref Classlist childNodes*: seq[Node]
children*: seq[Node]
data*: cstring data*: cstring
firstChild*: ref TNode firstChild*: Node
lastChild*: ref TNode lastChild*: Node
nextSibling*: ref TNode nextSibling*: Node
nodeName*: cstring nodeName*: cstring
nodeType*: TNodeType nodeType*: TNodeType
nodeValue*: cstring nodeValue*: cstring
parentNode*: ref TNode parentNode*: Node
previousSibling*: ref TNode previousSibling*: Node
appendChild*: proc (child: ref TNode) {.nimcall.} appendChild*: proc (child: Node) {.nimcall.}
appendData*: proc (data: cstring) {.nimcall.} appendData*: proc (data: cstring) {.nimcall.}
cloneNode*: proc (copyContent: bool): ref TNode {.nimcall.} cloneNode*: proc (copyContent: bool): Node {.nimcall.}
deleteData*: proc (start, len: int) {.nimcall.} deleteData*: proc (start, len: int) {.nimcall.}
getAttribute*: proc (attr: cstring): cstring {.nimcall.} getAttribute*: proc (attr: cstring): cstring {.nimcall.}
getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.} getAttributeNode*: proc (attr: cstring): Node {.nimcall.}
getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.}
hasChildNodes*: proc (): bool {.nimcall.} hasChildNodes*: proc (): bool {.nimcall.}
innerHTML*: cstring innerHTML*: cstring
insertBefore*: proc (newNode, before: ref TNode) {.nimcall.} insertBefore*: proc (newNode, before: Node) {.nimcall.}
insertData*: proc (position: int, data: cstring) {.nimcall.} insertData*: proc (position: int, data: cstring) {.nimcall.}
addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent)) {.nimcall.}
removeAttribute*: proc (attr: cstring) {.nimcall.} removeAttribute*: proc (attr: cstring) {.nimcall.}
removeAttributeNode*: proc (attr: ref TNode) {.nimcall.} removeAttributeNode*: proc (attr: Node) {.nimcall.}
removeChild*: proc (child: ref TNode) {.nimcall.} removeChild*: proc (child: Node) {.nimcall.}
replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.} replaceChild*: proc (newNode, oldNode: Node) {.nimcall.}
replaceData*: proc (start, len: int, text: cstring) {.nimcall.} replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
scrollIntoView*: proc () {.nimcall.} scrollIntoView*: proc () {.nimcall.}
setAttribute*: proc (name, value: cstring) {.nimcall.} setAttribute*: proc (name, value: cstring) {.nimcall.}
setAttributeNode*: proc (attr: ref TNode) {.nimcall.} setAttributeNode*: proc (attr: Node) {.nimcall.}
style*: ref TStyle style*: ref TStyle
Document* = ref DocumentObj
DocumentObj {.importc.} = object of NodeObj
alinkColor*: cstring
bgColor*: cstring
charset*: cstring
cookie*: cstring
defaultCharset*: cstring
fgColor*: cstring
lastModified*: cstring
linkColor*: cstring
referrer*: cstring
title*: cstring
URL*: cstring
vlinkColor*: cstring
captureEvents*: proc (eventMask: int) {.nimcall.}
createAttribute*: proc (identifier: cstring): Node {.nimcall.}
createElement*: proc (identifier: cstring): Element {.nimcall.}
createTextNode*: proc (identifier: cstring): Node {.nimcall.}
getElementById*: proc (id: cstring): Element {.nimcall.}
getElementsByName*: proc (name: cstring): seq[Element] {.nimcall.}
getElementsByTagName*: proc (name: cstring): seq[Element] {.nimcall.}
getElementsByClassName*: proc (name: cstring): seq[Element] {.nimcall.}
getSelection*: proc (): cstring {.nimcall.}
handleEvent*: proc (event: ref TEvent) {.nimcall.}
open*: proc () {.nimcall.}
releaseEvents*: proc (eventMask: int) {.nimcall.}
routeEvent*: proc (event: ref TEvent) {.nimcall.}
write*: proc (text: cstring) {.nimcall.}
writeln*: proc (text: cstring) {.nimcall.}
anchors*: seq[AnchorElement]
forms*: seq[FormElement]
images*: seq[ImageElement]
applets*: seq[ref TApplet]
embeds*: seq[EmbedElement]
links*: seq[LinkElement]
Element* = ref ElementObj
ElementObj {.importc.} = object of NodeObj
classList*: ref Classlist
checked*: bool
defaultChecked*: bool
defaultValue*: cstring
disabled*: bool
form*: FormElement
name*: cstring
readOnly*: bool
blur*: proc () {.nimcall.}
click*: proc () {.nimcall.}
focus*: proc () {.nimcall.}
handleEvent*: proc (event: ref TEvent) {.nimcall.}
select*: proc () {.nimcall.}
options*: seq[OptionElement]
getElementsByTagName*: proc (name: cstring): seq[Element] {.nimcall.}
getElementsByClassName*: proc (name: cstring): seq[Element] {.nimcall.}
LinkElement* = ref LinkObj
LinkObj {.importc.} = object of ElementObj
target*: cstring
text*: cstring
x*: int
y*: int
EmbedElement* = ref EmbedObj
EmbedObj {.importc.} = object of ElementObj
height*: int
hspace*: int
src*: cstring
width*: int
`type`*: cstring
vspace*: int
play*: proc () {.nimcall.}
stop*: proc () {.nimcall.}
AnchorElement* = ref AnchorObj
AnchorObj {.importc.} = object of ElementObj
text*: cstring
x*, y*: int
TApplet* {.importc.} = object of RootObj
OptionElement* = ref OptionObj
OptionObj {.importc.} = object of ElementObj
defaultSelected*: bool
selected*: bool
selectedIndex*: int
text*: cstring
value*: cstring
FormElement* = ref FormObj
FormObj {.importc.} = object of ElementObj
action*: cstring
encoding*: cstring
`method`*: cstring
target*: cstring
reset*: proc () {.nimcall.}
submit*: proc () {.nimcall.}
elements*: seq[Element]
ImageElement* = ref ImageObj
ImageObj {.importc.} = object of ElementObj
border*: int
complete*: bool
height*: int
hspace*: int
lowsrc*: cstring
src*: cstring
vspace*: int
width*: int
TStyle* {.importc.} = object of RootObj TStyle* {.importc.} = object of RootObj
background*: cstring background*: cstring
backgroundAttachment*: cstring backgroundAttachment*: cstring
@ -350,7 +353,7 @@ type
setAttribute*: proc (attr, value: cstring, caseSensitive=false) {.nimcall.} setAttribute*: proc (attr, value: cstring, caseSensitive=false) {.nimcall.}
TEvent* {.importc.} = object of RootObj TEvent* {.importc.} = object of RootObj
target*: ref TNode target*: Node
altKey*, ctrlKey*, shiftKey*: bool altKey*, ctrlKey*, shiftKey*: bool
button*: int button*: int
clientX*, clientY*: int clientX*, clientY*: int
@ -448,8 +451,8 @@ type
TInterval* {.importc.} = object of RootObj TInterval* {.importc.} = object of RootObj
var var
window* {.importc, nodecl.}: ref TWindow window* {.importc, nodecl.}: Window
document* {.importc, nodecl.}: ref TDocument document* {.importc, nodecl.}: Document
navigator* {.importc, nodecl.}: ref TNavigator navigator* {.importc, nodecl.}: ref TNavigator
screen* {.importc, nodecl.}: ref TScreen screen* {.importc, nodecl.}: ref TScreen
@ -466,3 +469,17 @@ proc isNaN*(x: BiggestFloat): bool {.importc, nodecl.}
proc parseFloat*(s: cstring): BiggestFloat {.importc, nodecl.} proc parseFloat*(s: cstring): BiggestFloat {.importc, nodecl.}
proc parseInt*(s: cstring): int {.importc, nodecl.} proc parseInt*(s: cstring): int {.importc, nodecl.}
proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.} proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.}
type
TWindow* {.deprecated.} = WindowObj
TFrame* {.deprecated.} = FrameObj
TNode* {.deprecated.} = NodeObj
TDocument* {.deprecated.} = DocumentObj
TElement* {.deprecated.} = ElementObj
TLink* {.deprecated.} = LinkObj
TEmbed* {.deprecated.} = EmbedObj
TAnchor* {.deprecated.} = AnchorObj
TOption* {.deprecated.} = OptionObj
TForm* {.deprecated.} = FormObj
TImage* {.deprecated.} = ImageObj

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,7 @@ type
rnField, # a field item rnField, # a field item
rnFieldName, # consisting of a field name ... rnFieldName, # consisting of a field name ...
rnFieldBody, # ... and a field body rnFieldBody, # ... and a field body
rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString, rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock, rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock,
rnLineBlock, # the | thingie rnLineBlock, # the | thingie
rnLineBlockItem, # sons of the | thing rnLineBlockItem, # sons of the | thing
@ -50,7 +50,7 @@ type
# * `file#id <file#id>'_ # * `file#id <file#id>'_
rnSubstitutionDef, # a definition of a substitution rnSubstitutionDef, # a definition of a substitution
rnGeneralRole, # Inline markup: rnGeneralRole, # Inline markup:
rnSub, rnSup, rnIdx, rnSub, rnSup, rnIdx,
rnEmphasis, # "*" rnEmphasis, # "*"
rnStrongEmphasis, # "**" rnStrongEmphasis, # "**"
rnTripleEmphasis, # "***" rnTripleEmphasis, # "***"
@ -71,25 +71,25 @@ type
level*: int ## valid for some node kinds level*: int ## valid for some node kinds
sons*: TRstNodeSeq ## the node's sons sons*: TRstNodeSeq ## the node's sons
proc len*(n: PRstNode): int = proc len*(n: PRstNode): int =
result = len(n.sons) result = len(n.sons)
proc newRstNode*(kind: TRstNodeKind): PRstNode = proc newRstNode*(kind: TRstNodeKind): PRstNode =
new(result) new(result)
result.sons = @[] result.sons = @[]
result.kind = kind result.kind = kind
proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode = proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
result = newRstNode(kind) result = newRstNode(kind)
result.text = s result.text = s
proc lastSon*(n: PRstNode): PRstNode = proc lastSon*(n: PRstNode): PRstNode =
result = n.sons[len(n.sons)-1] result = n.sons[len(n.sons)-1]
proc add*(father, son: PRstNode) = proc add*(father, son: PRstNode) =
add(father.sons, son) add(father.sons, son)
proc addIfNotNil*(father, son: PRstNode) = proc addIfNotNil*(father, son: PRstNode) =
if son != nil: add(father, son) if son != nil: add(father, son)
@ -98,26 +98,27 @@ type
indent: int indent: int
verbatim: int verbatim: int
proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) proc renderRstToRst(d: var TRenderContext, n: PRstNode,
result: var string) {.gcsafe.}
proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) = proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
for i in countup(0, len(n) - 1): for i in countup(0, len(n) - 1):
renderRstToRst(d, n.sons[i], result) renderRstToRst(d, n.sons[i], result)
proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) = proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
# this is needed for the index generation; it may also be useful for # this is needed for the index generation; it may also be useful for
# debugging, but most code is already debugged... # debugging, but most code is already debugged...
const const
lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+'] lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
if n == nil: return if n == nil: return
var ind = spaces(d.indent) var ind = spaces(d.indent)
case n.kind case n.kind
of rnInner: of rnInner:
renderRstSons(d, n, result) renderRstSons(d, n, result)
of rnHeadline: of rnHeadline:
result.add("\n") result.add("\n")
result.add(ind) result.add(ind)
let oldLen = result.len let oldLen = result.len
renderRstSons(d, n, result) renderRstSons(d, n, result)
let headlineLen = result.len - oldLen let headlineLen = result.len - oldLen
@ -131,16 +132,16 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
var headline = "" var headline = ""
renderRstSons(d, n, headline) renderRstSons(d, n, headline)
let lvl = repeat(lvlToChar[n.level], headline.len - d.indent) let lvl = repeat(lvlToChar[n.level], headline.len - d.indent)
result.add(lvl) result.add(lvl)
result.add("\n") result.add("\n")
result.add(headline) result.add(headline)
result.add("\n") result.add("\n")
result.add(ind) result.add(ind)
result.add(lvl) result.add(lvl)
of rnTransition: of rnTransition:
result.add("\n\n") result.add("\n\n")
result.add(ind) result.add(ind)
result.add repeat('-', 78-d.indent) result.add repeat('-', 78-d.indent)
@ -149,11 +150,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add("\n\n") result.add("\n\n")
result.add(ind) result.add(ind)
renderRstSons(d, n, result) renderRstSons(d, n, result)
of rnBulletItem: of rnBulletItem:
inc(d.indent, 2) inc(d.indent, 2)
var tmp = "" var tmp = ""
renderRstSons(d, n, tmp) renderRstSons(d, n, tmp)
if tmp.len > 0: if tmp.len > 0:
result.add("\n") result.add("\n")
result.add(ind) result.add(ind)
result.add("* ") result.add("* ")
@ -163,22 +164,22 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
inc(d.indent, 4) inc(d.indent, 4)
var tmp = "" var tmp = ""
renderRstSons(d, n, tmp) renderRstSons(d, n, tmp)
if tmp.len > 0: if tmp.len > 0:
result.add("\n") result.add("\n")
result.add(ind) result.add(ind)
result.add("(#) ") result.add("(#) ")
result.add(tmp) result.add(tmp)
dec(d.indent, 4) dec(d.indent, 4)
of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName, of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList: rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
renderRstSons(d, n, result) renderRstSons(d, n, result)
of rnDefName: of rnDefName:
result.add("\n\n") result.add("\n\n")
result.add(ind) result.add(ind)
renderRstSons(d, n, result) renderRstSons(d, n, result)
of rnDefBody: of rnDefBody:
inc(d.indent, 2) inc(d.indent, 2)
if n.sons[0].kind != rnBulletList: if n.sons[0].kind != rnBulletList:
result.add("\n") result.add("\n")
result.add(ind) result.add(ind)
result.add(" ") result.add(" ")
@ -187,10 +188,10 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
of rnField: of rnField:
var tmp = "" var tmp = ""
renderRstToRst(d, n.sons[0], tmp) renderRstToRst(d, n.sons[0], tmp)
var L = max(tmp.len + 3, 30) var L = max(tmp.len + 3, 30)
inc(d.indent, L) inc(d.indent, L)
result.add "\n" result.add "\n"
result.add ind result.add ind
result.add ':' result.add ':'
@ -198,9 +199,9 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add ':' result.add ':'
result.add spaces(L - tmp.len - 2) result.add spaces(L - tmp.len - 2)
renderRstToRst(d, n.sons[1], result) renderRstToRst(d, n.sons[1], result)
dec(d.indent, L) dec(d.indent, L)
of rnLineBlockItem: of rnLineBlockItem:
result.add("\n") result.add("\n")
result.add(ind) result.add(ind)
result.add("| ") result.add("| ")
@ -209,11 +210,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
inc(d.indent, 2) inc(d.indent, 2)
renderRstSons(d, n, result) renderRstSons(d, n, result)
dec(d.indent, 2) dec(d.indent, 2)
of rnRef: of rnRef:
result.add("`") result.add("`")
renderRstSons(d, n, result) renderRstSons(d, n, result)
result.add("`_") result.add("`_")
of rnHyperlink: of rnHyperlink:
result.add('`') result.add('`')
renderRstToRst(d, n.sons[0], result) renderRstToRst(d, n.sons[0], result)
result.add(" <") result.add(" <")
@ -225,23 +226,23 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add("`:") result.add("`:")
renderRstToRst(d, n.sons[1],result) renderRstToRst(d, n.sons[1],result)
result.add(':') result.add(':')
of rnSub: of rnSub:
result.add('`') result.add('`')
renderRstSons(d, n, result) renderRstSons(d, n, result)
result.add("`:sub:") result.add("`:sub:")
of rnSup: of rnSup:
result.add('`') result.add('`')
renderRstSons(d, n, result) renderRstSons(d, n, result)
result.add("`:sup:") result.add("`:sup:")
of rnIdx: of rnIdx:
result.add('`') result.add('`')
renderRstSons(d, n, result) renderRstSons(d, n, result)
result.add("`:idx:") result.add("`:idx:")
of rnEmphasis: of rnEmphasis:
result.add("*") result.add("*")
renderRstSons(d, n, result) renderRstSons(d, n, result)
result.add("*") result.add("*")
of rnStrongEmphasis: of rnStrongEmphasis:
result.add("**") result.add("**")
renderRstSons(d, n, result) renderRstSons(d, n, result)
result.add("**") result.add("**")
@ -249,11 +250,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add("***") result.add("***")
renderRstSons(d, n, result) renderRstSons(d, n, result)
result.add("***") result.add("***")
of rnInterpretedText: of rnInterpretedText:
result.add('`') result.add('`')
renderRstSons(d, n, result) renderRstSons(d, n, result)
result.add('`') result.add('`')
of rnInlineLiteral: of rnInlineLiteral:
inc(d.verbatim) inc(d.verbatim)
result.add("``") result.add("``")
renderRstSons(d, n, result) renderRstSons(d, n, result)
@ -266,11 +267,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add("\\\\") # XXX: escape more special characters! result.add("\\\\") # XXX: escape more special characters!
else: else:
result.add(n.text) result.add(n.text)
of rnIndex: of rnIndex:
result.add("\n\n") result.add("\n\n")
result.add(ind) result.add(ind)
result.add(".. index::\n") result.add(".. index::\n")
inc(d.indent, 3) inc(d.indent, 3)
if n.sons[2] != nil: renderRstSons(d, n.sons[2], result) if n.sons[2] != nil: renderRstSons(d, n.sons[2], result)
dec(d.indent, 3) dec(d.indent, 3)
@ -280,7 +281,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
result.add(".. contents::") result.add(".. contents::")
else: else:
result.add("Error: cannot render: " & $n.kind) result.add("Error: cannot render: " & $n.kind)
proc renderRstToRst*(n: PRstNode, result: var string) = proc renderRstToRst*(n: PRstNode, result: var string) =
## renders `n` into its string representation and appends to `result`. ## renders `n` into its string representation and appends to `result`.
var d: TRenderContext var d: TRenderContext
@ -302,7 +303,7 @@ proc renderRstToJsonNode(node: PRstNode): JsonNode =
proc renderRstToJson*(node: PRstNode): string = proc renderRstToJson*(node: PRstNode): string =
## Writes the given RST node as JSON that is in the form ## Writes the given RST node as JSON that is in the form
## :: ## ::
## { ## {
## "kind":string node.kind, ## "kind":string node.kind,
## "text":optional string node.text, ## "text":optional string node.text,

View file

@ -95,10 +95,11 @@ type
header: "<dirent.h>", final, pure.} = object ## dirent_t struct header: "<dirent.h>", final, pure.} = object ## dirent_t struct
d_ino*: Tino ## File serial number. d_ino*: Tino ## File serial number.
when defined(linux) or defined(macosx) or defined(bsd): when defined(linux) or defined(macosx) or defined(bsd):
d_off*: TOff ## Not an offset. Value that ``telldir()`` would return.
d_reclen*: cshort ## Length of this record. (not POSIX) d_reclen*: cshort ## Length of this record. (not POSIX)
d_type*: int8 ## Type of file; not supported by all filesystem types. d_type*: int8 ## Type of file; not supported by all filesystem types.
## (not POSIX) ## (not POSIX)
when defined(linux) or defined(bsd):
d_off*: TOff ## Not an offset. Value that ``telldir()`` would return.
d_name*: array [0..255, char] ## Name of entry. d_name*: array [0..255, char] ## Name of entry.
Tflock* {.importc: "struct flock", final, pure, Tflock* {.importc: "struct flock", final, pure,
@ -1579,8 +1580,11 @@ else:
when defined(macosx): when defined(macosx):
# We can't use the NOSIGNAL flag in the ``send`` function, it has no effect # We can't use the NOSIGNAL flag in the ``send`` function, it has no effect
var # Instead we should use SO_NOSIGPIPE in setsockopt
const
MSG_NOSIGNAL* = 0'i32 MSG_NOSIGNAL* = 0'i32
var
SO_NOSIGPIPE* {.importc, header: "<sys/socket.h>".}: cint
else: else:
var var
MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint

View file

@ -24,7 +24,7 @@ proc `*`*(x: int, order: SortOrder): int {.inline.} =
var y = order.ord - 1 var y = order.ord - 1
result = (x xor y) - y result = (x xor y) - y
proc reverse*[T](a: var openArray[T], first, last: int) = proc reverse*[T](a: var openArray[T], first, last: Natural) =
## reverses the array ``a[first..last]``. ## reverses the array ``a[first..last]``.
var x = first var x = first
var y = last var y = last
@ -37,7 +37,7 @@ proc reverse*[T](a: var openArray[T]) =
## reverses the array `a`. ## reverses the array `a`.
reverse(a, 0, a.high) reverse(a, 0, a.high)
proc reversed*[T](a: openArray[T], first, last: int): seq[T] = proc reversed*[T](a: openArray[T], first, last: Natural): seq[T] =
## returns the reverse of the array `a[first..last]`. ## returns the reverse of the array `a[first..last]`.
result = newSeq[T](last - first + 1) result = newSeq[T](last - first + 1)
var x = first var x = first

View file

@ -841,6 +841,8 @@ else:
proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD = proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD =
result = newRawSocket(domain, typ, protocol).TAsyncFD result = newRawSocket(domain, typ, protocol).TAsyncFD
result.SocketHandle.setBlocking(false) result.SocketHandle.setBlocking(false)
when defined(macosx):
result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
register(result) register(result)
proc newAsyncRawSocket*(domain: Domain = AF_INET, proc newAsyncRawSocket*(domain: Domain = AF_INET,
@ -848,6 +850,8 @@ else:
protocol: Protocol = IPPROTO_TCP): TAsyncFD = protocol: Protocol = IPPROTO_TCP): TAsyncFD =
result = newRawSocket(domain, typ, protocol).TAsyncFD result = newRawSocket(domain, typ, protocol).TAsyncFD
result.SocketHandle.setBlocking(false) result.SocketHandle.setBlocking(false)
when defined(macosx):
result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
register(result) register(result)
proc closeSocket*(sock: TAsyncFD) = proc closeSocket*(sock: TAsyncFD) =
@ -959,7 +963,6 @@ else:
result = true result = true
let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint, let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint,
flags.toOSFlags()) flags.toOSFlags())
#echo("recv cb res: ", res)
if res < 0: if res < 0:
let lastError = osLastError() let lastError = osLastError()
if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}: if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:

View file

@ -14,12 +14,12 @@
## copy; use ``assign`` to get a deep copy. ## copy; use ``assign`` to get a deep copy.
import import
os, hashes, math hashes, math
type type
BitScalar = int BitScalar = int
const const
InitIntSetSize = 8 # must be a power of two! InitIntSetSize = 8 # must be a power of two!
TrunkShift = 9 TrunkShift = 9
BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and
@ -31,11 +31,11 @@ const
type type
PTrunk = ref TTrunk PTrunk = ref TTrunk
TTrunk {.final.} = object TTrunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0 key: int # start address at bit 0
bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector
TTrunkSeq = seq[PTrunk] TTrunkSeq = seq[PTrunk]
IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set
counter, max: int counter, max: int
@ -44,42 +44,42 @@ type
{.deprecated: [TIntSet: IntSet].} {.deprecated: [TIntSet: IntSet].}
proc mustRehash(length, counter: int): bool {.inline.} = proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter) assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4) result = (length * 2 < counter * 3) or (length - counter < 4)
proc nextTry(h, maxHash: THash): THash {.inline.} = proc nextTry(h, maxHash: THash): THash {.inline.} =
result = ((5 * h) + 1) and maxHash result = ((5 * h) + 1) and maxHash
proc intSetGet(t: IntSet, key: int): PTrunk = proc intSetGet(t: IntSet, key: int): PTrunk =
var h = key and t.max var h = key and t.max
while t.data[h] != nil: while t.data[h] != nil:
if t.data[h].key == key: if t.data[h].key == key:
return t.data[h] return t.data[h]
h = nextTry(h, t.max) h = nextTry(h, t.max)
result = nil result = nil
proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) = proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
var h = desc.key and t.max var h = desc.key and t.max
while data[h] != nil: while data[h] != nil:
assert(data[h] != desc) assert(data[h] != desc)
h = nextTry(h, t.max) h = nextTry(h, t.max)
assert(data[h] == nil) assert(data[h] == nil)
data[h] = desc data[h] = desc
proc intSetEnlarge(t: var IntSet) = proc intSetEnlarge(t: var IntSet) =
var n: TTrunkSeq var n: TTrunkSeq
var oldMax = t.max var oldMax = t.max
t.max = ((t.max + 1) * 2) - 1 t.max = ((t.max + 1) * 2) - 1
newSeq(n, t.max + 1) newSeq(n, t.max + 1)
for i in countup(0, oldMax): for i in countup(0, oldMax):
if t.data[i] != nil: intSetRawInsert(t, n, t.data[i]) if t.data[i] != nil: intSetRawInsert(t, n, t.data[i])
swap(t.data, n) swap(t.data, n)
proc intSetPut(t: var IntSet, key: int): PTrunk = proc intSetPut(t: var IntSet, key: int): PTrunk =
var h = key and t.max var h = key and t.max
while t.data[h] != nil: while t.data[h] != nil:
if t.data[h].key == key: if t.data[h].key == key:
return t.data[h] return t.data[h]
h = nextTry(h, t.max) h = nextTry(h, t.max)
if mustRehash(t.max + 1, t.counter): intSetEnlarge(t) if mustRehash(t.max + 1, t.counter): intSetEnlarge(t)
@ -94,43 +94,43 @@ proc intSetPut(t: var IntSet, key: int): PTrunk =
t.data[h] = result t.data[h] = result
proc contains*(s: IntSet, key: int): bool = proc contains*(s: IntSet, key: int): bool =
## returns true iff `key` is in `s`. ## returns true iff `key` is in `s`.
var t = intSetGet(s, `shr`(key, TrunkShift)) var t = intSetGet(s, `shr`(key, TrunkShift))
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0 result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
else: else:
result = false result = false
proc incl*(s: var IntSet, key: int) = proc incl*(s: var IntSet, key: int) =
## includes an element `key` in `s`. ## includes an element `key` in `s`.
var t = intSetPut(s, `shr`(key, TrunkShift)) var t = intSetPut(s, `shr`(key, TrunkShift))
var u = key and TrunkMask var u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask) `shl`(1, u and IntMask)
proc excl*(s: var IntSet, key: int) = proc excl*(s: var IntSet, key: int) =
## excludes `key` from the set `s`. ## excludes `key` from the set `s`.
var t = intSetGet(s, `shr`(key, TrunkShift)) var t = intSetGet(s, `shr`(key, TrunkShift))
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
not `shl`(1, u and IntMask) not `shl`(1, u and IntMask)
proc containsOrIncl*(s: var IntSet, key: int): bool = proc containsOrIncl*(s: var IntSet, key: int): bool =
## returns true if `s` contains `key`, otherwise `key` is included in `s` ## returns true if `s` contains `key`, otherwise `key` is included in `s`
## and false is returned. ## and false is returned.
var t = intSetGet(s, `shr`(key, TrunkShift)) var t = intSetGet(s, `shr`(key, TrunkShift))
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0 result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
if not result: if not result:
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask) `shl`(1, u and IntMask)
else: else:
incl(s, key) incl(s, key)
result = false result = false
proc initIntSet*: IntSet = proc initIntSet*: IntSet =
## creates a new int set that is empty. ## creates a new int set that is empty.
newSeq(result.data, InitIntSetSize) newSeq(result.data, InitIntSetSize)
@ -140,14 +140,14 @@ proc initIntSet*: IntSet =
proc assign*(dest: var IntSet, src: IntSet) = proc assign*(dest: var IntSet, src: IntSet) =
## copies `src` to `dest`. `dest` does not need to be initialized by ## copies `src` to `dest`. `dest` does not need to be initialized by
## `initIntSet`. ## `initIntSet`.
dest.counter = src.counter dest.counter = src.counter
dest.max = src.max dest.max = src.max
newSeq(dest.data, src.data.len) newSeq(dest.data, src.data.len)
var it = src.head var it = src.head
while it != nil: while it != nil:
var h = it.key and dest.max var h = it.key and dest.max
while dest.data[h] != nil: h = nextTry(h, dest.max) while dest.data[h] != nil: h = nextTry(h, dest.max)
assert(dest.data[h] == nil) assert(dest.data[h] == nil)
@ -168,7 +168,7 @@ iterator items*(s: IntSet): int {.inline.} =
while r != nil: while r != nil:
var i = 0 var i = 0
while i <= high(r.bits): while i <= high(r.bits):
var w = r.bits[i] var w = r.bits[i]
# taking a copy of r.bits[i] here is correct, because # taking a copy of r.bits[i] here is correct, because
# modifying operations are not allowed during traversation # modifying operations are not allowed during traversation
var j = 0 var j = 0

View file

@ -114,7 +114,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter) assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4) result = (length * 2 < counter * 3) or (length - counter < 4)
proc rightSize*(count: int): int {.inline.} = proc rightSize*(count: Natural): int {.inline.} =
## Return the value of `initialSize` to support `count` items. ## Return the value of `initialSize` to support `count` items.
## ##
## If more items are expected to be added, simply add that ## If more items are expected to be added, simply add that
@ -798,177 +798,178 @@ proc `==`*[A](s, t: OrderedSet[A]): bool =
g = nxg g = nxg
result = compared == s.counter result = compared == s.counter
proc testModule() = when isMainModule and not defined(release):
## Internal micro test to validate docstrings and such. proc testModule() =
block isValidTest: ## Internal micro test to validate docstrings and such.
var options: HashSet[string] block isValidTest:
proc savePreferences(options: HashSet[string]) = var options: HashSet[string]
assert options.isValid, "Pass an initialized set!" proc savePreferences(options: HashSet[string]) =
options = initSet[string]() assert options.isValid, "Pass an initialized set!"
options.savePreferences options = initSet[string]()
options.savePreferences
block lenTest: block lenTest:
var values: HashSet[int] var values: HashSet[int]
assert(not values.isValid) assert(not values.isValid)
assert values.len == 0 assert values.len == 0
assert values.card == 0 assert values.card == 0
block setIterator: block setIterator:
type pair = tuple[a, b: int] type pair = tuple[a, b: int]
var a, b = initSet[pair]() var a, b = initSet[pair]()
a.incl((2, 3)) a.incl((2, 3))
a.incl((3, 2)) a.incl((3, 2))
a.incl((2, 3)) a.incl((2, 3))
for x, y in a.items: for x, y in a.items:
b.incl((x - 2, y + 1)) b.incl((x - 2, y + 1))
assert a.len == b.card assert a.len == b.card
assert a.len == 2 assert a.len == 2
#echo b #echo b
block setContains: block setContains:
var values = initSet[int]() var values = initSet[int]()
assert(not values.contains(2)) assert(not values.contains(2))
values.incl(2) values.incl(2)
assert values.contains(2) assert values.contains(2)
values.excl(2) values.excl(2)
assert(not values.contains(2)) assert(not values.contains(2))
values.incl(4) values.incl(4)
var others = toSet([6, 7]) var others = toSet([6, 7])
values.incl(others) values.incl(others)
assert values.len == 3 assert values.len == 3
values.init values.init
assert values.containsOrIncl(2) == false assert values.containsOrIncl(2) == false
assert values.containsOrIncl(2) == true assert values.containsOrIncl(2) == true
var var
a = toSet([1, 2]) a = toSet([1, 2])
b = toSet([1]) b = toSet([1])
b.incl(2) b.incl(2)
assert a == b assert a == b
block exclusions: block exclusions:
var s = toSet([2, 3, 6, 7]) var s = toSet([2, 3, 6, 7])
s.excl(2) s.excl(2)
s.excl(2) s.excl(2)
assert s.len == 3 assert s.len == 3
var var
numbers = toSet([1, 2, 3, 4, 5]) numbers = toSet([1, 2, 3, 4, 5])
even = toSet([2, 4, 6, 8]) even = toSet([2, 4, 6, 8])
numbers.excl(even) numbers.excl(even)
#echo numbers #echo numbers
# --> {1, 3, 5} # --> {1, 3, 5}
block toSeqAndString: block toSeqAndString:
var a = toSet([2, 4, 5]) var a = toSet([2, 4, 5])
var b = initSet[int]() var b = initSet[int]()
for x in [2, 4, 5]: b.incl(x) for x in [2, 4, 5]: b.incl(x)
assert($a == $b) assert($a == $b)
#echo a #echo a
#echo toSet(["no", "esc'aping", "is \" provided"]) #echo toSet(["no", "esc'aping", "is \" provided"])
#block orderedToSeqAndString: #block orderedToSeqAndString:
# echo toOrderedSet([2, 4, 5]) # echo toOrderedSet([2, 4, 5])
# echo toOrderedSet(["no", "esc'aping", "is \" provided"]) # echo toOrderedSet(["no", "esc'aping", "is \" provided"])
block setOperations: block setOperations:
var var
a = toSet(["a", "b"]) a = toSet(["a", "b"])
b = toSet(["b", "c"]) b = toSet(["b", "c"])
c = union(a, b) c = union(a, b)
assert c == toSet(["a", "b", "c"]) assert c == toSet(["a", "b", "c"])
var d = intersection(a, b) var d = intersection(a, b)
assert d == toSet(["b"]) assert d == toSet(["b"])
var e = difference(a, b) var e = difference(a, b)
assert e == toSet(["a"]) assert e == toSet(["a"])
var f = symmetricDifference(a, b) var f = symmetricDifference(a, b)
assert f == toSet(["a", "c"]) assert f == toSet(["a", "c"])
assert d < a and d < b assert d < a and d < b
assert((a < a) == false) assert((a < a) == false)
assert d <= a and d <= b assert d <= a and d <= b
assert((a <= a)) assert((a <= a))
# Alias test. # Alias test.
assert a + b == toSet(["a", "b", "c"]) assert a + b == toSet(["a", "b", "c"])
assert a * b == toSet(["b"]) assert a * b == toSet(["b"])
assert a - b == toSet(["a"]) assert a - b == toSet(["a"])
assert a -+- b == toSet(["a", "c"]) assert a -+- b == toSet(["a", "c"])
assert disjoint(a, b) == false assert disjoint(a, b) == false
assert disjoint(a, b - a) == true assert disjoint(a, b - a) == true
block mapSet: block mapSet:
var a = toSet([1, 2, 3]) var a = toSet([1, 2, 3])
var b = a.map(proc (x: int): string = $x) var b = a.map(proc (x: int): string = $x)
assert b == toSet(["1", "2", "3"]) assert b == toSet(["1", "2", "3"])
block isValidTest: block isValidTest:
var cards: OrderedSet[string] var cards: OrderedSet[string]
proc saveTarotCards(cards: OrderedSet[string]) = proc saveTarotCards(cards: OrderedSet[string]) =
assert cards.isValid, "Pass an initialized set!" assert cards.isValid, "Pass an initialized set!"
cards = initOrderedSet[string]() cards = initOrderedSet[string]()
cards.saveTarotCards cards.saveTarotCards
block lenTest: block lenTest:
var values: OrderedSet[int] var values: OrderedSet[int]
assert(not values.isValid) assert(not values.isValid)
assert values.len == 0 assert values.len == 0
assert values.card == 0 assert values.card == 0
block setIterator: block setIterator:
type pair = tuple[a, b: int] type pair = tuple[a, b: int]
var a, b = initOrderedSet[pair]() var a, b = initOrderedSet[pair]()
a.incl((2, 3)) a.incl((2, 3))
a.incl((3, 2)) a.incl((3, 2))
a.incl((2, 3)) a.incl((2, 3))
for x, y in a.items: for x, y in a.items:
b.incl((x - 2, y + 1)) b.incl((x - 2, y + 1))
assert a.len == b.card assert a.len == b.card
assert a.len == 2 assert a.len == 2
#block orderedSetIterator: #block orderedSetIterator:
# var a = initOrderedSet[int]() # var a = initOrderedSet[int]()
# for value in [9, 2, 1, 5, 1, 8, 4, 2]: # for value in [9, 2, 1, 5, 1, 8, 4, 2]:
# a.incl(value) # a.incl(value)
# for value in a.items: # for value in a.items:
# echo "Got ", value # echo "Got ", value
block setContains: block setContains:
var values = initOrderedSet[int]() var values = initOrderedSet[int]()
assert(not values.contains(2)) assert(not values.contains(2))
values.incl(2) values.incl(2)
assert values.contains(2) assert values.contains(2)
block toSeqAndString: block toSeqAndString:
var a = toOrderedSet([2, 4, 5]) var a = toOrderedSet([2, 4, 5])
var b = initOrderedSet[int]() var b = initOrderedSet[int]()
for x in [2, 4, 5]: b.incl(x) for x in [2, 4, 5]: b.incl(x)
assert($a == $b) assert($a == $b)
assert(a == b) # https://github.com/Araq/Nimrod/issues/1413 assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
block initBlocks: block initBlocks:
var a: OrderedSet[int] var a: OrderedSet[int]
a.init(4) a.init(4)
a.incl(2) a.incl(2)
a.init a.init
assert a.len == 0 and a.isValid assert a.len == 0 and a.isValid
a = initOrderedSet[int](4) a = initOrderedSet[int](4)
a.incl(2) a.incl(2)
assert a.len == 1 assert a.len == 1
var b: HashSet[int] var b: HashSet[int]
b.init(4) b.init(4)
b.incl(2) b.incl(2)
b.init b.init
assert b.len == 0 and b.isValid assert b.len == 0 and b.isValid
b = initSet[int](4) b = initSet[int](4)
b.incl(2) b.incl(2)
assert b.len == 1 assert b.len == 1
for i in 0 .. 32: for i in 0 .. 32:
var s = rightSize(i) var s = rightSize(i)
if s <= i or mustRehash(s, i): if s <= i or mustRehash(s, i):
echo "performance issue: rightSize() will not elide enlarge() at ", i echo "performance issue: rightSize() will not elide enlarge() at ", i
echo "Micro tests run successfully." echo "Micro tests run successfully."
when isMainModule and not defined(release): testModule() testModule()

View file

@ -128,7 +128,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
assert(length > counter) assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4) result = (length * 2 < counter * 3) or (length - counter < 4)
proc rightSize*(count: int): int {.inline.} = proc rightSize*(count: Natural): int {.inline.} =
## Return the value of `initialSize` to support `count` items. ## Return the value of `initialSize` to support `count` items.
## ##
## If more items are expected to be added, simply add that ## If more items are expected to be added, simply add that

View file

@ -605,6 +605,49 @@ proc newJArray*(): JsonNode =
result.kind = JArray result.kind = JArray
result.elems = @[] result.elems = @[]
proc getStr*(n: JsonNode, default: string = ""): string =
## Retrieves the string value of a `JString JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JString``.
if n.kind != JString: return default
else: return n.str
proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
## Retrieves the int value of a `JInt JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JInt``.
if n.kind != JInt: return default
else: return n.num
proc getFNum*(n: JsonNode, default: float = 0.0): float =
## Retrieves the float value of a `JFloat JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JFloat``.
if n.kind != JFloat: return default
else: return n.fnum
proc getBVal*(n: JsonNode, default: bool = false): bool =
## Retrieves the bool value of a `JBool JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JBool``.
if n.kind != JBool: return default
else: return n.bval
proc getFields*(n: JsonNode,
default: seq[tuple[key: string, val: JsonNode]] = @[]):
seq[tuple[key: string, val: JsonNode]] =
## Retrieves the key, value pairs of a `JObject JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JObject``.
if n.kind != JObject: return default
else: return n.fields
proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
## Retrieves the int value of a `JArray JsonNode`.
##
## Returns ``default`` if ``n`` is not a ``JArray``.
if n.kind != JArray: return default
else: return n.elems
proc `%`*(s: string): JsonNode = proc `%`*(s: string): JsonNode =
## Generic constructor for JSON data. Creates a new `JString JsonNode`. ## Generic constructor for JSON data. Creates a new `JString JsonNode`.

View file

@ -152,6 +152,7 @@ proc randomize*(seed: int) {.benign.}
## Note: Does nothing for the JavaScript target, ## Note: Does nothing for the JavaScript target,
## as JavaScript does not support this. ## as JavaScript does not support this.
{.push noSideEffect.}
when not defined(JS): when not defined(JS):
proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".} proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
## computes the square root of `x`. ## computes the square root of `x`.
@ -273,6 +274,8 @@ else:
var y = exp(2.0*x) var y = exp(2.0*x)
return (y-1.0)/(y+1.0) return (y-1.0)/(y+1.0)
{.pop.}
proc `mod`*(x, y: float): float = proc `mod`*(x, y: float): float =
result = if y == 0.0: x else: x - y * (x/y).floor result = if y == 0.0: x else: x - y * (x/y).floor
@ -370,3 +373,7 @@ when isMainModule and not defined(JS):
for i in 0..SIZE-1: for i in 0..SIZE-1:
assert buf[i] == random(high(int)), "non deterministic random seeding" assert buf[i] == random(high(int)), "non deterministic random seeding"
echo "random values equal after reseeding" echo "random values equal after reseeding"
# Check for no side effect annotation
proc mySqrt(num: float): float {.noSideEffect.} =
return sqrt(num)

View file

@ -137,7 +137,7 @@ proc startProcess*(command: string,
## `env` is the environment that will be passed to the process. ## `env` is the environment that will be passed to the process.
## If ``env == nil`` the environment is inherited of ## If ``env == nil`` the environment is inherited of
## the parent process. `options` are additional flags that may be passed ## the parent process. `options` are additional flags that may be passed
## to `startProcess`. See the documentation of ``TProcessOption`` for the ## to `startProcess`. See the documentation of ``ProcessOption`` for the
## meaning of these flags. You need to `close` the process when done. ## meaning of these flags. You need to `close` the process when done.
## ##
## Note that you can't pass any `args` if you use the option ## Note that you can't pass any `args` if you use the option

View file

@ -12,6 +12,7 @@
## a denominator `den`, both of type int. The denominator can not be 0. ## a denominator `den`, both of type int. The denominator can not be 0.
import math import math
import hashes
type Rational*[T] = object type Rational*[T] = object
## a rational number, consisting of a numerator and denominator ## a rational number, consisting of a numerator and denominator
@ -32,7 +33,7 @@ proc `$`*[T](x: Rational[T]): string =
## Turn a rational number into a string. ## Turn a rational number into a string.
result = $x.num & "/" & $x.den result = $x.num & "/" & $x.den
proc toRational*[T](x: SomeInteger): Rational[T] = proc toRational*[T](x: T): Rational[T] =
## Convert some integer `x` to a rational number. ## Convert some integer `x` to a rational number.
result.num = x result.num = x
result.den = 1 result.den = 1
@ -188,7 +189,7 @@ proc `/=`*[T](x: var Rational[T], y: T) =
x.den *= y x.den *= y
reduce(x) reduce(x)
proc cmp*(x, y: Rational): int = proc cmp*(x, y: Rational): int {.procvar.} =
## Compares two rationals. ## Compares two rationals.
(x - y).num (x - y).num
@ -205,6 +206,17 @@ proc abs*[T](x: Rational[T]): Rational[T] =
result.num = abs x.num result.num = abs x.num
result.den = abs x.den result.den = abs x.den
proc hash*[T](x: Rational[T]): THash =
## Computes hash for rational `x`
# reduce first so that hash(x) == hash(y) for x == y
var copy = x
reduce(copy)
var h: THash = 0
h = h !& hash(copy.num)
h = h !& hash(copy.den)
result = !$h
when isMainModule: when isMainModule:
var var
z = Rational[int](num: 0, den: 1) z = Rational[int](num: 0, den: 1)
@ -242,11 +254,13 @@ when isMainModule:
assert( not(o > o) ) assert( not(o > o) )
assert( cmp(o, o) == 0 ) assert( cmp(o, o) == 0 )
assert( cmp(z, z) == 0 ) assert( cmp(z, z) == 0 )
assert( hash(o) == hash(o) )
assert( a == b ) assert( a == b )
assert( a >= b ) assert( a >= b )
assert( not(b > a) ) assert( not(b > a) )
assert( cmp(a, b) == 0 ) assert( cmp(a, b) == 0 )
assert( hash(a) == hash(b) )
var x = 1//3 var x = 1//3
@ -270,6 +284,6 @@ when isMainModule:
y /= 9 y /= 9
assert( y == 13//27 ) assert( y == 13//27 )
assert toRational[int, int](5) == 5//1 assert toRational(5) == 5//1
assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
assert toInt(z) == 0 assert toInt(z) == 0

View file

@ -39,6 +39,9 @@ export
SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR, SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR,
MSG_PEEK MSG_PEEK
when defined(macosx):
export SO_NOSIGPIPE
type type
Port* = distinct uint16 ## port type Port* = distinct uint16 ## port type
@ -428,10 +431,6 @@ proc selectWrite*(writefds: var seq[SocketHandle],
pruneSocketSet(writefds, (wr)) pruneSocketSet(writefds, (wr))
# We ignore signal SIGPIPE on Darwin
when defined(macosx):
signal(SIGPIPE, SIG_IGN)
when defined(Windows): when defined(Windows):
var wsa: WSAData var wsa: WSAData
if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError()) if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())

View file

@ -52,9 +52,9 @@ proc len*(a: Rope): int {.rtl, extern: "nro$1".} =
## the rope's length ## the rope's length
if a == nil: result = 0 if a == nil: result = 0
else: result = a.length else: result = a.length
proc newRope(): Rope = new(result) proc newRope(): Rope = new(result)
proc newRope(data: string): Rope = proc newRope(data: string): Rope =
new(result) new(result)
result.length = len(data) result.length = len(data)
result.data = data result.data = data
@ -65,18 +65,18 @@ var
when countCacheMisses: when countCacheMisses:
var misses, hits: int var misses, hits: int
proc splay(s: string, tree: Rope, cmpres: var int): Rope = proc splay(s: string, tree: Rope, cmpres: var int): Rope =
var c: int var c: int
var t = tree var t = tree
N.left = nil N.left = nil
N.right = nil # reset to nil N.right = nil # reset to nil
var le = N var le = N
var r = N var r = N
while true: while true:
c = cmp(s, t.data) c = cmp(s, t.data)
if c < 0: if c < 0:
if (t.left != nil) and (s < t.left.data): if (t.left != nil) and (s < t.left.data):
var y = t.left var y = t.left
t.left = y.right t.left = y.right
y.right = t y.right = t
@ -85,8 +85,8 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
r.left = t r.left = t
r = t r = t
t = t.left t = t.left
elif c > 0: elif c > 0:
if (t.right != nil) and (s > t.right.data): if (t.right != nil) and (s > t.right.data):
var y = t.right var y = t.right
t.right = y.left t.right = y.left
y.left = t y.left = t
@ -95,8 +95,8 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
le.right = t le.right = t
le = t le = t
t = t.right t = t.right
else: else:
break break
cmpres = c cmpres = c
le.right = t.left le.right = t.left
r.left = t.right r.left = t.right
@ -104,50 +104,50 @@ proc splay(s: string, tree: Rope, cmpres: var int): Rope =
t.right = N.left t.right = N.left
result = t result = t
proc insertInCache(s: string, tree: Rope): Rope = proc insertInCache(s: string, tree: Rope): Rope =
var t = tree var t = tree
if t == nil: if t == nil:
result = newRope(s) result = newRope(s)
when countCacheMisses: inc(misses) when countCacheMisses: inc(misses)
return return
var cmp: int var cmp: int
t = splay(s, t, cmp) t = splay(s, t, cmp)
if cmp == 0: if cmp == 0:
# We get here if it's already in the Tree # We get here if it's already in the Tree
# Don't add it again # Don't add it again
result = t result = t
when countCacheMisses: inc(hits) when countCacheMisses: inc(hits)
else: else:
when countCacheMisses: inc(misses) when countCacheMisses: inc(misses)
result = newRope(s) result = newRope(s)
if cmp < 0: if cmp < 0:
result.left = t.left result.left = t.left
result.right = t result.right = t
t.left = nil t.left = nil
else: else:
# i > t.item: # i > t.item:
result.right = t.right result.right = t.right
result.left = t result.left = t
t.right = nil t.right = nil
proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} = proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} =
## Converts a string to a rope. ## Converts a string to a rope.
if s.len == 0: if s.len == 0:
result = nil result = nil
elif cacheEnabled: elif cacheEnabled:
result = insertInCache(s, cache) result = insertInCache(s, cache)
cache = result cache = result
else: else:
result = newRope(s) result = newRope(s)
proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} = proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} =
## Converts an int to a rope. ## Converts an int to a rope.
result = rope($i) result = rope($i)
proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} = proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} =
## Converts a float to a rope. ## Converts a float to a rope.
result = rope($f) result = rope($f)
proc enableCache*() {.rtl, extern: "nro$1".} = proc enableCache*() {.rtl, extern: "nro$1".} =
## Enables the caching of leaves. This reduces the memory footprint at ## Enables the caching of leaves. This reduces the memory footprint at
## the cost of runtime efficiency. ## the cost of runtime efficiency.
@ -160,9 +160,9 @@ proc disableCache*() {.rtl, extern: "nro$1".} =
proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} = proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
## the concatenation operator for ropes. ## the concatenation operator for ropes.
if a == nil: if a == nil:
result = b result = b
elif b == nil: elif b == nil:
result = a result = a
else: else:
result = newRope() result = newRope()
@ -177,16 +177,16 @@ proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
else: else:
result.left = a result.left = a
result.right = b result.right = b
proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} = proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
## the concatenation operator for ropes. ## the concatenation operator for ropes.
result = a & rope(b) result = a & rope(b)
proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} = proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} =
## the concatenation operator for ropes. ## the concatenation operator for ropes.
result = rope(a) & b result = rope(a) & b
proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} = proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} =
## the concatenation operator for an openarray of ropes. ## the concatenation operator for an openarray of ropes.
for i in countup(0, high(a)): result = result & a[i] for i in countup(0, high(a)): result = result & a[i]
@ -219,7 +219,7 @@ iterator leaves*(r: Rope): string =
## iterates over any leaf string in the rope `r`. ## iterates over any leaf string in the rope `r`.
if r != nil: if r != nil:
var stack = @[r] var stack = @[r]
while stack.len > 0: while stack.len > 0:
var it = stack.pop var it = stack.pop
while isConc(it): while isConc(it):
stack.add(it.right) stack.add(it.right)
@ -227,7 +227,7 @@ iterator leaves*(r: Rope): string =
assert(it != nil) assert(it != nil)
assert(it.data != nil) assert(it.data != nil)
yield it.data yield it.data
iterator items*(r: Rope): char = iterator items*(r: Rope): char =
## iterates over any character in the rope `r`. ## iterates over any character in the rope `r`.
for s in leaves(r): for s in leaves(r):
@ -237,7 +237,7 @@ proc write*(f: File, r: Rope) {.rtl, extern: "nro$1".} =
## writes a rope to a file. ## writes a rope to a file.
for s in leaves(r): write(f, s) for s in leaves(r): write(f, s)
proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}= proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}=
## converts a rope back to a string. ## converts a rope back to a string.
result = newString(r.len) result = newString(r.len)
setLen(result, 0) setLen(result, 0)
@ -251,25 +251,25 @@ when false:
new(result) new(result)
result.length = -idx result.length = -idx
proc compileFrmt(frmt: string): Rope = proc compileFrmt(frmt: string): Rope =
var i = 0 var i = 0
var length = len(frmt) var length = len(frmt)
result = nil result = nil
var num = 0 var num = 0
while i < length: while i < length:
if frmt[i] == '$': if frmt[i] == '$':
inc(i) inc(i)
case frmt[i] case frmt[i]
of '$': of '$':
add(result, "$") add(result, "$")
inc(i) inc(i)
of '#': of '#':
inc(i) inc(i)
add(result, compiledArg(num+1)) add(result, compiledArg(num+1))
inc(num) inc(num)
of '0'..'9': of '0'..'9':
var j = 0 var j = 0
while true: while true:
j = j * 10 + ord(frmt[i]) - ord('0') j = j * 10 + ord(frmt[i]) - ord('0')
inc(i) inc(i)
if frmt[i] notin {'0'..'9'}: break if frmt[i] notin {'0'..'9'}: break
@ -285,13 +285,13 @@ when false:
add(s, compiledArg(j)) add(s, compiledArg(j))
else: raise newException(EInvalidValue, "invalid format string") else: raise newException(EInvalidValue, "invalid format string")
var start = i var start = i
while i < length: while i < length:
if frmt[i] != '$': inc(i) if frmt[i] != '$': inc(i)
else: break else: break
if i - 1 >= start: if i - 1 >= start:
add(result, substr(frmt, start, i-1)) add(result, substr(frmt, start, i-1))
proc `%`*(frmt: string, args: openArray[Rope]): Rope {. proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
rtl, extern: "nroFormat".} = rtl, extern: "nroFormat".} =
## `%` substitution operator for ropes. Does not support the ``$identifier`` ## `%` substitution operator for ropes. Does not support the ``$identifier``
## nor ``${identifier}`` notations. ## nor ``${identifier}`` notations.
@ -299,23 +299,23 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
var length = len(frmt) var length = len(frmt)
result = nil result = nil
var num = 0 var num = 0
while i < length: while i < length:
if frmt[i] == '$': if frmt[i] == '$':
inc(i) inc(i)
case frmt[i] case frmt[i]
of '$': of '$':
add(result, "$") add(result, "$")
inc(i) inc(i)
of '#': of '#':
inc(i) inc(i)
add(result, args[num]) add(result, args[num])
inc(num) inc(num)
of '0'..'9': of '0'..'9':
var j = 0 var j = 0
while true: while true:
j = j * 10 + ord(frmt[i]) - ord('0') j = j * 10 + ord(frmt[i]) - ord('0')
inc(i) inc(i)
if frmt[i] notin {'0'..'9'}: break if frmt[i] notin {'0'..'9'}: break
add(result, args[j-1]) add(result, args[j-1])
of '{': of '{':
inc(i) inc(i)
@ -325,13 +325,14 @@ proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
inc(i) inc(i)
if frmt[i] == '}': inc(i) if frmt[i] == '}': inc(i)
else: raise newException(ValueError, "invalid format string") else: raise newException(ValueError, "invalid format string")
add(result, args[j-1]) add(result, args[j-1])
else: raise newException(ValueError, "invalid format string") else: raise newException(ValueError, "invalid format string")
var start = i var start = i
while i < length: while i < length:
if frmt[i] != '$': inc(i) if frmt[i] != '$': inc(i)
else: break else: break
if i - 1 >= start: if i - 1 >= start:
add(result, substr(frmt, start, i - 1)) add(result, substr(frmt, start, i - 1))
proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {. proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
@ -339,29 +340,46 @@ proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
## shortcut for ``add(c, frmt % args)``. ## shortcut for ``add(c, frmt % args)``.
add(c, frmt % args) add(c, frmt % args)
const
bufSize = 1024 # 1 KB is reasonable
proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} = proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} =
## returns true if the contents of the file `f` equal `r`. ## returns true if the contents of the file `f` equal `r`.
var bufSize = 1024 # reasonable start value var
var buf = alloc(bufSize) buf: array[bufSize, char]
for s in leaves(r): bpos = buf.len
if s.len > bufSize: blen = buf.len
bufSize = max(bufSize * 2, s.len)
buf = realloc(buf, bufSize)
var readBytes = readBuffer(f, buf, s.len)
result = readBytes == s.len and equalMem(buf, cstring(s), s.len)
if not result: break
if result:
result = readBuffer(f, buf, 1) == 0 # really at the end of file?
dealloc(buf)
proc equalsFile*(r: Rope, f: string): bool {.rtl, extern: "nro$1Str".} = for s in leaves(r):
var spos = 0
let slen = s.len
while spos < slen:
if bpos == blen:
# Read more data
bpos = 0
blen = readBuffer(f, addr(buf[0]), buf.len)
if blen == 0: # no more data in file
result = false
return
let n = min(blen - bpos, slen - spos)
# TODO There's gotta be a better way of comparing here...
if not equalMem(addr(buf[bpos]),
cast[pointer](cast[int](cstring(s))+spos), n):
result = false
return
spos += n
bpos += n
result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all
proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} =
## returns true if the contents of the file `f` equal `r`. If `f` does not ## returns true if the contents of the file `f` equal `r`. If `f` does not
## exist, false is returned. ## exist, false is returned.
var bin: File var f: File
result = open(bin, f) result = open(f, filename)
if result: if result:
result = equalsFile(r, bin) result = equalsFile(r, f)
close(bin) close(f)
new(N) # init dummy node for splay algorithm new(N) # init dummy node for splay algorithm

View file

@ -386,7 +386,7 @@ proc split*(s: string, sep: string): seq[string] {.noSideEffect,
## `split iterator <#split.i,string,string>`_. ## `split iterator <#split.i,string,string>`_.
accumulateResult(split(s, sep)) accumulateResult(split(s, sep))
proc toHex*(x: BiggestInt, len: int): string {.noSideEffect, proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
rtl, extern: "nsuToHex".} = rtl, extern: "nsuToHex".} =
## Converts `x` to its hexadecimal representation. ## Converts `x` to its hexadecimal representation.
## ##
@ -403,7 +403,7 @@ proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
# handle negative overflow # handle negative overflow
if n == 0 and x < 0: n = -1 if n == 0 and x < 0: n = -1
proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect, proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect,
rtl, extern: "nsuIntToStr".} = rtl, extern: "nsuIntToStr".} =
## Converts `x` to its decimal representation. ## Converts `x` to its decimal representation.
## ##
@ -499,7 +499,7 @@ proc parseEnum*[T: enum](s: string, default: T): T =
return e return e
result = default result = default
proc repeat*(c: char, count: int): string {.noSideEffect, proc repeat*(c: char, count: Natural): string {.noSideEffect,
rtl, extern: "nsuRepeatChar".} = rtl, extern: "nsuRepeatChar".} =
## Returns a string of length `count` consisting only of ## Returns a string of length `count` consisting only of
## the character `c`. You can use this proc to left align strings. Example: ## the character `c`. You can use this proc to left align strings. Example:
@ -514,7 +514,7 @@ proc repeat*(c: char, count: int): string {.noSideEffect,
result = newString(count) result = newString(count)
for i in 0..count-1: result[i] = c for i in 0..count-1: result[i] = c
proc repeat*(s: string, n: int): string {.noSideEffect, proc repeat*(s: string, n: Natural): string {.noSideEffect,
rtl, extern: "nsuRepeatStr".} = rtl, extern: "nsuRepeatStr".} =
## Returns String `s` concatenated `n` times. Example: ## Returns String `s` concatenated `n` times. Example:
## ##
@ -523,7 +523,7 @@ proc repeat*(s: string, n: int): string {.noSideEffect,
result = newStringOfCap(n * s.len) result = newStringOfCap(n * s.len)
for i in 1..n: result.add(s) for i in 1..n: result.add(s)
template spaces*(n: int): string = repeat(' ',n) template spaces*(n: Natural): string = repeat(' ',n)
## Returns a String with `n` space characters. You can use this proc ## Returns a String with `n` space characters. You can use this proc
## to left align strings. Example: ## to left align strings. Example:
## ##
@ -535,15 +535,15 @@ template spaces*(n: int): string = repeat(' ',n)
## echo text1 & spaces(max(0, width - text1.len)) & "|" ## echo text1 & spaces(max(0, width - text1.len)) & "|"
## echo text2 & spaces(max(0, width - text2.len)) & "|" ## echo text2 & spaces(max(0, width - text2.len)) & "|"
proc repeatChar*(count: int, c: char = ' '): string {.deprecated.} = repeat(c, count) proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} = repeat(c, count)
## deprecated: use repeat() or spaces() ## deprecated: use repeat() or spaces()
proc repeatStr*(count: int, s: string): string {.deprecated.} = repeat(s, count) proc repeatStr*(count: Natural, s: string): string {.deprecated.} = repeat(s, count)
## deprecated: use repeat(string, count) or string.repeat(count) ## deprecated: use repeat(string, count) or string.repeat(count)
proc align*(s: string, count: int, padding = ' '): string {. proc align*(s: string, count: Natural, padding = ' '): string {.
noSideEffect, rtl, extern: "nsuAlignString".} = noSideEffect, rtl, extern: "nsuAlignString".} =
## Aligns a string `s` with `padding`, so that is of length `count`. ## Aligns a string `s` with `padding`, so that it is of length `count`.
## ##
## `padding` characters (by default spaces) are added before `s` resulting in ## `padding` characters (by default spaces) are added before `s` resulting in
## right alignment. If ``s.len >= count``, no spaces are added and `s` is ## right alignment. If ``s.len >= count``, no spaces are added and `s` is
@ -682,7 +682,7 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
inc(i) inc(i)
if suffix[i] == '\0': return true if suffix[i] == '\0': return true
proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect, proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
rtl, extern: "nsuContinuesWith".} = rtl, extern: "nsuContinuesWith".} =
## Returns true iff ``s`` continues with ``substr`` at position ``start``. ## Returns true iff ``s`` continues with ``substr`` at position ``start``.
## ##
@ -693,8 +693,8 @@ proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
if s[i+start] != substr[i]: return false if s[i+start] != substr[i]: return false
inc(i) inc(i)
proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect, proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
inline.} = {.noSideEffect, inline.} =
## Adds a separator to `dest` only if its length is bigger than `startLen`. ## Adds a separator to `dest` only if its length is bigger than `startLen`.
## ##
## A shorthand for: ## A shorthand for:
@ -784,7 +784,7 @@ proc findAux(s, sub: string, start: int, a: SkipTable): int =
inc(j, a[s[j+m]]) inc(j, a[s[j+m]])
return -1 return -1
proc find*(s, sub: string, start: int = 0): int {.noSideEffect, proc find*(s, sub: string, start: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindStr".} = rtl, extern: "nsuFindStr".} =
## Searches for `sub` in `s` starting at position `start`. ## Searches for `sub` in `s` starting at position `start`.
## ##
@ -793,7 +793,7 @@ proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
preprocessSub(sub, a) preprocessSub(sub, a)
result = findAux(s, sub, start, a) result = findAux(s, sub, start, a)
proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect, proc find*(s: string, sub: char, start: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindChar".} = rtl, extern: "nsuFindChar".} =
## Searches for `sub` in `s` starting at position `start`. ## Searches for `sub` in `s` starting at position `start`.
## ##
@ -802,7 +802,7 @@ proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect,
if sub == s[i]: return i if sub == s[i]: return i
return -1 return -1
proc find*(s: string, chars: set[char], start: int = 0): int {.noSideEffect, proc find*(s: string, chars: set[char], start: Natural = 0): int {.noSideEffect,
rtl, extern: "nsuFindCharSet".} = rtl, extern: "nsuFindCharSet".} =
## Searches for `chars` in `s` starting at position `start`. ## Searches for `chars` in `s` starting at position `start`.
## ##
@ -933,7 +933,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
var j = findAux(s, sub, i, a) var j = findAux(s, sub, i, a)
if j < 0: break if j < 0: break
# word boundary? # word boundary?
if (j == 0 or s[j-1] notin wordChars) and if (j == 0 or s[j-1] notin wordChars) and
(j+sub.len >= s.len or s[j+sub.len] notin wordChars): (j+sub.len >= s.len or s[j+sub.len] notin wordChars):
add result, substr(s, i, j - 1) add result, substr(s, i, j - 1)
add result, by add result, by
@ -976,7 +976,7 @@ proc parseOctInt*(s: string): int {.noSideEffect,
of '\0': break of '\0': break
else: raise newException(ValueError, "invalid integer: " & s) else: raise newException(ValueError, "invalid integer: " & s)
proc toOct*(x: BiggestInt, len: int): string {.noSideEffect, proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
rtl, extern: "nsuToOct".} = rtl, extern: "nsuToOct".} =
## Converts `x` into its octal representation. ## Converts `x` into its octal representation.
## ##
@ -992,7 +992,7 @@ proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,
shift = shift + 3 shift = shift + 3
mask = mask shl 3 mask = mask shl 3
proc toBin*(x: BiggestInt, len: int): string {.noSideEffect, proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect,
rtl, extern: "nsuToBin".} = rtl, extern: "nsuToBin".} =
## Converts `x` into its binary representation. ## Converts `x` into its binary representation.
## ##
@ -1221,7 +1221,7 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
## of significant digits to be printed. ## of significant digits to be printed.
## `precision`'s default value is the maximum number of meaningful digits ## `precision`'s default value is the maximum number of meaningful digits
## after the decimal point for Nim's ``biggestFloat`` type. ## after the decimal point for Nim's ``biggestFloat`` type.
## ##
## If ``precision == 0``, it tries to format it nicely. ## If ``precision == 0``, it tries to format it nicely.
const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e'] const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e']
var var
@ -1286,7 +1286,7 @@ proc findNormalized(x: string, inArray: openArray[string]): int =
return -1 return -1
proc invalidFormatString() {.noinline.} = proc invalidFormatString() {.noinline.} =
raise newException(ValueError, "invalid format string") raise newException(ValueError, "invalid format string")
proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {. proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
noSideEffect, rtl, extern: "nsuAddf".} = noSideEffect, rtl, extern: "nsuAddf".} =
@ -1416,7 +1416,7 @@ when isMainModule:
doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc"
type MyEnum = enum enA, enB, enC, enuD, enE type MyEnum = enum enA, enB, enC, enuD, enE
doAssert parseEnum[MyEnum]("enu_D") == enuD doAssert parseEnum[MyEnum]("enu_D") == enuD

File diff suppressed because it is too large Load diff

View file

@ -76,6 +76,10 @@ type
void* {.magic: "VoidType".} ## meta type to denote the absence of any type void* {.magic: "VoidType".} ## meta type to denote the absence of any type
auto* = expr auto* = expr
any* = distinct auto any* = distinct auto
untyped* {.magic: Expr.} ## meta type to denote an expression that
## is not resolved (for templates)
typed* {.magic: Stmt.} ## meta type to denote an expression that
## is resolved (for templates)
SomeSignedInt* = int|int8|int16|int32|int64 SomeSignedInt* = int|int8|int16|int32|int64
## type class matching all signed integer types ## type class matching all signed integer types
@ -173,12 +177,6 @@ proc new*(T: typedesc): ref T =
## reference to it as result value ## reference to it as result value
new(result) new(result)
proc unsafeNew*[T](a: var ref T, size: int) {.magic: "New", noSideEffect.}
## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``. This is **unsafe** as it allocates an object
## of the passed ``size``. This should only be used for optimization
## purposes when you know what you're doing!
proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.} proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
## leaked implementation detail. Do not use. ## leaked implementation detail. Do not use.
@ -513,7 +511,13 @@ type
ESynch: Exception ESynch: Exception
].} ].}
proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.} proc unsafeNew*[T](a: var ref T, size: Natural) {.magic: "New", noSideEffect.}
## creates a new object of type ``T`` and returns a safe (traced)
## reference to it in ``a``. This is **unsafe** as it allocates an object
## of the passed ``size``. This should only be used for optimization
## purposes when you know what you're doing!
proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
## returns the size of ``x`` in bytes. Since this is a low-level proc, ## returns the size of ``x`` in bytes. Since this is a low-level proc,
## its usage is discouraged - using ``new`` for the most cases suffices ## its usage is discouraged - using ``new`` for the most cases suffices
## that one never needs to know ``x``'s size. As a special semantic rule, ## that one never needs to know ``x``'s size. As a special semantic rule,
@ -547,7 +551,7 @@ proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.
## 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: Natural) {.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
## efficient since no reallocation is needed. ## efficient since no reallocation is needed.
@ -565,7 +569,7 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
## inputStrings[2] = "would crash" ## inputStrings[2] = "would crash"
## #inputStrings[3] = "out of bounds" ## #inputStrings[3] = "out of bounds"
proc newSeq*[T](len = 0): seq[T] = proc newSeq*[T](len = 0.Natural): seq[T] =
## creates a new sequence of type ``seq[T]`` with length ``len``. ## creates a new sequence of type ``seq[T]`` with length ``len``.
## ##
## Note that the sequence will be filled with zeroed entries, which can be a ## Note that the sequence will be filled with zeroed entries, which can be a
@ -704,6 +708,7 @@ proc `div` *(x, y: int32): int32 {.magic: "DivI", noSideEffect.}
proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.} proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.}
## computes the integer division. This is roughly the same as ## computes the integer division. This is roughly the same as
## ``floor(x/y)``. ## ``floor(x/y)``.
##
## .. code-block:: Nim ## .. code-block:: Nim
## 1 div 2 == 0 ## 1 div 2 == 0
## 2 div 2 == 1 ## 2 div 2 == 1
@ -723,6 +728,7 @@ proc `shr` *(x, y: int16): int16 {.magic: "ShrI", noSideEffect.}
proc `shr` *(x, y: int32): int32 {.magic: "ShrI", noSideEffect.} proc `shr` *(x, y: int32): int32 {.magic: "ShrI", noSideEffect.}
proc `shr` *(x, y: int64): int64 {.magic: "ShrI64", noSideEffect.} proc `shr` *(x, y: int64): int64 {.magic: "ShrI64", noSideEffect.}
## computes the `shift right` operation of `x` and `y`. ## computes the `shift right` operation of `x` and `y`.
##
## .. code-block:: Nim ## .. code-block:: Nim
## 0b0001_0000'i8 shr 2 == 0b0100_0000'i8 ## 0b0001_0000'i8 shr 2 == 0b0100_0000'i8
## 0b1000_0000'i8 shr 2 == 0b0000_0000'i8 ## 0b1000_0000'i8 shr 2 == 0b0000_0000'i8
@ -937,7 +943,7 @@ proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
## 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: Natural) {.
magic: "SetLengthSeq", noSideEffect.} magic: "SetLengthSeq", noSideEffect.}
## sets the length of `s` to `newlen`. ## sets the length of `s` to `newlen`.
## ``T`` may be any sequence type. ## ``T`` may be any sequence type.
@ -945,14 +951,14 @@ proc setLen*[T](s: var seq[T], newlen: int) {.
## ``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: Natural) {.
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: Natural): string {.
magic: "NewString", importc: "mnewString", noSideEffect.} magic: "NewString", importc: "mnewString", noSideEffect.}
## returns a new string of length ``len`` but with uninitialized ## returns a new string of length ``len`` but with uninitialized
## content. One needs to fill the string character after character ## content. One needs to fill the string character after character
@ -960,7 +966,7 @@ proc newString*(len: int): string {.
## optimization purposes; the same effect can be achieved with the ## optimization purposes; the same effect can be achieved with the
## ``&`` operator or with ``add``. ## ``&`` operator or with ``add``.
proc newStringOfCap*(cap: int): string {. proc newStringOfCap*(cap: Natural): 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
@ -1150,21 +1156,21 @@ proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
## 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: Natural) {.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: Natural) {.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.Natural) {.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)
@ -1310,19 +1316,19 @@ proc substr*(s: string, first, last: int): string {.
## or `limit`:idx: a string's length. ## or `limit`:idx: a string's length.
when not defined(nimrodVM): when not defined(nimrodVM):
proc zeroMem*(p: pointer, size: int) {.importc, noDecl, benign.} proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.}
## overwrites the contents of the memory at ``p`` with the value 0. ## overwrites the contents of the memory at ``p`` with the value 0.
## Exactly ``size`` bytes will be overwritten. Like any procedure ## Exactly ``size`` bytes will be overwritten. Like any procedure
## dealing with raw memory this is *unsafe*. ## dealing with raw memory this is *unsafe*.
proc copyMem*(dest, source: pointer, size: int) {. proc copyMem*(dest, source: pointer, size: Natural) {.
importc: "memcpy", header: "<string.h>", benign.} importc: "memcpy", header: "<string.h>", benign.}
## copies the contents from the memory at ``source`` to the memory ## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
## regions may not overlap. Like any procedure dealing with raw ## regions may not overlap. Like any procedure dealing with raw
## memory this is *unsafe*. ## memory this is *unsafe*.
proc moveMem*(dest, source: pointer, size: int) {. proc moveMem*(dest, source: pointer, size: Natural) {.
importc: "memmove", header: "<string.h>", benign.} importc: "memmove", header: "<string.h>", benign.}
## copies the contents from the memory at ``source`` to the memory ## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
@ -1330,7 +1336,7 @@ when not defined(nimrodVM):
## and is thus somewhat more safe than ``copyMem``. Like any procedure ## and is thus somewhat more safe than ``copyMem``. Like any procedure
## dealing with raw memory this is still *unsafe*, though. ## dealing with raw memory this is still *unsafe*, though.
proc equalMem*(a, b: pointer, size: int): bool {. proc equalMem*(a, b: pointer, size: Natural): bool {.
importc: "equalMem", noDecl, noSideEffect.} importc: "equalMem", noDecl, noSideEffect.}
## compares the memory blocks ``a`` and ``b``. ``size`` bytes will ## compares the memory blocks ``a`` and ``b``. ``size`` bytes will
## be compared. If the blocks are equal, true is returned, false ## be compared. If the blocks are equal, true is returned, false
@ -1338,7 +1344,7 @@ when not defined(nimrodVM):
## *unsafe*. ## *unsafe*.
when hostOS != "standalone": when hostOS != "standalone":
proc alloc*(size: int): pointer {.noconv, rtl, tags: [], benign.} proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
## allocates a new memory block with at least ``size`` bytes. The ## allocates a new memory block with at least ``size`` bytes. The
## block has to be freed with ``realloc(block, 0)`` or ## block has to be freed with ``realloc(block, 0)`` or
## ``dealloc(block)``. The block is not initialized, so reading ## ``dealloc(block)``. The block is not initialized, so reading
@ -1353,7 +1359,7 @@ when not defined(nimrodVM):
## The allocated memory belongs to its allocating thread! ## The allocated memory belongs to its allocating thread!
## Use `createSharedU` to allocate from a shared heap. ## Use `createSharedU` to allocate from a shared heap.
cast[ptr T](alloc(T.sizeof * size)) cast[ptr T](alloc(T.sizeof * size))
proc alloc0*(size: int): pointer {.noconv, rtl, tags: [], benign.} proc alloc0*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
## allocates a new memory block with at least ``size`` bytes. The ## allocates a new memory block with at least ``size`` bytes. The
## block has to be freed with ``realloc(block, 0)`` or ## block has to be freed with ``realloc(block, 0)`` or
## ``dealloc(block)``. The block is initialized with all bytes ## ``dealloc(block)``. The block is initialized with all bytes
@ -1368,8 +1374,8 @@ 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: Natural): 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
## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil** ## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
@ -1396,7 +1402,7 @@ when not defined(nimrodVM):
## 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.} =
dealloc(p) dealloc(p)
proc allocShared*(size: int): pointer {.noconv, rtl, benign.} proc allocShared*(size: Natural): 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)``. The block ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
@ -1410,7 +1416,7 @@ when not defined(nimrodVM):
## 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: Natural): 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)``.
@ -1423,8 +1429,8 @@ when not defined(nimrodVM):
## 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: Natural): 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
## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil** ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
@ -2487,37 +2493,37 @@ when not defined(JS): #and not defined(NimrodVM):
proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.} proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
## retrieves the file size (in bytes) of `f`. ## retrieves the file size (in bytes) of `f`.
proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: int): int {. proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {.
tags: [ReadIOEffect], benign.} tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than ## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater. ## `len` (if not as many bytes are remaining), but not greater.
proc readChars*(f: File, a: var openArray[char], start, len: int): int {. proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {.
tags: [ReadIOEffect], benign.} tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than ## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater. ## `len` (if not as many bytes are remaining), but not greater.
proc readBuffer*(f: File, buffer: pointer, len: int): int {. proc readBuffer*(f: File, buffer: pointer, len: Natural): int {.
tags: [ReadIOEffect], benign.} tags: [ReadIOEffect], benign.}
## reads `len` bytes into the buffer pointed to by `buffer`. Returns ## reads `len` bytes into the buffer pointed to by `buffer`. Returns
## the actual number of bytes that have been read which may be less than ## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater. ## `len` (if not as many bytes are remaining), but not greater.
proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: int): int {. proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {.
tags: [WriteIOEffect], benign.} tags: [WriteIOEffect], benign.}
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case ## the number of actual written bytes, which may be less than `len` in case
## of an error. ## of an error.
proc writeChars*(f: File, a: openArray[char], start, len: int): int {. proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {.
tags: [WriteIOEffect], benign.} tags: [WriteIOEffect], benign.}
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case ## the number of actual written bytes, which may be less than `len` in case
## of an error. ## of an error.
proc writeBuffer*(f: File, buffer: pointer, len: int): int {. proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {.
tags: [WriteIOEffect], benign.} tags: [WriteIOEffect], benign.}
## writes the bytes of buffer pointed to by the parameter `buffer` to the ## writes the bytes of buffer pointed to by the parameter `buffer` to the
## file `f`. Returns the number of actual written bytes, which may be less ## file `f`. Returns the number of actual written bytes, which may be less
@ -2539,7 +2545,7 @@ when not defined(JS): #and not defined(NimrodVM):
when not defined(nimfix): when not defined(nimfix):
{.deprecated: [fileHandle: getFileHandle].} {.deprecated: [fileHandle: getFileHandle].}
proc cstringArrayToSeq*(a: cstringArray, len: int): seq[string] = proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be ## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
## of length ``len``. ## of length ``len``.
newSeq(result, len) newSeq(result, len)
@ -2809,14 +2815,14 @@ elif defined(JS):
proc getTotalMem(): int = return -1 proc getTotalMem(): int = return -1
proc dealloc(p: pointer) = discard proc dealloc(p: pointer) = discard
proc alloc(size: int): pointer = discard proc alloc(size: Natural): pointer = discard
proc alloc0(size: int): pointer = discard proc alloc0(size: Natural): pointer = discard
proc realloc(p: pointer, newsize: int): pointer = discard proc realloc(p: pointer, newsize: Natural): pointer = discard
proc allocShared(size: int): pointer = discard proc allocShared(size: Natural): pointer = discard
proc allocShared0(size: int): pointer = discard proc allocShared0(size: Natural): pointer = discard
proc deallocShared(p: pointer) = discard proc deallocShared(p: pointer) = discard
proc reallocShared(p: pointer, newsize: int): pointer = discard proc reallocShared(p: pointer, newsize: Natural): pointer = discard
when defined(JS): when defined(JS):
include "system/jssys" include "system/jssys"
@ -3028,8 +3034,8 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[
## result = a[pos] ## result = a[pos]
## ##
## when isMainModule: ## when isMainModule:
## testException(EInvalidIndex, tester(30)) ## testException(IndexError, tester(30))
## testException(EInvalidIndex, tester(1)) ## testException(IndexError, tester(1))
## # --> Test failure at example.nim:20 with 'tester(1)' ## # --> Test failure at example.nim:20 with 'tester(1)'
template currentSourcePath*: string = instantiationInfo(-1, true).filename template currentSourcePath*: string = instantiationInfo(-1, true).filename
@ -3038,13 +3044,12 @@ template currentSourcePath*: string = instantiationInfo(-1, true).filename
proc raiseAssert*(msg: string) {.noinline.} = proc raiseAssert*(msg: string) {.noinline.} =
sysFatal(AssertionError, msg) sysFatal(AssertionError, msg)
when true: proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = # trick the compiler to not list ``AssertionError`` when called
# trick the compiler to not list ``EAssertionFailed`` when called # by ``assert``.
# by ``assert``. type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
type THide = proc (msg: string) {.noinline, raises: [], noSideEffect, tags: [].}
tags: [].} THide(raiseAssert)(msg)
THide(raiseAssert)(msg)
template assert*(cond: bool, msg = "") = template assert*(cond: bool, msg = "") =
## Raises ``AssertionError`` with `msg` if `cond` is false. Note ## Raises ``AssertionError`` with `msg` if `cond` is false. Note
@ -3109,24 +3114,18 @@ when not defined(nimhygiene):
template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} = 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 module scope.
## Can be defined multiple times in a single function.
## ##
## .. code-block:: nim ## .. code-block:: nim
## # module-wide policy to change the failed assert
## # exception type in order to include a lineinfo
## onFailedAssert(msg):
## var e = new(TMyError)
## e.msg = msg
## e.lineinfo = instantiationInfo(-2)
## raise e
## ##
## proc example(x: int): TErrorCode = template failedAssertImpl(msgIMPL: string): stmt {.dirty.} =
## onFailedAssert(msg):
## log msg
## return E_FAIL
##
## assert(...)
##
## onFailedAssert(msg):
## raise newException(EMyException, msg)
##
## assert(...)
##
template failedAssertImpl(msgIMPL: string): stmt {.dirty, immediate.} =
let msg = msgIMPL let msg = msgIMPL
code code
@ -3162,7 +3161,7 @@ when false:
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.Natural) {.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)

View file

@ -8,7 +8,7 @@
# #
# Low level allocator for Nim. Has been designed to support the GC. # Low level allocator for Nim. Has been designed to support the GC.
# TODO: # TODO:
# - eliminate "used" field # - eliminate "used" field
# - make searching for block O(1) # - make searching for block O(1)
{.push profiler:off.} {.push profiler:off.}
@ -21,37 +21,37 @@
# used with a size of 0: # used with a size of 0:
const weirdUnmap = not (defined(amd64) or defined(i386)) or defined(windows) const weirdUnmap = not (defined(amd64) or defined(i386)) or defined(windows)
when defined(posix): when defined(posix):
const const
PROT_READ = 1 # page can be read PROT_READ = 1 # page can be read
PROT_WRITE = 2 # page can be written PROT_WRITE = 2 # page can be written
MAP_PRIVATE = 2'i32 # Changes are private MAP_PRIVATE = 2'i32 # Changes are private
when defined(macosx) or defined(bsd): when defined(macosx) or defined(bsd):
const MAP_ANONYMOUS = 0x1000 const MAP_ANONYMOUS = 0x1000
elif defined(solaris): elif defined(solaris):
const MAP_ANONYMOUS = 0x100 const MAP_ANONYMOUS = 0x100
else: else:
var var
MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint
proc mmap(adr: pointer, len: int, prot, flags, fildes: cint, proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
off: int): pointer {.header: "<sys/mman.h>".} off: int): pointer {.header: "<sys/mman.h>".}
proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".} proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".}
proc osAllocPages(size: int): pointer {.inline.} = proc osAllocPages(size: int): pointer {.inline.} =
result = mmap(nil, size, PROT_READ or PROT_WRITE, result = mmap(nil, size, PROT_READ or PROT_WRITE,
MAP_PRIVATE or MAP_ANONYMOUS, -1, 0) MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
if result == nil or result == cast[pointer](-1): if result == nil or result == cast[pointer](-1):
raiseOutOfMem() raiseOutOfMem()
proc osDeallocPages(p: pointer, size: int) {.inline} = proc osDeallocPages(p: pointer, size: int) {.inline} =
when reallyOsDealloc: munmap(p, size) when reallyOsDealloc: munmap(p, size)
elif defined(windows): elif defined(windows):
const const
MEM_RESERVE = 0x2000 MEM_RESERVE = 0x2000
MEM_COMMIT = 0x1000 MEM_COMMIT = 0x1000
MEM_TOP_DOWN = 0x100000 MEM_TOP_DOWN = 0x100000
PAGE_READWRITE = 0x04 PAGE_READWRITE = 0x04
@ -62,12 +62,12 @@ elif defined(windows):
proc virtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType, proc virtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
flProtect: int32): pointer {. flProtect: int32): pointer {.
header: "<windows.h>", stdcall, importc: "VirtualAlloc".} header: "<windows.h>", stdcall, importc: "VirtualAlloc".}
proc virtualFree(lpAddress: pointer, dwSize: int, proc virtualFree(lpAddress: pointer, dwSize: int,
dwFreeType: int32) {.header: "<windows.h>", stdcall, dwFreeType: int32) {.header: "<windows.h>", stdcall,
importc: "VirtualFree".} importc: "VirtualFree".}
proc osAllocPages(size: int): pointer {.inline.} = proc osAllocPages(size: int): pointer {.inline.} =
result = virtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT, result = virtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT,
PAGE_READWRITE) PAGE_READWRITE)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
@ -82,7 +82,7 @@ elif defined(windows):
when reallyOsDealloc: virtualFree(p, 0, MEM_RELEASE) when reallyOsDealloc: virtualFree(p, 0, MEM_RELEASE)
#VirtualFree(p, size, MEM_DECOMMIT) #VirtualFree(p, size, MEM_DECOMMIT)
else: else:
{.error: "Port memory manager to your platform".} {.error: "Port memory manager to your platform".}
# --------------------- end of non-portable code ----------------------------- # --------------------- end of non-portable code -----------------------------
@ -97,17 +97,17 @@ const
InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn! InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn!
SmallChunkSize = PageSize SmallChunkSize = PageSize
type type
PTrunk = ptr TTrunk PTrunk = ptr TTrunk
TTrunk {.final.} = object TTrunk {.final.} = object
next: PTrunk # all nodes are connected with this pointer next: PTrunk # all nodes are connected with this pointer
key: int # start address at bit 0 key: int # start address at bit 0
bits: array[0..IntsPerTrunk-1, int] # a bit vector bits: array[0..IntsPerTrunk-1, int] # a bit vector
TTrunkBuckets = array[0..255, PTrunk] TTrunkBuckets = array[0..255, PTrunk]
TIntSet {.final.} = object TIntSet {.final.} = object
data: TTrunkBuckets data: TTrunkBuckets
type type
TAlignType = BiggestFloat TAlignType = BiggestFloat
TFreeCell {.final, pure.} = object TFreeCell {.final, pure.} = object
@ -123,14 +123,14 @@ type
prevSize: int # size of previous chunk; for coalescing prevSize: int # size of previous chunk; for coalescing
size: int # if < PageSize it is a small chunk size: int # if < PageSize it is a small chunk
used: bool # later will be optimized into prevSize... used: bool # later will be optimized into prevSize...
TSmallChunk = object of TBaseChunk TSmallChunk = object of TBaseChunk
next, prev: PSmallChunk # chunks of the same size next, prev: PSmallChunk # chunks of the same size
freeList: ptr TFreeCell freeList: ptr TFreeCell
free: int # how many bytes remain free: int # how many bytes remain
acc: int # accumulator for small object allocation acc: int # accumulator for small object allocation
data: TAlignType # start of usable memory data: TAlignType # start of usable memory
TBigChunk = object of TBaseChunk # not necessarily > PageSize! TBigChunk = object of TBaseChunk # not necessarily > PageSize!
next, prev: PBigChunk # chunks of the same (or bigger) size next, prev: PBigChunk # chunks of the same (or bigger) size
align: int align: int
@ -139,7 +139,7 @@ type
template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType) template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType)
template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType) template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType)
proc roundup(x, v: int): int {.inline.} = proc roundup(x, v: int): int {.inline.} =
result = (x + (v-1)) and not (v-1) result = (x + (v-1)) and not (v-1)
sysAssert(result >= x, "roundup: result < x") sysAssert(result >= x, "roundup: result < x")
#return ((-x) and (v-1)) +% x #return ((-x) and (v-1)) +% x
@ -153,7 +153,7 @@ sysAssert(roundup(65, 8) == 72, "roundup broken 2")
# endings of big chunks. This is needed by the merging operation. The only # endings of big chunks. This is needed by the merging operation. The only
# remaining operation is best-fit for big chunks. Since there is a size-limit # remaining operation is best-fit for big chunks. Since there is a size-limit
# for big chunks (because greater than the limit means they are returned back # for big chunks (because greater than the limit means they are returned back
# to the OS), a fixed size array can be used. # to the OS), a fixed size array can be used.
type type
PLLChunk = ptr TLLChunk PLLChunk = ptr TLLChunk
@ -163,21 +163,21 @@ type
next: PLLChunk # next low-level chunk; only needed for dealloc next: PLLChunk # next low-level chunk; only needed for dealloc
PAvlNode = ptr TAvlNode PAvlNode = ptr TAvlNode
TAvlNode {.pure, final.} = object TAvlNode {.pure, final.} = object
link: array[0..1, PAvlNode] # Left (0) and right (1) links link: array[0..1, PAvlNode] # Left (0) and right (1) links
key, upperBound: int key, upperBound: int
level: int level: int
TMemRegion {.final, pure.} = object TMemRegion {.final, pure.} = object
minLargeObj, maxLargeObj: int minLargeObj, maxLargeObj: int
freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk] freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
llmem: PLLChunk llmem: PLLChunk
currMem, maxMem, freeMem: int # memory sizes (allocated from OS) currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
lastSize: int # needed for the case that OS gives us pages linearly lastSize: int # needed for the case that OS gives us pages linearly
freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
chunkStarts: TIntSet chunkStarts: TIntSet
root, deleted, last, freeAvlNodes: PAvlNode root, deleted, last, freeAvlNodes: PAvlNode
# shared: # shared:
var var
bottomData: TAvlNode bottomData: TAvlNode
@ -191,7 +191,7 @@ proc initAllocator() =
bottom.link[1] = bottom bottom.link[1] = bottom
{.pop.} {.pop.}
proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} = proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
inc(a.currMem, bytes) inc(a.currMem, bytes)
proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} = proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
@ -199,11 +199,11 @@ proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
dec(a.currMem, bytes) dec(a.currMem, bytes)
proc getMaxMem(a: var TMemRegion): int = proc getMaxMem(a: var TMemRegion): int =
# Since we update maxPagesCount only when freeing pages, # Since we update maxPagesCount only when freeing pages,
# maxPagesCount may not be up to date. Thus we use the # maxPagesCount may not be up to date. Thus we use the
# maximum of these both values here: # maximum of these both values here:
result = max(a.currMem, a.maxMem) result = max(a.currMem, a.maxMem)
proc llAlloc(a: var TMemRegion, size: int): pointer = proc llAlloc(a: var TMemRegion, size: int): pointer =
# *low-level* alloc for the memory managers data structures. Deallocation # *low-level* alloc for the memory managers data structures. Deallocation
# is done at he end of the allocator's life time. # is done at he end of the allocator's life time.
@ -251,15 +251,15 @@ proc llDeallocAll(a: var TMemRegion) =
var next = it.next var next = it.next
osDeallocPages(it, PageSize) osDeallocPages(it, PageSize)
it = next it = next
proc intSetGet(t: TIntSet, key: int): PTrunk = proc intSetGet(t: TIntSet, key: int): PTrunk =
var it = t.data[key and high(t.data)] var it = t.data[key and high(t.data)]
while it != nil: while it != nil:
if it.key == key: return it if it.key == key: return it
it = it.next it = it.next
result = nil result = nil
proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk = proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
result = intSetGet(t, key) result = intSetGet(t, key)
if result == nil: if result == nil:
result = cast[PTrunk](llAlloc(a, sizeof(result[]))) result = cast[PTrunk](llAlloc(a, sizeof(result[])))
@ -267,20 +267,20 @@ proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
t.data[key and high(t.data)] = result t.data[key and high(t.data)] = result
result.key = key result.key = key
proc contains(s: TIntSet, key: int): bool = proc contains(s: TIntSet, key: int): bool =
var t = intSetGet(s, key shr TrunkShift) var t = intSetGet(s, key shr TrunkShift)
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0 result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
else: else:
result = false result = false
proc incl(a: var TMemRegion, s: var TIntSet, key: int) = proc incl(a: var TMemRegion, s: var TIntSet, key: int) =
var t = intSetPut(a, s, key shr TrunkShift) var t = intSetPut(a, s, key shr TrunkShift)
var u = key and TrunkMask var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask)) t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
proc excl(s: var TIntSet, key: int) = proc excl(s: var TIntSet, key: int) =
var t = intSetGet(s, key shr TrunkShift) var t = intSetGet(s, key shr TrunkShift)
if t != nil: if t != nil:
var u = key and TrunkMask var u = key and TrunkMask
@ -304,11 +304,11 @@ iterator elements(t: TIntSet): int {.inline.} =
w = w shr 1 w = w shr 1
inc(i) inc(i)
r = r.next r = r.next
proc isSmallChunk(c: PChunk): bool {.inline.} = proc isSmallChunk(c: PChunk): bool {.inline.} =
return c.size <= SmallChunkSize-smallChunkOverhead() return c.size <= SmallChunkSize-smallChunkOverhead()
proc chunkUnused(c: PChunk): bool {.inline.} = proc chunkUnused(c: PChunk): bool {.inline.} =
result = not c.used result = not c.used
iterator allObjects(m: TMemRegion): pointer {.inline.} = iterator allObjects(m: TMemRegion): pointer {.inline.} =
@ -319,7 +319,7 @@ iterator allObjects(m: TMemRegion): pointer {.inline.} =
if not chunkUnused(c): if not chunkUnused(c):
if isSmallChunk(c): if isSmallChunk(c):
var c = cast[PSmallChunk](c) var c = cast[PSmallChunk](c)
let size = c.size let size = c.size
var a = cast[ByteAddress](addr(c.data)) var a = cast[ByteAddress](addr(c.data))
let limit = a + c.acc let limit = a + c.acc
@ -334,17 +334,17 @@ proc isCell(p: pointer): bool {.inline.} =
result = cast[ptr TFreeCell](p).zeroField >% 1 result = cast[ptr TFreeCell](p).zeroField >% 1
# ------------- chunk management ---------------------------------------------- # ------------- chunk management ----------------------------------------------
proc pageIndex(c: PChunk): int {.inline.} = proc pageIndex(c: PChunk): int {.inline.} =
result = cast[ByteAddress](c) shr PageShift result = cast[ByteAddress](c) shr PageShift
proc pageIndex(p: pointer): int {.inline.} = proc pageIndex(p: pointer): int {.inline.} =
result = cast[ByteAddress](p) shr PageShift result = cast[ByteAddress](p) shr PageShift
proc pageAddr(p: pointer): PChunk {.inline.} = proc pageAddr(p: pointer): PChunk {.inline.} =
result = cast[PChunk](cast[ByteAddress](p) and not PageMask) result = cast[PChunk](cast[ByteAddress](p) and not PageMask)
#sysAssert(Contains(allocator.chunkStarts, pageIndex(result))) #sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk = proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
incCurrMem(a, size) incCurrMem(a, size)
inc(a.freeMem, size) inc(a.freeMem, size)
result = cast[PBigChunk](osAllocPages(size)) result = cast[PBigChunk](osAllocPages(size))
@ -373,7 +373,7 @@ proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
result.prevSize = 0 # unknown result.prevSize = 0 # unknown
a.lastSize = size # for next request a.lastSize = size # for next request
proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) = proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
# update next.prevSize: # update next.prevSize:
var c = cast[PChunk](p) var c = cast[PChunk](p)
var nxt = cast[ByteAddress](p) +% c.size var nxt = cast[ByteAddress](p) +% c.size
@ -387,36 +387,36 @@ proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
dec(a.freeMem, size) dec(a.freeMem, size)
#c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size) #c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} = proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} =
result = contains(a.chunkStarts, pageIndex(p)) result = contains(a.chunkStarts, pageIndex(p))
proc contains[T](list, x: T): bool = proc contains[T](list, x: T): bool =
var it = list var it = list
while it != nil: while it != nil:
if it == x: return true if it == x: return true
it = it.next it = it.next
proc writeFreeList(a: TMemRegion) = proc writeFreeList(a: TMemRegion) =
var it = a.freeChunksList var it = a.freeChunksList
c_fprintf(c_stdout, "freeChunksList: %p\n", it) c_fprintf(c_stdout, "freeChunksList: %p\n", it)
while it != nil: while it != nil:
c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n", c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n",
it, it.next, it.prev) it, it.next, it.prev)
it = it.next it = it.next
proc listAdd[T](head: var T, c: T) {.inline.} = proc listAdd[T](head: var T, c: T) {.inline.} =
sysAssert(c notin head, "listAdd 1") sysAssert(c notin head, "listAdd 1")
sysAssert c.prev == nil, "listAdd 2" sysAssert c.prev == nil, "listAdd 2"
sysAssert c.next == nil, "listAdd 3" sysAssert c.next == nil, "listAdd 3"
c.next = head c.next = head
if head != nil: if head != nil:
sysAssert head.prev == nil, "listAdd 4" sysAssert head.prev == nil, "listAdd 4"
head.prev = c head.prev = c
head = c head = c
proc listRemove[T](head: var T, c: T) {.inline.} = proc listRemove[T](head: var T, c: T) {.inline.} =
sysAssert(c in head, "listRemove") sysAssert(c in head, "listRemove")
if c == head: if c == head:
head = c.next head = c.next
sysAssert c.prev == nil, "listRemove 2" sysAssert c.prev == nil, "listRemove 2"
if head != nil: head.prev = nil if head != nil: head.prev = nil
@ -426,15 +426,15 @@ proc listRemove[T](head: var T, c: T) {.inline.} =
if c.next != nil: c.next.prev = c.prev if c.next != nil: c.next.prev = c.prev
c.next = nil c.next = nil
c.prev = nil c.prev = nil
proc updatePrevSize(a: var TMemRegion, c: PBigChunk, proc updatePrevSize(a: var TMemRegion, c: PBigChunk,
prevSize: int) {.inline.} = prevSize: int) {.inline.} =
var ri = cast[PChunk](cast[ByteAddress](c) +% c.size) var ri = cast[PChunk](cast[ByteAddress](c) +% c.size)
sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize") sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize")
if isAccessible(a, ri): if isAccessible(a, ri):
ri.prevSize = prevSize ri.prevSize = prevSize
proc freeBigChunk(a: var TMemRegion, c: PBigChunk) = proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
var c = c var c = c
sysAssert(c.size >= PageSize, "freeBigChunk") sysAssert(c.size >= PageSize, "freeBigChunk")
inc(a.freeMem, c.size) inc(a.freeMem, c.size)
@ -448,7 +448,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
inc(c.size, ri.size) inc(c.size, ri.size)
excl(a.chunkStarts, pageIndex(ri)) excl(a.chunkStarts, pageIndex(ri))
when coalescLeft: when coalescLeft:
if c.prevSize != 0: if c.prevSize != 0:
var le = cast[PChunk](cast[ByteAddress](c) -% c.prevSize) var le = cast[PChunk](cast[ByteAddress](c) -% c.prevSize)
sysAssert((cast[ByteAddress](le) and PageMask) == 0, "freeBigChunk 4") sysAssert((cast[ByteAddress](le) and PageMask) == 0, "freeBigChunk 4")
if isAccessible(a, le) and chunkUnused(le): if isAccessible(a, le) and chunkUnused(le):
@ -467,7 +467,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
else: else:
freeOsChunks(a, c, c.size) freeOsChunks(a, c, c.size)
proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) = proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
var rest = cast[PBigChunk](cast[ByteAddress](c) +% size) var rest = cast[PBigChunk](cast[ByteAddress](c) +% size)
sysAssert(rest notin a.freeChunksList, "splitChunk") sysAssert(rest notin a.freeChunksList, "splitChunk")
rest.size = c.size - size rest.size = c.size - size
@ -480,7 +480,7 @@ proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
incl(a, a.chunkStarts, pageIndex(rest)) incl(a, a.chunkStarts, pageIndex(rest))
listAdd(a.freeChunksList, rest) listAdd(a.freeChunksList, rest)
proc getBigChunk(a: var TMemRegion, size: int): PBigChunk = proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
# use first fit for now: # use first fit for now:
sysAssert((size and PageMask) == 0, "getBigChunk 1") sysAssert((size and PageMask) == 0, "getBigChunk 1")
sysAssert(size > 0, "getBigChunk 2") sysAssert(size > 0, "getBigChunk 2")
@ -488,7 +488,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
block search: block search:
while result != nil: while result != nil:
sysAssert chunkUnused(result), "getBigChunk 3" sysAssert chunkUnused(result), "getBigChunk 3"
if result.size == size: if result.size == size:
listRemove(a.freeChunksList, result) listRemove(a.freeChunksList, result)
break search break search
elif result.size > size: elif result.size > size:
@ -497,7 +497,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
break search break search
result = result.next result = result.next
sysAssert result != a.freeChunksList, "getBigChunk 4" sysAssert result != a.freeChunksList, "getBigChunk 4"
if size < InitialMemoryRequest: if size < InitialMemoryRequest:
result = requestOsChunks(a, InitialMemoryRequest) result = requestOsChunks(a, InitialMemoryRequest)
splitChunk(a, result, size) splitChunk(a, result, size)
else: else:
@ -507,7 +507,7 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
incl(a, a.chunkStarts, pageIndex(result)) incl(a, a.chunkStarts, pageIndex(result))
dec(a.freeMem, size) dec(a.freeMem, size)
proc getSmallChunk(a: var TMemRegion): PSmallChunk = proc getSmallChunk(a: var TMemRegion): PSmallChunk =
var res = getBigChunk(a, PageSize) var res = getBigChunk(a, PageSize)
sysAssert res.prev == nil, "getSmallChunk 1" sysAssert res.prev == nil, "getSmallChunk 1"
sysAssert res.next == nil, "getSmallChunk 2" sysAssert res.next == nil, "getSmallChunk 2"
@ -521,15 +521,15 @@ proc allocInv(a: TMemRegion): bool =
for s in low(a.freeSmallChunks)..high(a.freeSmallChunks): for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
var c = a.freeSmallChunks[s] var c = a.freeSmallChunks[s]
while c != nil: while c != nil:
if c.next == c: if c.next == c:
echo "[SYSASSERT] c.next == c" echo "[SYSASSERT] c.next == c"
return false return false
if c.size != s * MemAlign: if c.size != s * MemAlign:
echo "[SYSASSERT] c.size != s * MemAlign" echo "[SYSASSERT] c.size != s * MemAlign"
return false return false
var it = c.freeList var it = c.freeList
while it != nil: while it != nil:
if it.zeroField != 0: if it.zeroField != 0:
echo "[SYSASSERT] it.zeroField != 0" echo "[SYSASSERT] it.zeroField != 0"
c_printf("%ld %p\n", it.zeroField, it) c_printf("%ld %p\n", it.zeroField, it)
return false return false
@ -539,16 +539,16 @@ proc allocInv(a: TMemRegion): bool =
proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer = proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
sysAssert(allocInv(a), "rawAlloc: begin") sysAssert(allocInv(a), "rawAlloc: begin")
sysAssert(roundup(65, 8) == 72, "rawAlloc 1") sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
sysAssert requestedSize >= sizeof(TFreeCell), "rawAlloc 2" sysAssert(requestedSize >= sizeof(TFreeCell), "rawAlloc: requested size too small")
var size = roundup(requestedSize, MemAlign) var size = roundup(requestedSize, MemAlign)
sysAssert(size >= requestedSize, "insufficient allocated size!") sysAssert(size >= requestedSize, "insufficient allocated size!")
#c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size) #c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
if size <= SmallChunkSize-smallChunkOverhead(): if size <= SmallChunkSize-smallChunkOverhead():
# allocate a small block: for small chunks, we use only its next pointer # allocate a small block: for small chunks, we use only its next pointer
var s = size div MemAlign var s = size div MemAlign
var c = a.freeSmallChunks[s] var c = a.freeSmallChunks[s]
if c == nil: if c == nil:
c = getSmallChunk(a) c = getSmallChunk(a)
c.freeList = nil c.freeList = nil
sysAssert c.size == PageSize, "rawAlloc 3" sysAssert c.size == PageSize, "rawAlloc 3"
@ -567,7 +567,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
# c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size) # c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size)
sysAssert c.size == size, "rawAlloc 6" sysAssert c.size == size, "rawAlloc 6"
if c.freeList == nil: if c.freeList == nil:
sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize, sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize,
"rawAlloc 7") "rawAlloc 7")
result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc) result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc)
inc(c.acc, size) inc(c.acc, size)
@ -621,9 +621,9 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
f.zeroField = 0 f.zeroField = 0
f.next = c.freeList f.next = c.freeList
c.freeList = f c.freeList = f
when overwriteFree: when overwriteFree:
# set to 0xff to check for usage after free bugs: # set to 0xff to check for usage after free bugs:
c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32, c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32,
s -% sizeof(TFreeCell)) s -% sizeof(TFreeCell))
# check if it is not in the freeSmallChunks[s] list: # check if it is not in the freeSmallChunks[s] list:
if c.free < s: if c.free < s:
@ -649,13 +649,13 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
sysAssert(allocInv(a), "rawDealloc: end") sysAssert(allocInv(a), "rawDealloc: end")
when logAlloc: cprintf("rawDealloc: %p\n", p) when logAlloc: cprintf("rawDealloc: %p\n", p)
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool = proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
if isAccessible(a, p): if isAccessible(a, p):
var c = pageAddr(p) var c = pageAddr(p)
if not chunkUnused(c): if not chunkUnused(c):
if isSmallChunk(c): if isSmallChunk(c):
var c = cast[PSmallChunk](c) var c = cast[PSmallChunk](c)
var offset = (cast[ByteAddress](p) and (PageSize-1)) -% var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
smallChunkOverhead() smallChunkOverhead()
result = (c.acc >% offset) and (offset %% c.size == 0) and result = (c.acc >% offset) and (offset %% c.size == 0) and
(cast[ptr TFreeCell](p).zeroField >% 1) (cast[ptr TFreeCell](p).zeroField >% 1)
@ -673,12 +673,12 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
if not chunkUnused(c): if not chunkUnused(c):
if isSmallChunk(c): if isSmallChunk(c):
var c = cast[PSmallChunk](c) var c = cast[PSmallChunk](c)
var offset = (cast[ByteAddress](p) and (PageSize-1)) -% var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
smallChunkOverhead() smallChunkOverhead()
if c.acc >% offset: if c.acc >% offset:
sysAssert(cast[ByteAddress](addr(c.data)) +% offset == sysAssert(cast[ByteAddress](addr(c.data)) +% offset ==
cast[ByteAddress](p), "offset is not what you think it is") cast[ByteAddress](p), "offset is not what you think it is")
var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +% var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +%
offset -% (offset %% c.size)) offset -% (offset %% c.size))
if d.zeroField >% 1: if d.zeroField >% 1:
result = d result = d
@ -711,13 +711,13 @@ proc ptrSize(p: pointer): int =
if not isSmallChunk(c): if not isSmallChunk(c):
dec result, bigChunkOverhead() dec result, bigChunkOverhead()
proc alloc(allocator: var TMemRegion, size: int): pointer = proc alloc(allocator: var TMemRegion, size: Natural): pointer =
result = rawAlloc(allocator, size+sizeof(TFreeCell)) result = rawAlloc(allocator, size+sizeof(TFreeCell))
cast[ptr TFreeCell](result).zeroField = 1 # mark it as used cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
sysAssert(not isAllocatedPtr(allocator, result), "alloc") sysAssert(not isAllocatedPtr(allocator, result), "alloc")
result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell)) result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell))
proc alloc0(allocator: var TMemRegion, size: int): pointer = proc alloc0(allocator: var TMemRegion, size: Natural): pointer =
result = alloc(allocator, size) result = alloc(allocator, size)
zeroMem(result, size) zeroMem(result, size)
@ -730,7 +730,7 @@ proc dealloc(allocator: var TMemRegion, p: pointer) =
rawDealloc(allocator, x) rawDealloc(allocator, x)
sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3") sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3")
proc realloc(allocator: var TMemRegion, p: pointer, newsize: int): pointer = proc realloc(allocator: var TMemRegion, p: pointer, newsize: Natural): pointer =
if newsize > 0: if newsize > 0:
result = alloc0(allocator, newsize) result = alloc0(allocator, newsize)
if p != nil: if p != nil:
@ -758,7 +758,7 @@ proc deallocOsPages(a: var TMemRegion) =
proc getFreeMem(a: TMemRegion): int {.inline.} = result = a.freeMem proc getFreeMem(a: TMemRegion): int {.inline.} = result = a.freeMem
proc getTotalMem(a: TMemRegion): int {.inline.} = result = a.currMem proc getTotalMem(a: TMemRegion): int {.inline.} = result = a.currMem
proc getOccupiedMem(a: TMemRegion): int {.inline.} = proc getOccupiedMem(a: TMemRegion): int {.inline.} =
result = a.currMem - a.freeMem result = a.currMem - a.freeMem
# ---------------------- thread memory region ------------------------------- # ---------------------- thread memory region -------------------------------
@ -774,16 +774,16 @@ template instantiateForRegion(allocator: expr) =
proc deallocOsPages = deallocOsPages(allocator) proc deallocOsPages = deallocOsPages(allocator)
proc alloc(size: int): pointer = proc alloc(size: Natural): pointer =
result = alloc(allocator, size) result = alloc(allocator, size)
proc alloc0(size: int): pointer = proc alloc0(size: Natural): pointer =
result = alloc0(allocator, size) result = alloc0(allocator, size)
proc dealloc(p: pointer) = proc dealloc(p: pointer) =
dealloc(allocator, p) dealloc(allocator, p)
proc realloc(p: pointer, newsize: int): pointer = proc realloc(p: pointer, newsize: Natural): pointer =
result = realloc(allocator, p, newSize) result = realloc(allocator, p, newSize)
when false: when false:
@ -794,7 +794,7 @@ template instantiateForRegion(allocator: expr) =
inc(result, it.size) inc(result, it.size)
it = it.next it = it.next
proc getFreeMem(): int = proc getFreeMem(): int =
result = allocator.freeMem result = allocator.freeMem
#sysAssert(result == countFreeMem()) #sysAssert(result == countFreeMem())
@ -807,7 +807,7 @@ template instantiateForRegion(allocator: expr) =
var heapLock: TSysLock var heapLock: TSysLock
initSysLock(heapLock) initSysLock(heapLock)
proc allocShared(size: int): pointer = proc allocShared(size: Natural): pointer =
when hasThreadSupport: when hasThreadSupport:
acquireSys(heapLock) acquireSys(heapLock)
result = alloc(sharedHeap, size) result = alloc(sharedHeap, size)
@ -815,20 +815,20 @@ template instantiateForRegion(allocator: expr) =
else: else:
result = alloc(size) result = alloc(size)
proc allocShared0(size: int): pointer = proc allocShared0(size: Natural): pointer =
result = allocShared(size) result = allocShared(size)
zeroMem(result, size) zeroMem(result, size)
proc deallocShared(p: pointer) = proc deallocShared(p: pointer) =
when hasThreadSupport: when hasThreadSupport:
acquireSys(heapLock) acquireSys(heapLock)
dealloc(sharedHeap, p) dealloc(sharedHeap, p)
releaseSys(heapLock) releaseSys(heapLock)
else: else:
dealloc(p) dealloc(p)
proc reallocShared(p: pointer, newsize: int): pointer = proc reallocShared(p: pointer, newsize: Natural): pointer =
when hasThreadSupport: when hasThreadSupport:
acquireSys(heapLock) acquireSys(heapLock)
result = realloc(sharedHeap, p, newsize) result = realloc(sharedHeap, p, newsize)
releaseSys(heapLock) releaseSys(heapLock)

View file

@ -109,24 +109,24 @@ when defined(boehmgc):
when not defined(useNimRtl): when not defined(useNimRtl):
proc alloc(size: int): pointer = proc alloc(size: Natural): pointer =
result = boehmAlloc(size) result = boehmAlloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc alloc0(size: int): pointer = proc alloc0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc realloc(p: pointer, newsize: int): pointer = proc realloc(p: pointer, newsize: Natural): pointer =
result = boehmRealloc(p, newsize) result = boehmRealloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc dealloc(p: pointer) = boehmDealloc(p) proc dealloc(p: pointer) = boehmDealloc(p)
proc allocShared(size: int): pointer = proc allocShared(size: Natural): pointer =
result = boehmAlloc(size) result = boehmAlloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc allocShared0(size: int): pointer = proc allocShared0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc reallocShared(p: pointer, newsize: int): pointer = proc reallocShared(p: pointer, newsize: Natural): pointer =
result = boehmRealloc(p, newsize) result = boehmRealloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc deallocShared(p: pointer) = boehmDealloc(p) proc deallocShared(p: pointer) = boehmDealloc(p)
@ -196,24 +196,24 @@ when defined(boehmgc):
elif defined(nogc) and defined(useMalloc): elif defined(nogc) and defined(useMalloc):
when not defined(useNimRtl): when not defined(useNimRtl):
proc alloc(size: int): pointer = proc alloc(size: Natural): pointer =
result = cmalloc(size) result = cmalloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc alloc0(size: int): pointer = proc alloc0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc realloc(p: pointer, newsize: int): pointer = proc realloc(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize) result = crealloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc dealloc(p: pointer) = cfree(p) proc dealloc(p: pointer) = cfree(p)
proc allocShared(size: int): pointer = proc allocShared(size: Natural): pointer =
result = cmalloc(size) result = cmalloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc allocShared0(size: int): pointer = proc allocShared0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc reallocShared(p: pointer, newsize: int): pointer = proc reallocShared(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize) result = crealloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc deallocShared(p: pointer) = cfree(p) proc deallocShared(p: pointer) = cfree(p)

View file

@ -16,7 +16,7 @@
# of the standard library! # of the standard library!
proc fputs(c: cstring, f: File) {.importc: "fputs", header: "<stdio.h>", proc fputs(c: cstring, f: File) {.importc: "fputs", header: "<stdio.h>",
tags: [WriteIOEffect].} tags: [WriteIOEffect].}
proc fgets(c: cstring, n: int, f: File): cstring {. proc fgets(c: cstring, n: int, f: File): cstring {.
importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].} importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].}
@ -26,11 +26,30 @@ proc ungetc(c: cint, f: File) {.importc: "ungetc", header: "<stdio.h>",
tags: [].} tags: [].}
proc putc(c: char, stream: File) {.importc: "putc", header: "<stdio.h>", proc putc(c: char, stream: File) {.importc: "putc", header: "<stdio.h>",
tags: [WriteIOEffect].} tags: [WriteIOEffect].}
proc fprintf(f: File, frmt: cstring) {.importc: "fprintf", proc fprintf(f: File, frmt: cstring) {.importc: "fprintf",
header: "<stdio.h>", varargs, tags: [WriteIOEffect].} header: "<stdio.h>", varargs, tags: [WriteIOEffect].}
proc strlen(c: cstring): int {. proc strlen(c: cstring): int {.
importc: "strlen", header: "<string.h>", tags: [].} importc: "strlen", header: "<string.h>", tags: [].}
when defined(posix):
proc getc_unlocked(stream: File): cint {.importc: "getc_unlocked",
header: "<stdio.h>", tags: [ReadIOEffect].}
proc flockfile(stream: File) {.importc: "flockfile", header: "<stdio.h>",
tags: [ReadIOEffect].}
proc funlockfile(stream: File) {.importc: "funlockfile", header: "<stdio.h>",
tags: [ReadIOEffect].}
elif false:
# doesn't work on Windows yet:
proc getc_unlocked(stream: File): cint {.importc: "_fgetc_nolock",
header: "<stdio.h>", tags: [ReadIOEffect].}
proc flockfile(stream: File) {.importc: "_lock_file", header: "<stdio.h>",
tags: [ReadIOEffect].}
proc funlockfile(stream: File) {.importc: "_unlock_file", header: "<stdio.h>",
tags: [ReadIOEffect].}
# C routine that is used here: # C routine that is used here:
proc fread(buf: pointer, size, n: int, f: File): int {. proc fread(buf: pointer, size, n: int, f: File): int {.
@ -67,39 +86,57 @@ const
proc raiseEIO(msg: string) {.noinline, noreturn.} = proc raiseEIO(msg: string) {.noinline, noreturn.} =
sysFatal(IOError, msg) sysFatal(IOError, msg)
proc readLine(f: File, line: var TaintedString): bool = when declared(getc_unlocked):
# of course this could be optimized a bit; but IO is slow anyway... proc readLine(f: File, line: var TaintedString): bool =
# and it was difficult to get this CORRECT with Ansi C's methods setLen(line.string, 0) # reuse the buffer!
setLen(line.string, 0) # reuse the buffer! flockfile(f)
while true: while true:
var c = fgetc(f) var c = getc_unlocked(f)
if c < 0'i32: if c < 0'i32:
if line.len > 0: break if line.len > 0: break
else: return false else: return false
if c == 10'i32: break # LF if c == 10'i32: break # LF
if c == 13'i32: # CR if c == 13'i32: # CR
c = fgetc(f) # is the next char LF? c = getc_unlocked(f) # is the next char LF?
if c != 10'i32: ungetc(c, f) # no, put the character back if c != 10'i32: ungetc(c, f) # no, put the character back
break break
add line.string, chr(int(c)) add line.string, chr(int(c))
result = true result = true
funlockfile(f)
else:
proc readLine(f: File, line: var TaintedString): bool =
# of course this could be optimized a bit; but IO is slow anyway...
# and it was difficult to get this CORRECT with Ansi C's methods
setLen(line.string, 0) # reuse the buffer!
while true:
var c = fgetc(f)
if c < 0'i32:
if line.len > 0: break
else: return false
if c == 10'i32: break # LF
if c == 13'i32: # CR
c = fgetc(f) # is the next char LF?
if c != 10'i32: ungetc(c, f) # no, put the character back
break
add line.string, chr(int(c))
result = true
proc readLine(f: File): TaintedString = proc readLine(f: File): TaintedString =
result = TaintedString(newStringOfCap(80)) result = TaintedString(newStringOfCap(80))
if not readLine(f, result): raiseEIO("EOF reached") if not readLine(f, result): raiseEIO("EOF reached")
proc write(f: File, i: int) = proc write(f: File, i: int) =
when sizeof(int) == 8: when sizeof(int) == 8:
fprintf(f, "%lld", i) fprintf(f, "%lld", i)
else: else:
fprintf(f, "%ld", i) fprintf(f, "%ld", i)
proc write(f: File, i: BiggestInt) = proc write(f: File, i: BiggestInt) =
when sizeof(BiggestInt) == 8: when sizeof(BiggestInt) == 8:
fprintf(f, "%lld", i) fprintf(f, "%lld", i)
else: else:
fprintf(f, "%ld", i) fprintf(f, "%ld", i)
proc write(f: File, b: bool) = proc write(f: File, b: bool) =
if b: write(f, "true") if b: write(f, "true")
else: write(f, "false") else: write(f, "false")
@ -110,7 +147,7 @@ proc write(f: File, c: char) = putc(c, f)
proc write(f: File, a: varargs[string, `$`]) = proc write(f: File, a: varargs[string, `$`]) =
for x in items(a): write(f, x) for x in items(a): write(f, x)
proc readAllBuffer(file: File): string = proc readAllBuffer(file: File): string =
# This proc is for File we want to read but don't know how many # This proc is for File we want to read but don't know how many
# bytes we need to read before the buffer is empty. # bytes we need to read before the buffer is empty.
result = "" result = ""
@ -123,8 +160,8 @@ proc readAllBuffer(file: File): string =
buffer.setLen(bytesRead) buffer.setLen(bytesRead)
result.add(buffer) result.add(buffer)
break break
proc rawFileSize(file: File): int = proc rawFileSize(file: File): int =
# this does not raise an error opposed to `getFileSize` # this does not raise an error opposed to `getFileSize`
var oldPos = ftell(file) var oldPos = ftell(file)
discard fseek(file, 0, 2) # seek the end of the file discard fseek(file, 0, 2) # seek the end of the file
@ -141,8 +178,8 @@ proc readAllFile(file: File, len: int): string =
proc readAllFile(file: File): string = proc readAllFile(file: File): string =
var len = rawFileSize(file) var len = rawFileSize(file)
result = readAllFile(file, len) result = readAllFile(file, len)
proc readAll(file: File): TaintedString = proc readAll(file: File): TaintedString =
# Separate handling needed because we need to buffer when we # Separate handling needed because we need to buffer when we
# don't know the overall length of the File. # don't know the overall length of the File.
let len = if file != stdin: rawFileSize(file) else: -1 let len = if file != stdin: rawFileSize(file) else: -1
@ -150,7 +187,7 @@ proc readAll(file: File): TaintedString =
result = readAllFile(file, len).TaintedString result = readAllFile(file, len).TaintedString
else: else:
result = readAllBuffer(file).TaintedString result = readAllBuffer(file).TaintedString
proc readFile(filename: string): TaintedString = proc readFile(filename: string): TaintedString =
var f = open(filename) var f = open(filename)
try: try:
@ -229,7 +266,7 @@ proc open(f: var File, filename: string,
elif bufSize == 0: elif bufSize == 0:
discard setvbuf(f, nil, IONBF, 0) discard setvbuf(f, nil, IONBF, 0)
proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool = proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool =
var p: pointer = freopen(filename, FormatOpen[mode], f) var p: pointer = freopen(filename, FormatOpen[mode], f)
result = p != nil result = p != nil
@ -243,23 +280,23 @@ proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool =
proc fwrite(buf: pointer, size, n: int, f: File): int {. proc fwrite(buf: pointer, size, n: int, f: File): int {.
importc: "fwrite", noDecl.} importc: "fwrite", noDecl.}
proc readBuffer(f: File, buffer: pointer, len: int): int = proc readBuffer(f: File, buffer: pointer, len: Natural): int =
result = fread(buffer, 1, len, f) result = fread(buffer, 1, len, f)
proc readBytes(f: File, a: var openArray[int8|uint8], start, len: int): int = proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int =
result = readBuffer(f, addr(a[start]), len) result = readBuffer(f, addr(a[start]), len)
proc readChars(f: File, a: var openArray[char], start, len: int): int = proc readChars(f: File, a: var openArray[char], start, len: Natural): int =
result = readBuffer(f, addr(a[start]), len) result = readBuffer(f, addr(a[start]), len)
{.push stackTrace:off, profiler:off.} {.push stackTrace:off, profiler:off.}
proc writeBytes(f: File, a: openArray[int8|uint8], start, len: int): int = proc writeBytes(f: File, a: openArray[int8|uint8], start, len: Natural): int =
var x = cast[ptr array[0..1000_000_000, int8]](a) var x = cast[ptr array[0..1000_000_000, int8]](a)
result = writeBuffer(f, addr(x[start]), len) result = writeBuffer(f, addr(x[start]), len)
proc writeChars(f: File, a: openArray[char], start, len: int): int = proc writeChars(f: File, a: openArray[char], start, len: Natural): int =
var x = cast[ptr array[0..1000_000_000, int8]](a) var x = cast[ptr array[0..1000_000_000, int8]](a)
result = writeBuffer(f, addr(x[start]), len) result = writeBuffer(f, addr(x[start]), len)
proc writeBuffer(f: File, buffer: pointer, len: int): int = proc writeBuffer(f: File, buffer: pointer, len: Natural): int =
result = fwrite(buffer, 1, len, f) result = fwrite(buffer, 1, len, f)
proc write(f: File, s: string) = proc write(f: File, s: string) =

View file

@ -11,7 +11,7 @@
## Unicode version. ## Unicode version.
{.deadCodeElim: on.} {.deadCodeElim: on.}
{.push gcsafe.}
type type
WideChar* = uint16 WideChar* = uint16
PWideChar* = ptr uint16 PWideChar* = ptr uint16
@ -23481,7 +23481,7 @@ proc ListView_EnsureVisible(hwndLV: HWND, i, fPartialOK: int32): LRESULT =
MAKELPARAM(fPartialOK, 0)) MAKELPARAM(fPartialOK, 0))
proc ListView_FindItem(wnd: HWND, iStart: int32, lvfi: var LV_FINDINFO): int32 = proc ListView_FindItem(wnd: HWND, iStart: int32, lvfi: var LV_FINDINFO): int32 =
result = SendMessage(wnd, LVM_FINDITEM, WPARAM(iStart), result = SendMessage(wnd, LVM_FINDITEM, WPARAM(iStart),
cast[LPARAM](addr(lvfi))).int32 cast[LPARAM](addr(lvfi))).int32
proc ListView_GetBkColor(wnd: HWND): LRESULT = proc ListView_GetBkColor(wnd: HWND): LRESULT =
@ -23615,9 +23615,9 @@ proc ListView_SetTextBkColor(wnd: HWND, clrTextBk: COLORREF): LRESULT =
proc ListView_SetTextColor(wnd: HWND, clrText: COLORREF): LRESULT = proc ListView_SetTextColor(wnd: HWND, clrText: COLORREF): LRESULT =
result = SendMessage(wnd, LVM_SETTEXTCOLOR, 0, LPARAM(clrText)) result = SendMessage(wnd, LVM_SETTEXTCOLOR, 0, LPARAM(clrText))
proc ListView_SortItems(hwndLV: HWND, pfnCompare: PFNLVCOMPARE, proc ListView_SortItems(hwndLV: HWND, pfnCompare: PFNLVCOMPARE,
lPrm: LPARAM): LRESULT = lPrm: LPARAM): LRESULT =
result = SendMessage(hwndLV, LVM_SORTITEMS, WPARAM(lPrm), result = SendMessage(hwndLV, LVM_SORTITEMS, WPARAM(lPrm),
cast[LPARAM](pfnCompare)) cast[LPARAM](pfnCompare))
proc ListView_Update(hwndLV: HWND, i: int32): LRESULT = proc ListView_Update(hwndLV: HWND, i: int32): LRESULT =
@ -23924,3 +23924,5 @@ proc LOCALE_NEUTRAL(): DWORD =
proc LOCALE_INVARIANT(): DWORD = proc LOCALE_INVARIANT(): DWORD =
result = MAKELCID(MAKELANGID(toU16(LANG_INVARIANT), SUBLANG_NEUTRAL), SORT_DEFAULT) result = MAKELCID(MAKELANGID(toU16(LANG_INVARIANT), SUBLANG_NEUTRAL), SORT_DEFAULT)
{.pop.}

View file

@ -1,13 +1,13 @@
# #
# Binding for the IUP GUI toolkit # Binding for the IUP GUI toolkit
# (c) 2012 Andreas Rumpf # (c) 2012 Andreas Rumpf
# C header files translated by hand # C header files translated by hand
# Licence of IUP follows: # Licence of IUP follows:
# **************************************************************************** # ****************************************************************************
# Copyright (C) 1994-2009 Tecgraf, PUC-Rio. # Copyright (C) 1994-2009 Tecgraf, PUC-Rio.
# #
# Permission is hereby granted, free of charge, to any person obtaining # Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the # a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including # "Software"), to deal in the Software without restriction, including
@ -30,12 +30,12 @@
{.deadCodeElim: on.} {.deadCodeElim: on.}
when defined(windows): when defined(windows):
const dllname = "iup(30|27|26|25|24).dll" const dllname = "iup(|30|27|26|25|24).dll"
elif defined(macosx): elif defined(macosx):
const dllname = "libiup(3.0|2.7|2.6|2.5|2.4).dylib" const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).dylib"
else: else:
const dllname = "libiup(3.0|2.7|2.6|2.5|2.4).so.1" const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).so(|.1)"
const const
IUP_NAME* = "IUP - Portable User Interface" IUP_NAME* = "IUP - Portable User Interface"
@ -67,8 +67,8 @@ proc alarm*(title, msg, b1, b2, b3: cstring): cint {.
importc: "IupAlarm", dynlib: dllname, cdecl.} importc: "IupAlarm", dynlib: dllname, cdecl.}
proc scanf*(format: cstring): cint {. proc scanf*(format: cstring): cint {.
importc: "IupScanf", dynlib: dllname, cdecl, varargs.} importc: "IupScanf", dynlib: dllname, cdecl, varargs.}
proc listDialog*(theType: cint, title: cstring, size: cint, proc listDialog*(theType: cint, title: cstring, size: cint,
list: cstringArray, op, maxCol, maxLin: cint, list: cstringArray, op, maxCol, maxLin: cint,
marks: ptr cint): cint {. marks: ptr cint): cint {.
importc: "IupListDialog", dynlib: dllname, cdecl.} importc: "IupListDialog", dynlib: dllname, cdecl.}
proc getText*(title, text: cstring): cint {. proc getText*(title, text: cstring): cint {.
@ -77,14 +77,14 @@ proc getColor*(x, y: cint, r, g, b: var byte): cint {.
importc: "IupGetColor", dynlib: dllname, cdecl.} importc: "IupGetColor", dynlib: dllname, cdecl.}
type type
Iparamcb* = proc (dialog: PIhandle, paramIndex: cint, Iparamcb* = proc (dialog: PIhandle, paramIndex: cint,
userData: pointer): cint {.cdecl.} userData: pointer): cint {.cdecl.}
proc getParam*(title: cstring, action: Iparamcb, userData: pointer, proc getParam*(title: cstring, action: Iparamcb, userData: pointer,
format: cstring): cint {. format: cstring): cint {.
importc: "IupGetParam", cdecl, varargs, dynlib: dllname.} importc: "IupGetParam", cdecl, varargs, dynlib: dllname.}
proc getParamv*(title: cstring, action: Iparamcb, userData: pointer, proc getParamv*(title: cstring, action: Iparamcb, userData: pointer,
format: cstring, paramCount, paramExtra: cint, format: cstring, paramCount, paramExtra: cint,
paramData: pointer): cint {. paramData: pointer): cint {.
importc: "IupGetParamv", cdecl, dynlib: dllname.} importc: "IupGetParamv", cdecl, dynlib: dllname.}
@ -96,11 +96,11 @@ proc open*(argc: ptr cint, argv: ptr cstringArray): cint {.
proc close*() {.importc: "IupClose", cdecl, dynlib: dllname.} proc close*() {.importc: "IupClose", cdecl, dynlib: dllname.}
proc imageLibOpen*() {.importc: "IupImageLibOpen", cdecl, dynlib: dllname.} proc imageLibOpen*() {.importc: "IupImageLibOpen", cdecl, dynlib: dllname.}
proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname, proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname,
discardable.} discardable.}
proc loopStep*(): cint {.importc: "IupLoopStep", cdecl, dynlib: dllname, proc loopStep*(): cint {.importc: "IupLoopStep", cdecl, dynlib: dllname,
discardable.} discardable.}
proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl, proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl,
dynlib: dllname, discardable.} dynlib: dllname, discardable.}
proc flush*() {.importc: "IupFlush", cdecl, dynlib: dllname.} proc flush*() {.importc: "IupFlush", cdecl, dynlib: dllname.}
proc exitLoop*() {.importc: "IupExitLoop", cdecl, dynlib: dllname.} proc exitLoop*() {.importc: "IupExitLoop", cdecl, dynlib: dllname.}
@ -204,7 +204,7 @@ proc getCallback*(ih: PIhandle, name: cstring): Icallback {.
importc: "IupGetCallback", cdecl, dynlib: dllname.} importc: "IupGetCallback", cdecl, dynlib: dllname.}
proc setCallback*(ih: PIhandle, name: cstring, fn: Icallback): Icallback {. proc setCallback*(ih: PIhandle, name: cstring, fn: Icallback): Icallback {.
importc: "IupSetCallback", cdecl, dynlib: dllname, discardable.} importc: "IupSetCallback", cdecl, dynlib: dllname, discardable.}
proc setCallbacks*(ih: PIhandle, name: cstring, fn: Icallback): PIhandle {. proc setCallbacks*(ih: PIhandle, name: cstring, fn: Icallback): PIhandle {.
importc: "IupSetCallbacks", cdecl, dynlib: dllname, varargs, discardable.} importc: "IupSetCallbacks", cdecl, dynlib: dllname, varargs, discardable.}
@ -235,7 +235,7 @@ proc getClassName*(ih: PIhandle): cstring {.
importc: "IupGetClassName", cdecl, dynlib: dllname.} importc: "IupGetClassName", cdecl, dynlib: dllname.}
proc getClassType*(ih: PIhandle): cstring {. proc getClassType*(ih: PIhandle): cstring {.
importc: "IupGetClassType", cdecl, dynlib: dllname.} importc: "IupGetClassType", cdecl, dynlib: dllname.}
proc getClassAttributes*(classname: cstring, names: cstringArray, proc getClassAttributes*(classname: cstring, names: cstringArray,
n: cint): cint {. n: cint): cint {.
importc: "IupGetClassAttributes", cdecl, dynlib: dllname.} importc: "IupGetClassAttributes", cdecl, dynlib: dllname.}
proc saveClassAttributes*(ih: PIhandle) {. proc saveClassAttributes*(ih: PIhandle) {.
@ -378,12 +378,12 @@ const
IUP_CONTINUE* = cint(-4) IUP_CONTINUE* = cint(-4)
# IupPopup and IupShowXY Parameter Values # IupPopup and IupShowXY Parameter Values
IUP_CENTER* = cint(0xFFFF) IUP_CENTER* = cint(0xFFFF)
IUP_LEFT* = cint(0xFFFE) IUP_LEFT* = cint(0xFFFE)
IUP_RIGHT* = cint(0xFFFD) IUP_RIGHT* = cint(0xFFFD)
IUP_MOUSEPOS* = cint(0xFFFC) IUP_MOUSEPOS* = cint(0xFFFC)
IUP_CURRENT* = cint(0xFFFB) IUP_CURRENT* = cint(0xFFFB)
IUP_CENTERPARENT* = cint(0xFFFA) IUP_CENTERPARENT* = cint(0xFFFA)
IUP_TOP* = IUP_LEFT IUP_TOP* = IUP_LEFT
IUP_BOTTOM* = IUP_RIGHT IUP_BOTTOM* = IUP_RIGHT
@ -397,10 +397,10 @@ const
# SCROLL_CB Callback Values # SCROLL_CB Callback Values
IUP_SBUP* = cint(0) IUP_SBUP* = cint(0)
IUP_SBDN* = cint(1) IUP_SBDN* = cint(1)
IUP_SBPGUP* = cint(2) IUP_SBPGUP* = cint(2)
IUP_SBPGDN* = cint(3) IUP_SBPGDN* = cint(3)
IUP_SBPOSV* = cint(4) IUP_SBPOSV* = cint(4)
IUP_SBDRAGV* = cint(5) IUP_SBDRAGV* = cint(5)
IUP_SBLEFT* = cint(6) IUP_SBLEFT* = cint(6)
IUP_SBRIGHT* = cint(7) IUP_SBRIGHT* = cint(7)
IUP_SBPGLEFT* = cint(8) IUP_SBPGLEFT* = cint(8)
@ -433,12 +433,12 @@ const
IUP_MASK_EFLOAT* = "[+/-]?(/d+/.?/d*|/./d+)([eE][+/-]?/d+)?" IUP_MASK_EFLOAT* = "[+/-]?(/d+/.?/d*|/./d+)([eE][+/-]?/d+)?"
IUP_MASK_INT* = "[+/-]?/d+" IUP_MASK_INT* = "[+/-]?/d+"
IUP_MASK_UINT* = "/d+" IUP_MASK_UINT* = "/d+"
# from 32 to 126, all character sets are equal, # from 32 to 126, all character sets are equal,
# the key code i the same as the character code. # the key code i the same as the character code.
const const
K_SP* = cint(ord(' ')) K_SP* = cint(ord(' '))
K_exclam* = cint(ord('!')) K_exclam* = cint(ord('!'))
K_quotedbl* = cint(ord('\"')) K_quotedbl* = cint(ord('\"'))
K_numbersign* = cint(ord('#')) K_numbersign* = cint(ord('#'))
K_dollar* = cint(ord('$')) K_dollar* = cint(ord('$'))
@ -467,51 +467,51 @@ const
K_semicolon* = cint(ord(';')) K_semicolon* = cint(ord(';'))
K_less* = cint(ord('<')) K_less* = cint(ord('<'))
K_equal* = cint(ord('=')) K_equal* = cint(ord('='))
K_greater* = cint(ord('>')) K_greater* = cint(ord('>'))
K_question* = cint(ord('?')) K_question* = cint(ord('?'))
K_at* = cint(ord('@')) K_at* = cint(ord('@'))
K_upperA* = cint(ord('A')) K_upperA* = cint(ord('A'))
K_upperB* = cint(ord('B')) K_upperB* = cint(ord('B'))
K_upperC* = cint(ord('C')) K_upperC* = cint(ord('C'))
K_upperD* = cint(ord('D')) K_upperD* = cint(ord('D'))
K_upperE* = cint(ord('E')) K_upperE* = cint(ord('E'))
K_upperF* = cint(ord('F')) K_upperF* = cint(ord('F'))
K_upperG* = cint(ord('G')) K_upperG* = cint(ord('G'))
K_upperH* = cint(ord('H')) K_upperH* = cint(ord('H'))
K_upperI* = cint(ord('I')) K_upperI* = cint(ord('I'))
K_upperJ* = cint(ord('J')) K_upperJ* = cint(ord('J'))
K_upperK* = cint(ord('K')) K_upperK* = cint(ord('K'))
K_upperL* = cint(ord('L')) K_upperL* = cint(ord('L'))
K_upperM* = cint(ord('M')) K_upperM* = cint(ord('M'))
K_upperN* = cint(ord('N')) K_upperN* = cint(ord('N'))
K_upperO* = cint(ord('O')) K_upperO* = cint(ord('O'))
K_upperP* = cint(ord('P')) K_upperP* = cint(ord('P'))
K_upperQ* = cint(ord('Q')) K_upperQ* = cint(ord('Q'))
K_upperR* = cint(ord('R')) K_upperR* = cint(ord('R'))
K_upperS* = cint(ord('S')) K_upperS* = cint(ord('S'))
K_upperT* = cint(ord('T')) K_upperT* = cint(ord('T'))
K_upperU* = cint(ord('U')) K_upperU* = cint(ord('U'))
K_upperV* = cint(ord('V')) K_upperV* = cint(ord('V'))
K_upperW* = cint(ord('W')) K_upperW* = cint(ord('W'))
K_upperX* = cint(ord('X')) K_upperX* = cint(ord('X'))
K_upperY* = cint(ord('Y')) K_upperY* = cint(ord('Y'))
K_upperZ* = cint(ord('Z')) K_upperZ* = cint(ord('Z'))
K_bracketleft* = cint(ord('[')) K_bracketleft* = cint(ord('['))
K_backslash* = cint(ord('\\')) K_backslash* = cint(ord('\\'))
K_bracketright* = cint(ord(']')) K_bracketright* = cint(ord(']'))
K_circum* = cint(ord('^')) K_circum* = cint(ord('^'))
K_underscore* = cint(ord('_')) K_underscore* = cint(ord('_'))
K_grave* = cint(ord('`')) K_grave* = cint(ord('`'))
K_lowera* = cint(ord('a')) K_lowera* = cint(ord('a'))
K_lowerb* = cint(ord('b')) K_lowerb* = cint(ord('b'))
K_lowerc* = cint(ord('c')) K_lowerc* = cint(ord('c'))
K_lowerd* = cint(ord('d')) K_lowerd* = cint(ord('d'))
K_lowere* = cint(ord('e')) K_lowere* = cint(ord('e'))
K_lowerf* = cint(ord('f')) K_lowerf* = cint(ord('f'))
K_lowerg* = cint(ord('g')) K_lowerg* = cint(ord('g'))
K_lowerh* = cint(ord('h')) K_lowerh* = cint(ord('h'))
K_loweri* = cint(ord('i')) K_loweri* = cint(ord('i'))
K_lowerj* = cint(ord('j')) K_lowerj* = cint(ord('j'))
K_lowerk* = cint(ord('k')) K_lowerk* = cint(ord('k'))
K_lowerl* = cint(ord('l')) K_lowerl* = cint(ord('l'))
K_lowerm* = cint(ord('m')) K_lowerm* = cint(ord('m'))
@ -553,19 +553,19 @@ proc isAltXkey*(c: cint): bool = return c > 768 and c < 1024
proc isSysXkey*(c: cint): bool = return c > 1024 and c < 1280 proc isSysXkey*(c: cint): bool = return c > 1024 and c < 1280
proc iUPxCODE*(c: cint): cint = return c + cint(128) # Normal (must be above 128) proc iUPxCODE*(c: cint): cint = return c + cint(128) # Normal (must be above 128)
proc iUPsxCODE*(c: cint): cint = proc iUPsxCODE*(c: cint): cint =
return c + cint(256) return c + cint(256)
# Shift (must have range to include the standard keys and the normal # Shift (must have range to include the standard keys and the normal
# extended keys, so must be above 256 # extended keys, so must be above 256
proc iUPcxCODE*(c: cint): cint = return c + cint(512) # Ctrl proc iUPcxCODE*(c: cint): cint = return c + cint(512) # Ctrl
proc iUPmxCODE*(c: cint): cint = return c + cint(768) # Alt proc iUPmxCODE*(c: cint): cint = return c + cint(768) # Alt
proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple) proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple)
const const
IUP_NUMMAXCODES* = 1280 ## 5*256=1280 Normal+Shift+Ctrl+Alt+Sys IUP_NUMMAXCODES* = 1280 ## 5*256=1280 Normal+Shift+Ctrl+Alt+Sys
K_HOME* = iUPxCODE(1) K_HOME* = iUPxCODE(1)
K_UP* = iUPxCODE(2) K_UP* = iUPxCODE(2)
K_PGUP* = iUPxCODE(3) K_PGUP* = iUPxCODE(3)
K_LEFT* = iUPxCODE(4) K_LEFT* = iUPxCODE(4)
@ -574,8 +574,8 @@ const
K_END* = iUPxCODE(7) K_END* = iUPxCODE(7)
K_DOWN* = iUPxCODE(8) K_DOWN* = iUPxCODE(8)
K_PGDN* = iUPxCODE(9) K_PGDN* = iUPxCODE(9)
K_INS* = iUPxCODE(10) K_INS* = iUPxCODE(10)
K_DEL* = iUPxCODE(11) K_DEL* = iUPxCODE(11)
K_PAUSE* = iUPxCODE(12) K_PAUSE* = iUPxCODE(12)
K_ESC* = iUPxCODE(13) K_ESC* = iUPxCODE(13)
K_ccedilla* = iUPxCODE(14) K_ccedilla* = iUPxCODE(14)
@ -728,13 +728,13 @@ const
K_yPrint* = iUPyxCODE(K_Print) K_yPrint* = iUPyxCODE(K_Print)
K_yMenu* = iUPyxCODE(K_Menu) K_yMenu* = iUPyxCODE(K_Menu)
K_sPlus* = iUPsxCODE(K_plus) K_sPlus* = iUPsxCODE(K_plus)
K_sComma* = iUPsxCODE(K_comma) K_sComma* = iUPsxCODE(K_comma)
K_sMinus* = iUPsxCODE(K_minus) K_sMinus* = iUPsxCODE(K_minus)
K_sPeriod* = iUPsxCODE(K_period) K_sPeriod* = iUPsxCODE(K_period)
K_sSlash* = iUPsxCODE(K_slash) K_sSlash* = iUPsxCODE(K_slash)
K_sAsterisk* = iUPsxCODE(K_asterisk) K_sAsterisk* = iUPsxCODE(K_asterisk)
K_cupperA* = iUPcxCODE(K_upperA) K_cupperA* = iUPcxCODE(K_upperA)
K_cupperB* = iUPcxCODE(K_upperB) K_cupperB* = iUPcxCODE(K_upperB)
K_cupperC* = iUPcxCODE(K_upperC) K_cupperC* = iUPcxCODE(K_upperC)
@ -767,16 +767,16 @@ const
K_c4* = iUPcxCODE(K_4) K_c4* = iUPcxCODE(K_4)
K_c5* = iUPcxCODE(K_5) K_c5* = iUPcxCODE(K_5)
K_c6* = iUPcxCODE(K_6) K_c6* = iUPcxCODE(K_6)
K_c7* = iUPcxCODE(K_7) K_c7* = iUPcxCODE(K_7)
K_c8* = iUPcxCODE(K_8) K_c8* = iUPcxCODE(K_8)
K_c9* = iUPcxCODE(K_9) K_c9* = iUPcxCODE(K_9)
K_c0* = iUPcxCODE(K_0) K_c0* = iUPcxCODE(K_0)
K_cPlus* = iUPcxCODE(K_plus) K_cPlus* = iUPcxCODE(K_plus)
K_cComma* = iUPcxCODE(K_comma) K_cComma* = iUPcxCODE(K_comma)
K_cMinus* = iUPcxCODE(K_minus) K_cMinus* = iUPcxCODE(K_minus)
K_cPeriod* = iUPcxCODE(K_period) K_cPeriod* = iUPcxCODE(K_period)
K_cSlash* = iUPcxCODE(K_slash) K_cSlash* = iUPcxCODE(K_slash)
K_cSemicolon* = iUPcxCODE(K_semicolon) K_cSemicolon* = iUPcxCODE(K_semicolon)
K_cEqual* = iUPcxCODE(K_equal) K_cEqual* = iUPcxCODE(K_equal)
K_cBracketleft* = iUPcxCODE(K_bracketleft) K_cBracketleft* = iUPcxCODE(K_bracketleft)
K_cBracketright* = iUPcxCODE(K_bracketright) K_cBracketright* = iUPcxCODE(K_bracketright)
@ -815,16 +815,16 @@ const
K_m4* = iUPmxCODE(K_4) K_m4* = iUPmxCODE(K_4)
K_m5* = iUPmxCODE(K_5) K_m5* = iUPmxCODE(K_5)
K_m6* = iUPmxCODE(K_6) K_m6* = iUPmxCODE(K_6)
K_m7* = iUPmxCODE(K_7) K_m7* = iUPmxCODE(K_7)
K_m8* = iUPmxCODE(K_8) K_m8* = iUPmxCODE(K_8)
K_m9* = iUPmxCODE(K_9) K_m9* = iUPmxCODE(K_9)
K_m0* = iUPmxCODE(K_0) K_m0* = iUPmxCODE(K_0)
K_mPlus* = iUPmxCODE(K_plus) K_mPlus* = iUPmxCODE(K_plus)
K_mComma* = iUPmxCODE(K_comma) K_mComma* = iUPmxCODE(K_comma)
K_mMinus* = iUPmxCODE(K_minus) K_mMinus* = iUPmxCODE(K_minus)
K_mPeriod* = iUPmxCODE(K_period) K_mPeriod* = iUPmxCODE(K_period)
K_mSlash* = iUPmxCODE(K_slash) K_mSlash* = iUPmxCODE(K_slash)
K_mSemicolon* = iUPmxCODE(K_semicolon) K_mSemicolon* = iUPmxCODE(K_semicolon)
K_mEqual* = iUPmxCODE(K_equal) K_mEqual* = iUPmxCODE(K_equal)
K_mBracketleft* = iUPmxCODE(K_bracketleft) K_mBracketleft* = iUPmxCODE(K_bracketleft)
K_mBracketright* = iUPmxCODE(K_bracketright) K_mBracketright* = iUPmxCODE(K_bracketright)
@ -863,16 +863,16 @@ const
K_y4* = iUPyxCODE(K_4) K_y4* = iUPyxCODE(K_4)
K_y5* = iUPyxCODE(K_5) K_y5* = iUPyxCODE(K_5)
K_y6* = iUPyxCODE(K_6) K_y6* = iUPyxCODE(K_6)
K_y7* = iUPyxCODE(K_7) K_y7* = iUPyxCODE(K_7)
K_y8* = iUPyxCODE(K_8) K_y8* = iUPyxCODE(K_8)
K_y9* = iUPyxCODE(K_9) K_y9* = iUPyxCODE(K_9)
K_y0* = iUPyxCODE(K_0) K_y0* = iUPyxCODE(K_0)
K_yPlus* = iUPyxCODE(K_plus) K_yPlus* = iUPyxCODE(K_plus)
K_yComma* = iUPyxCODE(K_comma) K_yComma* = iUPyxCODE(K_comma)
K_yMinus* = iUPyxCODE(K_minus) K_yMinus* = iUPyxCODE(K_minus)
K_yPeriod* = iUPyxCODE(K_period) K_yPeriod* = iUPyxCODE(K_period)
K_ySlash* = iUPyxCODE(K_slash) K_ySlash* = iUPyxCODE(K_slash)
K_ySemicolon* = iUPyxCODE(K_semicolon) K_ySemicolon* = iUPyxCODE(K_semicolon)
K_yEqual* = iUPyxCODE(K_equal) K_yEqual* = iUPyxCODE(K_equal)
K_yBracketleft* = iUPyxCODE(K_bracketleft) K_yBracketleft* = iUPyxCODE(K_bracketleft)
K_yBracketright* = iUPyxCODE(K_bracketright) K_yBracketright* = iUPyxCODE(K_bracketright)
@ -893,11 +893,11 @@ proc dial*(theType: cstring): PIhandle {.cdecl, importc: "IupDial", dynlib: dlln
proc matrix*(action: cstring): PIhandle {.cdecl, importc: "IupMatrix", dynlib: dllname.} proc matrix*(action: cstring): PIhandle {.cdecl, importc: "IupMatrix", dynlib: dllname.}
# IupMatrix utilities # IupMatrix utilities
proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint, proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
value: cstring) {. value: cstring) {.
cdecl, importc: "IupMatSetAttribute", dynlib: dllname.} cdecl, importc: "IupMatSetAttribute", dynlib: dllname.}
proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint, proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
value: cstring) {.cdecl, value: cstring) {.cdecl,
importc: "IupMatStoreAttribute", dynlib: dllname.} importc: "IupMatStoreAttribute", dynlib: dllname.}
proc matGetAttribute*(ih: PIhandle, name: cstring, lin, col: cint): cstring {. proc matGetAttribute*(ih: PIhandle, name: cstring, lin, col: cint): cstring {.
cdecl, importc: "IupMatGetAttribute", dynlib: dllname.} cdecl, importc: "IupMatGetAttribute", dynlib: dllname.}
@ -905,9 +905,9 @@ proc matGetInt*(ih: PIhandle, name: cstring, lin, col: cint): cint {.
cdecl, importc: "IupMatGetInt", dynlib: dllname.} cdecl, importc: "IupMatGetInt", dynlib: dllname.}
proc matGetFloat*(ih: PIhandle, name: cstring, lin, col: cint): cfloat {. proc matGetFloat*(ih: PIhandle, name: cstring, lin, col: cint): cfloat {.
cdecl, importc: "IupMatGetFloat", dynlib: dllname.} cdecl, importc: "IupMatGetFloat", dynlib: dllname.}
proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint, proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
format: cstring) {.cdecl, format: cstring) {.cdecl,
importc: "IupMatSetfAttribute", importc: "IupMatSetfAttribute",
dynlib: dllname, varargs.} dynlib: dllname, varargs.}
# Used by IupColorbar # Used by IupColorbar
@ -931,10 +931,10 @@ proc pPlotAddStr*(ih: PIhandle, x: cstring, y: cfloat) {.
proc pPlotEnd*(ih: PIhandle): cint {. proc pPlotEnd*(ih: PIhandle): cint {.
cdecl, importc: "IupPPlotEnd", dynlib: dllname.} cdecl, importc: "IupPPlotEnd", dynlib: dllname.}
proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring, proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring,
y: cfloat) {.cdecl, importc: "IupPPlotInsertStr", y: cfloat) {.cdecl, importc: "IupPPlotInsertStr",
dynlib: dllname.} dynlib: dllname.}
proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint, proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint,
x, y: cfloat) {. x, y: cfloat) {.
cdecl, importc: "IupPPlotInsert", dynlib: dllname.} cdecl, importc: "IupPPlotInsert", dynlib: dllname.}

View file

@ -30,7 +30,7 @@ proc bar: int =
# local overrides that are active only # local overrides that are active only
# in this proc # in this proc
onFailedAssert(msg): echo "WARNING: " & msg onFailedAssert(msg): echo "WARNING: " & msg
assert(false, "first assertion from bar") assert(false, "first assertion from bar")
onFailedAssert(msg): onFailedAssert(msg):

View file

@ -0,0 +1,10 @@
type
Concrete* = object
a*, b*: string
rc*: int # refcount
proc `=`(d: var Concrete; src: Concrete) =
shallowCopy(d.a, src.a)
shallowCopy(d.b, src.b)
dec d.rc
d.rc = src.rc + 1

View file

@ -0,0 +1,75 @@
discard """
output: '''Concrete '='
Concrete '='
Concrete '='
Concrete '='
Concrete '='
GenericT[T] '=' int
GenericT[T] '=' float
GenericT[T] '=' float
GenericT[T] '=' float
GenericT[T] '=' string
GenericT[T] '=' int8
GenericT[T] '=' bool
GenericT[T] '=' bool
GenericT[T] '=' bool
GenericT[T] '=' bool'''
"""
import typetraits
type
Concrete = object
a, b: string
proc `=`(d: var Concrete; src: Concrete) =
shallowCopy(d.a, src.a)
shallowCopy(d.b, src.b)
echo "Concrete '='"
var x, y: array[0..2, Concrete]
var cA, cB: Concrete
var cATup, cBTup: tuple[x: int, ha: Concrete]
x = y
cA = cB
cATup = cBTup
type
GenericT[T] = object
a, b: T
proc `=`[T](d: var GenericT[T]; src: GenericT[T]) =
shallowCopy(d.a, src.a)
shallowCopy(d.b, src.b)
echo "GenericT[T] '=' ", type(T).name
var ag: GenericT[int]
var bg: GenericT[int]
ag = bg
var xg, yg: array[0..2, GenericT[float]]
var cAg, cBg: GenericT[string]
var cATupg, cBTupg: tuple[x: int, ha: GenericT[int8]]
xg = yg
cAg = cBg
cATupg = cBTupg
var caSeqg, cbSeqg: seq[GenericT[bool]]
newSeq(cbSeqg, 4)
caSeqg = cbSeqg
when false:
type
Foo = object
case b: bool
of false: xx: GenericT[int]
of true: yy: bool
var
a, b: Foo
a = b

View file

@ -0,0 +1,22 @@
discard """
output: '''i value 88
2aa'''
"""
import moverload_asgn2
proc passAround(i: int): Concrete =
echo "i value ", i
result = Concrete(a: "aa", b: "bb", rc: 0)
proc main =
let
i = 88
v = passAround(i)
z = v.a
var
x: Concrete
x = v
echo x.rc, z # 2aa
main()

View file

@ -0,0 +1,9 @@
discard """
output: '''true'''
"""
# bug #2489
let a = [1]
let b = [1]
echo a == b

View file

@ -40,7 +40,7 @@ type
x: A x: A
y: B y: B
z: C z: C
TObjKind = enum A, B, C, D TObjKind = enum A, B, C, D
TCaseObj = object TCaseObj = object
@ -57,14 +57,14 @@ type
q: TMyGeneric3[TMyObj, int, int] q: TMyGeneric3[TMyObj, int, int]
r: string r: string
proc destroy(o: var TMyObj) {.override.} = proc `=destroy`(o: var TMyObj) =
if o.p != nil: dealloc o.p if o.p != nil: dealloc o.p
echo "myobj destroyed" echo "myobj destroyed"
proc destroy(o: var TMyGeneric1) {.override.} = proc `=destroy`(o: var TMyGeneric1) =
echo "mygeneric1 destroyed" echo "mygeneric1 destroyed"
proc destroy[A, B](o: var TMyGeneric2[A, B]) {.override.} = proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) =
echo "mygeneric2 destroyed" echo "mygeneric2 destroyed"
proc open: TMyObj = proc open: TMyObj =
@ -83,12 +83,12 @@ proc mygeneric1() =
proc mygeneric2[T](val: T) = proc mygeneric2[T](val: T) =
var a = open() var a = open()
var b = TMyGeneric2[int, T](x: 10, y: val) var b = TMyGeneric2[int, T](x: 10, y: val)
echo "mygeneric2 constructed" echo "mygeneric2 constructed"
var c = TMyGeneric3[int, int, string](x: 10, y: 20, z: "test") var c = TMyGeneric3[int, int, string](x: 10, y: 20, z: "test")
proc mygeneric3 = proc mygeneric3 =
var x = TMyGeneric3[int, string, TMyGeneric1[int]]( var x = TMyGeneric3[int, string, TMyGeneric1[int]](
x: 10, y: "test", z: TMyGeneric1[int](x: 10)) x: 10, y: "test", z: TMyGeneric1[int](x: 10))
@ -111,11 +111,11 @@ proc caseobj =
block: block:
echo "----" echo "----"
var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10)) var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10))
block: block:
echo "----" echo "----"
var o2 = TCaseObj(kind: B, y: open()) var o2 = TCaseObj(kind: B, y: open())
block: block:
echo "----" echo "----"
var o3 = TCaseObj(kind: D, innerKind: B, r: "test", var o3 = TCaseObj(kind: D, innerKind: B, r: "test",

View file

@ -5,14 +5,14 @@ discard """
{.experimental.} {.experimental.}
type type
TMyObj = object TMyObj = object
x, y: int x, y: int
p: pointer p: pointer
proc destroy(o: var TMyObj) {.override.} = proc `=destroy`(o: var TMyObj) =
if o.p != nil: dealloc o.p if o.p != nil: dealloc o.p
proc open: TMyObj = proc open: TMyObj =
result = TMyObj(x: 1, y: 2, p: alloc(3)) result = TMyObj(x: 1, y: 2, p: alloc(3))

View file

@ -1,6 +1,7 @@
discard """ discard """
output: '''foo output: '''foo
js 3.14''' js 3.14
7'''
""" """
# This file tests the JavaScript generator # This file tests the JavaScript generator
@ -20,3 +21,11 @@ else:
proc foo(val: float): string = "js " & $val proc foo(val: float): string = "js " & $val
echo foo(3.14) echo foo(3.14)
# #2495
type C = concept x
proc test(x: C, T: typedesc): T =
cast[T](x)
echo 7.test(int8)

View file

@ -15,5 +15,6 @@ const
valid = 45 valid = 45
a = test("foo&&") a = test("foo&&")
b = test("valid") b = test("valid")
c = test("\"") # bug #2504
echo a, " ", b echo a, " ", b

View file

@ -0,0 +1,14 @@
discard """
output: '''253'''
"""
# bug #2427
import unsigned
var x = 0'u8
dec x # OverflowError
x -= 1 # OverflowError
x = x - 1 # No error
echo x

View file

@ -0,0 +1,38 @@
# bug #2481
import math
template test(loopCount: int, extraI: int, testBody: stmt): stmt =
block:
for i in 0..loopCount-1:
testBody
echo "done extraI=", extraI
template test(loopCount: int, extraF: float, testBody: stmt): stmt =
block:
test(loopCount, round(extraF), testBody)
template test(loopCount: int, testBody: stmt): stmt =
block:
test(loopCount, 0, testBody)
echo "done extraI passed 0"
when isMainModule:
var
loops = 0
test 0, 0:
loops += 1
echo "test 0 complete, loops=", loops
test 1, 1.0:
loops += 1
echo "test 1.0 complete, loops=", loops
when true:
# when true we get the following compile time error:
# b.nim(35, 6) Error: expression 'loops += 1' has no type (or is ambiguous)
loops = 0
test 2:
loops += 1
echo "test no extra complete, loops=", loops

View file

@ -0,0 +1,39 @@
discard """
line: 28
nimout: '''tgc_unsafe2.nim(22, 5) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory
tgc_unsafe2.nim(26, 5) Warning: 'track' is not GC-safe as it calls 'trick'
tgc_unsafe2.nim(28, 5) Error: 'consumer' is not GC-safe as it calls 'track'
'''
errormsg: "'consumer' is not GC-safe as it calls 'track'"
"""
import threadpool
type StringChannel = TChannel[string]
var channels: array[1..3, StringChannel]
type
MyObject[T] = object
x: T
var global: MyObject[string]
var globalB: MyObject[float]
proc trick(ix: int) =
echo global.x
echo channels[ix].recv()
proc track(ix: int) = trick(ix)
proc consumer(ix: int) {.thread.} =
track(ix)
proc main =
for ix in 1..3: channels[ix].open()
for ix in 1..3: spawn consumer(ix)
for ix in 1..3: channels[ix].send("test")
sync()
for ix in 1..3: channels[ix].close()
when isMainModule:
main()

View file

@ -2,6 +2,12 @@
discard """ discard """
output: '''35 output: '''35
true
true
4
true
1
false
77 77
(Field0: 1, Field1: 2, Field2: 2) (Field0: 1, Field1: 2, Field2: 2)
ha ha
@ -14,6 +20,17 @@ all args
echo 2+5 * 5 echo 2+5 * 5
# Keyword operators
echo 1 + 16 shl 1 == 1 + (16 shl 1)
echo 2 and 1 in {0, 30}
echo 2+2 * 2 shr 1
echo false or 2 and 1 in {0, 30}
proc `^`(a, b: int): int = a + b div 2
echo 19 mod 16 ^ 4 + 2 and 1
echo 18 mod 16 ^ 4 > 0
# echo $foo gotcha
let foo = 77 let foo = 77
echo $foo echo $foo
@ -27,7 +44,7 @@ when true:
let b = 66 let b = 66
let c = 90 let c = 90
let bar = 8000 let bar = 8000
if foo+4 * 4 == 8 and b&c | 9 ++ if foo+4 * 4 == 8 and b&c | 9 ++
bar: bar:
echo "ho" echo "ho"
else: else:

9
tests/stdlib/treloop.nim Normal file
View file

@ -0,0 +1,9 @@
discard """
output: "@[(, +, 1, 2, )]"
"""
import re
let str = "(+ 1 2)"
var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
echo str.findAll(tokenRE)

View file

@ -3,12 +3,12 @@ discard """
line: 18 line: 18
errormsg: "undeclared identifier: \'b\'" errormsg: "undeclared identifier: \'b\'"
""" """
template declareInScope(x: expr, t: typeDesc): stmt {.immediate.} = template declareInScope(x: untyped, t: typeDesc): untyped {.immediate.} =
var x: t var x: t
template declareInNewScope(x: expr, t: typeDesc): stmt {.immediate.} = template declareInNewScope(x: untyped, t: typeDesc): untyped {.immediate.} =
# open a new scope: # open a new scope:
block: block:
var x: t var x: t
declareInScope(a, int) declareInScope(a, int)

View file

@ -0,0 +1,10 @@
# bug #1986 found by gdmoore
proc test(): int64 =
return 0xdeadbeef.int64
const items = [
(var1: test(), var2: 100'u32),
(var1: test(), var2: 192'u32)
]

View file

@ -1,14 +1,12 @@
version 0.10.4 version 0.10.4
============== ==============
- improve GC-unsafety warnings
- make 'nil' work for 'add' and 'len' - make 'nil' work for 'add' and 'len'
- overloading of '='
version 1.0 version 1.0
=========== ===========
- macro support for '='; bind '=' to a memory region
- remove echo $foo gotcha - remove echo $foo gotcha
- add "all threads are blocked" detection to 'spawn' - add "all threads are blocked" detection to 'spawn'
- figure out why C++ bootstrapping is so much slower - figure out why C++ bootstrapping is so much slower

View file

@ -69,7 +69,15 @@ News
spacing around binary operators. Later versions of the language will parse spacing around binary operators. Later versions of the language will parse
these as unary operators instead so that ``echo $foo`` finally can do what these as unary operators instead so that ``echo $foo`` finally can do what
people expect it to do. people expect it to do.
- ``system.untyped`` and ``system.typed`` have been introduced as aliases
for ``expr`` and ``stmt``. The new names capture the semantics much better
and most likely ``expr`` and ``stmt`` will be deprecated in favor of the
new names.
- The ``split`` method in module ``re`` has changed. It now handles the case
of matches having a length of 0, and empty strings being yielded from the
iterator. A notable change might be that a pattern being matched at the
beginning and end of a string, will result in an empty string being produced
at the start and the end of the iterator.
Language Additions Language Additions
------------------ ------------------
@ -113,6 +121,8 @@ News
- Array and seq indexing can now use the builtin ``^`` operator to access - Array and seq indexing can now use the builtin ``^`` operator to access
things from backwards: ``a[^1]`` is like Python's ``a[-1]``. things from backwards: ``a[^1]`` is like Python's ``a[-1]``.
- A first version of the specification and implementation of the overloading
of the assignment operator has arrived!
Library additions Library additions