Merge branch 'devel' of github.com:Araq/Nim into patch2
This commit is contained in:
commit
f852988d11
87 changed files with 4950 additions and 4334 deletions
|
|
@ -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})
|
||||||
|
|
|
||||||
|
|
@ -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 = @[]
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) =
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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) =
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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"))
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ proc commandDoc2 =
|
||||||
finishDoc2Pass(gProjectName)
|
finishDoc2Pass(gProjectName)
|
||||||
|
|
||||||
proc commandCompileToC =
|
proc commandCompileToC =
|
||||||
|
extccomp.initVars()
|
||||||
semanticPasses()
|
semanticPasses()
|
||||||
registerPass(cgenPass)
|
registerPass(cgenPass)
|
||||||
rodPass()
|
rodPass()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
293
lib/js/dom.nim
293
lib/js/dom.nim
|
|
@ -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
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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}:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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`.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
1930
lib/pure/unicode.nim
1930
lib/pure/unicode.nim
File diff suppressed because it is too large
Load diff
131
lib/system.nim
131
lib/system.nim
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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) =
|
||||||
|
|
|
||||||
|
|
@ -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.}
|
||||||
|
|
|
||||||
|
|
@ -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.}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
10
tests/assign/moverload_asgn2.nim
Normal file
10
tests/assign/moverload_asgn2.nim
Normal 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
|
||||||
75
tests/assign/toverload_asgn1.nim
Normal file
75
tests/assign/toverload_asgn1.nim
Normal 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
|
||||||
22
tests/assign/toverload_asgn2.nim
Normal file
22
tests/assign/toverload_asgn2.nim
Normal 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()
|
||||||
9
tests/ccgbugs/tarray_equality.nim
Normal file
9
tests/ccgbugs/tarray_equality.nim
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
discard """
|
||||||
|
output: '''true'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #2489
|
||||||
|
|
||||||
|
let a = [1]
|
||||||
|
let b = [1]
|
||||||
|
echo a == b
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
14
tests/misc/tunsignedinc.nim
Normal file
14
tests/misc/tunsignedinc.nim
Normal 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
|
||||||
38
tests/overload/tstmtoverload.nim
Normal file
38
tests/overload/tstmtoverload.nim
Normal 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
|
||||||
39
tests/parallel/tgc_unsafe2.nim
Normal file
39
tests/parallel/tgc_unsafe2.nim
Normal 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()
|
||||||
|
|
@ -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
9
tests/stdlib/treloop.nim
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
discard """
|
||||||
|
output: "@[(, +, 1, 2, )]"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
let str = "(+ 1 2)"
|
||||||
|
var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
|
||||||
|
echo str.findAll(tokenRE)
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
10
tests/tuples/tuint_tuple.nim
Normal file
10
tests/tuples/tuint_tuple.nim
Normal 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)
|
||||||
|
]
|
||||||
|
|
||||||
4
todo.txt
4
todo.txt
|
|
@ -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
|
||||||
|
|
|
||||||
12
web/news.txt
12
web/news.txt
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue