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

This commit is contained in:
fowlmouth 2015-04-02 01:56:44 -05:00
commit 770914bc16
3 changed files with 277 additions and 249 deletions

View file

@ -11,7 +11,7 @@
# and sets of nodes are supported. Efficiency is important as # and sets of nodes are supported. Efficiency is important as
# the data structures here are used in various places of the compiler. # the data structures here are used in various places of the compiler.
import 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
@ -22,7 +22,7 @@ proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope
proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): PRope
proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope
proc lineInfoToStr*(info: TLineInfo): PRope proc lineInfoToStr*(info: TLineInfo): PRope
# ----------------------- node sets: --------------------------------------- # ----------------------- node sets: ---------------------------------------
proc objectSetContains*(t: TObjectSet, obj: RootRef): bool proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
# returns true whether n is in t # returns true whether n is in t
@ -34,10 +34,10 @@ proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
# ----------------------- (key, val)-Hashtables ---------------------------- # ----------------------- (key, val)-Hashtables ----------------------------
proc tablePut*(t: var TTable, key, val: RootRef) proc tablePut*(t: var TTable, key, val: RootRef)
proc tableGet*(t: TTable, key: RootRef): RootRef proc tableGet*(t: TTable, key: RootRef): RootRef
type type
TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found
proc tableSearch*(t: TTable, key, closure: RootRef, proc tableSearch*(t: TTable, key, closure: RootRef,
comparator: TCmpProc): RootRef comparator: TCmpProc): RootRef
# return val as soon as comparator returns true; if this never happens, # return val as soon as comparator returns true; if this never happens,
# nil is returned # nil is returned
@ -45,16 +45,16 @@ proc tableSearch*(t: TTable, key, closure: RootRef,
# ----------------------- str table ----------------------------------------- # ----------------------- str table -----------------------------------------
proc strTableContains*(t: TStrTable, n: PSym): bool proc strTableContains*(t: TStrTable, n: PSym): bool
proc strTableAdd*(t: var TStrTable, n: PSym) proc strTableAdd*(t: var TStrTable, n: PSym)
proc strTableGet*(t: TStrTable, name: PIdent): PSym proc strTableGet*(t: TStrTable, name: PIdent): PSym
type type
TTabIter*{.final.} = object # consider all fields here private TTabIter*{.final.} = object # consider all fields here private
h*: THash # current hash h*: THash # current hash
proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
# usage: # usage:
# var # var
# i: TTabIter # i: TTabIter
# s: PSym # s: PSym
# s = InitTabIter(i, table) # s = InitTabIter(i, table)
@ -63,7 +63,7 @@ proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
# s = NextIter(i, table) # s = NextIter(i, table)
# #
type type
TIdentIter*{.final.} = object # iterator over all syms with same identifier TIdentIter*{.final.} = object # iterator over all syms with same identifier
h*: THash # current hash h*: THash # current hash
name*: PIdent name*: PIdent
@ -97,11 +97,11 @@ proc mustRehash*(length, counter: int): bool
proc nextTry*(h, maxHash: THash): THash {.inline.} proc nextTry*(h, maxHash: THash): THash {.inline.}
# ------------- table[int, int] --------------------------------------------- # ------------- table[int, int] ---------------------------------------------
const const
InvalidKey* = low(int) InvalidKey* = low(int)
type type
TIIPair*{.final.} = object TIIPair*{.final.} = object
key*, val*: int key*, val*: int
TIIPairSeq* = seq[TIIPair] TIIPairSeq* = seq[TIIPair]
@ -127,21 +127,21 @@ proc skipConvAndClosure*(n: PNode): PNode =
result = result.sons[1] result = result.sons[1]
else: break else: break
proc sameValue*(a, b: PNode): bool = proc sameValue*(a, b: PNode): bool =
result = false result = false
case a.kind case a.kind
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: of nkFloatLit..nkFloat64Lit:
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
else: else:
# don't raise an internal error for 'nimrod check': # don't raise an internal error for 'nimrod check':
#InternalError(a.info, "SameValue") #InternalError(a.info, "SameValue")
discard discard
proc leValue*(a, b: PNode): bool = proc leValue*(a, b: PNode): bool =
# a <= b? # a <= b?
result = false result = false
case a.kind case a.kind
@ -162,66 +162,66 @@ proc weakLeValue*(a, b: PNode): TImplication =
else: else:
result = if leValue(a, b): impYes else: impNo result = if leValue(a, b): impYes else: impNo
proc lookupInRecord(n: PNode, field: PIdent): PSym = proc lookupInRecord(n: PNode, field: PIdent): 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):
result = lookupInRecord(n.sons[i], field) result = lookupInRecord(n.sons[i], field)
if result != nil: return if result != nil: return
of nkRecCase: of nkRecCase:
if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord") if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord")
result = lookupInRecord(n.sons[0], field) result = lookupInRecord(n.sons[0], field)
if result != nil: return if result != nil: return
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:
result = lookupInRecord(lastSon(n.sons[i]), field) result = lookupInRecord(lastSon(n.sons[i]), field)
if result != nil: return if result != nil: return
else: internalError(n.info, "lookupInRecord(record case branch)") else: internalError(n.info, "lookupInRecord(record case branch)")
of nkSym: of nkSym:
if n.sym.name.id == field.id: result = n.sym if n.sym.name.id == field.id: result = n.sym
else: internalError(n.info, "lookupInRecord()") else: internalError(n.info, "lookupInRecord()")
proc getModule(s: PSym): PSym = proc getModule(s: PSym): PSym =
result = s result = s
assert((result.kind == skModule) or (result.owner != result)) assert((result.kind == skModule) or (result.owner != result))
while result != nil and result.kind != skModule: result = result.owner while result != nil and result.kind != skModule: result = result.owner
proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym = proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
for i in countup(start, sonsLen(list) - 1): for i in countup(start, sonsLen(list) - 1):
if list.sons[i].kind == nkSym: if list.sons[i].kind == nkSym:
result = list.sons[i].sym result = list.sons[i].sym
if result.name.id == ident.id: return if result.name.id == ident.id: return
else: internalError(list.info, "getSymFromList") else: internalError(list.info, "getSymFromList")
result = nil result = nil
proc hashNode(p: RootRef): THash = proc hashNode(p: RootRef): THash =
result = hash(cast[pointer](p)) result = hash(cast[pointer](p))
proc mustRehash(length, counter: int): bool = 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): PRope =
# returns x spaces # returns x spaces
result = toRope(spaces(x)) result = toRope(spaces(x))
proc toYamlChar(c: char): string = proc toYamlChar(c: char): string =
case c case c
of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4) of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
of '\'', '\"', '\\': result = '\\' & c of '\'', '\"', '\\': result = '\\' & c
else: result = $c else: result = $c
proc makeYamlString*(s: string): PRope = proc makeYamlString*(s: string): PRope =
# 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.
const MaxLineLength = 64 const MaxLineLength = 64
result = nil result = nil
var res = "\"" var res = "\""
for i in countup(0, if s.isNil: -1 else: (len(s)-1)): for i in countup(0, if s.isNil: -1 else: (len(s)-1)):
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)) app(result, toRope(res))
@ -230,161 +230,161 @@ proc makeYamlString*(s: string): PRope =
add(res, '\"') add(res, '\"')
app(result, toRope(res)) app(result, toRope(res))
proc flagsToStr[T](flags: set[T]): PRope = proc flagsToStr[T](flags: set[T]): PRope =
if flags == {}: if flags == {}:
result = toRope("[]") result = toRope("[]")
else: else:
result = nil result = nil
for x in items(flags): for x in items(flags):
if result != nil: app(result, ", ") if result != nil: app(result, ", ")
app(result, makeYamlString($x)) app(result, makeYamlString($x))
result = con("[", con(result, "]")) result = con("[", con(result, "]"))
proc lineInfoToStr(info: TLineInfo): PRope = proc lineInfoToStr(info: TLineInfo): PRope =
result = ropef("[$1, $2, $3]", [makeYamlString(toFilename(info)), result = ropef("[$1, $2, $3]", [makeYamlString(toFilename(info)),
toRope(toLinenumber(info)), toRope(toLinenumber(info)),
toRope(toColumn(info))]) toRope(toColumn(info))])
proc treeToYamlAux(n: PNode, marker: var IntSet, proc treeToYamlAux(n: PNode, marker: var IntSet,
indent, maxRecDepth: int): PRope indent, maxRecDepth: int): PRope
proc symToYamlAux(n: PSym, marker: var IntSet, proc symToYamlAux(n: PSym, marker: var IntSet,
indent, maxRecDepth: int): PRope indent, maxRecDepth: int): PRope
proc typeToYamlAux(n: PType, marker: var IntSet, proc typeToYamlAux(n: PType, marker: var IntSet,
indent, maxRecDepth: int): PRope indent, maxRecDepth: int): PRope
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int, proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
maxRecDepth: int): PRope = maxRecDepth: int): PRope =
var istr = rspaces(indent + 2) var istr = rspaces(indent + 2)
result = toRope("[") result = toRope("[")
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: app(result, ",")
appf(result, "$N$1$2", appf(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: appf(result, "$N$1", [rspaces(indent)])
app(result, "]") app(result, "]")
assert(mycount == n.counter) assert(mycount == n.counter)
proc ropeConstr(indent: int, c: openArray[PRope]): PRope = proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
# array of (name, value) pairs # array of (name, value) pairs
var istr = rspaces(indent + 2) var istr = rspaces(indent + 2)
result = toRope("{") result = toRope("{")
var i = 0 var i = 0
while i <= high(c): while i <= high(c):
if i > 0: app(result, ",") if i > 0: app(result, ",")
appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]]) appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
inc(i, 2) inc(i, 2)
appf(result, "$N$1}", [rspaces(indent)]) appf(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): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
elif containsOrIncl(marker, n.id): elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope( result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
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, [toRope("kind"),
makeYamlString($n.kind), makeYamlString($n.kind),
toRope("name"), makeYamlString(n.name.s), toRope("name"), makeYamlString(n.name.s),
toRope("typ"), typeToYamlAux(n.typ, marker, toRope("typ"), typeToYamlAux(n.typ, marker,
indent + 2, maxRecDepth - 1), indent + 2, maxRecDepth - 1),
toRope("info"), lineInfoToStr(n.info), toRope("info"), lineInfoToStr(n.info),
toRope("flags"), flagsToStr(n.flags), toRope("flags"), flagsToStr(n.flags),
toRope("magic"), makeYamlString($n.magic), toRope("magic"), makeYamlString($n.magic),
toRope("ast"), ast, toRope("options"), toRope("ast"), ast, toRope("options"),
flagsToStr(n.options), toRope("position"), flagsToStr(n.options), toRope("position"),
toRope(n.position)]) toRope(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): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
elif containsOrIncl(marker, n.id): elif containsOrIncl(marker, n.id):
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope( result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
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 = toRope("[")
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: app(result, ",") if i > 0: app(result, ",")
appf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i], appf(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)]) appf(result, "$N$1]", [rspaces(indent + 2)])
else: else:
result = toRope("null") result = toRope("null")
result = ropeConstr(indent, [toRope("kind"), result = ropeConstr(indent, [toRope("kind"),
makeYamlString($n.kind), makeYamlString($n.kind),
toRope("sym"), symToYamlAux(n.sym, marker, toRope("sym"), symToYamlAux(n.sym, marker,
indent + 2, maxRecDepth - 1), toRope("n"), treeToYamlAux(n.n, marker, indent + 2, maxRecDepth - 1), toRope("n"), treeToYamlAux(n.n, marker,
indent + 2, maxRecDepth - 1), toRope("flags"), flagsToStr(n.flags), indent + 2, maxRecDepth - 1), toRope("flags"), flagsToStr(n.flags),
toRope("callconv"), toRope("callconv"),
makeYamlString(CallingConvToStr[n.callConv]), makeYamlString(CallingConvToStr[n.callConv]),
toRope("size"), toRope(n.size), toRope("size"), toRope(n.size),
toRope("align"), toRope(n.align), toRope("align"), toRope(n.align),
toRope("sons"), result]) toRope("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): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
else: else:
var istr = rspaces(indent + 2) var istr = rspaces(indent + 2)
result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)]) result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
if maxRecDepth != 0: if maxRecDepth != 0:
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) appf(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)]) appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, ",$N$1\"floatVal\": $2", appf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.toStrMaxPrecision)]) [istr, toRope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if n.strVal.isNil: if n.strVal.isNil:
appf(result, ",$N$1\"strVal\": null", [istr]) appf(result, ",$N$1\"strVal\": null", [istr])
else: else:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym: of nkSym:
appf(result, ",$N$1\"sym\": $2", appf(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)]) appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
else: else:
appf(result, ",$N$1\"ident\": null", [istr]) appf(result, ",$N$1\"ident\": null", [istr])
else: else:
if sonsLen(n) > 0: if sonsLen(n) > 0:
appf(result, ",$N$1\"sons\": [", [istr]) appf(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: app(result, ",")
appf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i], appf(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]) appf(result, "$N$1]", [istr])
appf(result, ",$N$1\"typ\": $2", appf(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)]) appf(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): PRope =
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): PRope =
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): PRope =
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): PRope
proc debugType(n: PType, maxRecDepth=100): PRope = proc debugType(n: PType, maxRecDepth=100): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
else: else:
result = toRope($n.kind) result = toRope($n.kind)
if n.sym != nil: if n.sym != nil:
app(result, " ") app(result, " ")
app(result, n.sym.name.s) app(result, n.sym.name.s)
if n.kind in IntegralTypes and n.n != nil: if n.kind in IntegralTypes and n.n != nil:
@ -404,43 +404,43 @@ proc debugType(n: PType, maxRecDepth=100): PRope =
app(result, ")") app(result, ")")
proc debugTree(n: PNode, indent: int, maxRecDepth: int; proc debugTree(n: PNode, indent: int, maxRecDepth: int;
renderType=false): PRope = renderType=false): PRope =
if n == nil: if n == nil:
result = toRope("null") result = toRope("null")
else: else:
var istr = rspaces(indent + 2) var istr = rspaces(indent + 2)
result = ropef("{$N$1\"kind\": $2", result = ropef("{$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)]) appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, ",$N$1\"floatVal\": $2", appf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.toStrMaxPrecision)]) [istr, toRope(n.floatVal.toStrMaxPrecision)])
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if n.strVal.isNil: if n.strVal.isNil:
appf(result, ",$N$1\"strVal\": null", [istr]) appf(result, ",$N$1\"strVal\": null", [istr])
else: else:
appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym: of nkSym:
appf(result, ",$N$1\"sym\": $2_$3", appf(result, ",$N$1\"sym\": $2_$3",
[istr, toRope(n.sym.name.s), toRope(n.sym.id)]) [istr, toRope(n.sym.name.s), toRope(n.sym.id)])
# [istr, symToYaml(n.sym, indent, maxRecDepth), # [istr, symToYaml(n.sym, indent, maxRecDepth),
# toRope(n.sym.id)]) # toRope(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)]) appf(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)]) appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
else: else:
appf(result, ",$N$1\"ident\": null", [istr]) appf(result, ",$N$1\"ident\": null", [istr])
else: else:
if sonsLen(n) > 0: if sonsLen(n) > 0:
appf(result, ",$N$1\"sons\": [", [istr]) appf(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: app(result, ",")
appf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i], appf(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]) appf(result, "$N$1]", [istr])
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)]) appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
@ -454,25 +454,25 @@ proc debug(n: PSym) =
else: else:
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1))) #writeln(stdout, ropeToStr(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).ropeToStr,
flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr, flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr,
$n.kind]) $n.kind])
proc debug(n: PType) = proc debug(n: PType) =
msgWriteln(ropeToStr(debugType(n))) msgWriteln(ropeToStr(debugType(n)))
proc debug(n: PNode) = proc debug(n: PNode) =
msgWriteln(ropeToStr(debugTree(n, 0, 100))) msgWriteln(ropeToStr(debugTree(n, 0, 100)))
const const
EmptySeq = @[] EmptySeq = @[]
proc nextTry(h, maxHash: THash): THash = proc nextTry(h, maxHash: THash): THash =
result = ((5 * h) + 1) and maxHash result = ((5 * h) + 1) and maxHash
# For any initial h in range(maxHash), repeating that maxHash times # For any initial h in range(maxHash), repeating that maxHash times
# generates each int in range(maxHash) exactly once (see any text on # generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof). # random-number generation for proof).
proc objectSetContains(t: TObjectSet, obj: RootRef): bool = proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
# returns true whether n is in t # returns true whether n is in t
var h: THash = hashNode(obj) and high(t.data) # start with real hash value var h: THash = hashNode(obj) and high(t.data) # start with real hash value
@ -490,94 +490,94 @@ proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
assert(data[h] == nil) assert(data[h] == nil)
data[h] = obj data[h] = obj
proc objectSetEnlarge(t: var TObjectSet) = proc objectSetEnlarge(t: var TObjectSet) =
var n: TObjectSeq var n: TObjectSeq
newSeq(n, len(t.data) * GrowthFactor) newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)): for i in countup(0, high(t.data)):
if t.data[i] != nil: objectSetRawInsert(n, t.data[i]) if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
swap(t.data, n) swap(t.data, n)
proc objectSetIncl(t: var TObjectSet, obj: RootRef) = proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
if mustRehash(len(t.data), t.counter): objectSetEnlarge(t) if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
objectSetRawInsert(t.data, obj) objectSetRawInsert(t.data, obj)
inc(t.counter) inc(t.counter)
proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool = proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
# returns true if obj is already in the string table: # returns true if obj is already in the string table:
var h: THash = hashNode(obj) and high(t.data) var h: THash = hashNode(obj) and high(t.data)
while true: while true:
var it = t.data[h] var it = t.data[h]
if it == nil: break if it == nil: break
if it == obj: if it == obj:
return true # found it return true # found it
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
if mustRehash(len(t.data), t.counter): if mustRehash(len(t.data), t.counter):
objectSetEnlarge(t) objectSetEnlarge(t)
objectSetRawInsert(t.data, obj) objectSetRawInsert(t.data, obj)
else: else:
assert(t.data[h] == nil) assert(t.data[h] == nil)
t.data[h] = obj t.data[h] = obj
inc(t.counter) inc(t.counter)
result = false result = false
proc tableRawGet(t: TTable, key: RootRef): int = proc tableRawGet(t: TTable, key: RootRef): int =
var h: THash = hashNode(key) and high(t.data) # start with real hash value var h: THash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil: while t.data[h].key != nil:
if t.data[h].key == key: if t.data[h].key == key:
return h return h
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = -1 result = -1
proc tableSearch(t: TTable, key, closure: RootRef, proc tableSearch(t: TTable, key, closure: RootRef,
comparator: TCmpProc): RootRef = comparator: TCmpProc): RootRef =
var h: THash = hashNode(key) and high(t.data) # start with real hash value var h: THash = hashNode(key) and high(t.data) # start with real hash value
while t.data[h].key != nil: while t.data[h].key != nil:
if t.data[h].key == key: if t.data[h].key == key:
if comparator(t.data[h].val, closure): if comparator(t.data[h].val, closure):
# BUGFIX 1 # BUGFIX 1
return t.data[h].val return t.data[h].val
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = nil result = nil
proc tableGet(t: TTable, key: RootRef): RootRef = proc tableGet(t: TTable, key: RootRef): RootRef =
var index = tableRawGet(t, key) var index = tableRawGet(t, key)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: result = nil else: result = nil
proc tableRawInsert(data: var TPairSeq, key, val: RootRef) = proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
var h: THash = hashNode(key) and high(data) var h: THash = hashNode(key) and high(data)
while data[h].key != nil: while data[h].key != nil:
assert(data[h].key != key) assert(data[h].key != key)
h = nextTry(h, high(data)) h = nextTry(h, high(data))
assert(data[h].key == nil) assert(data[h].key == nil)
data[h].key = key data[h].key = key
data[h].val = val data[h].val = val
proc tableEnlarge(t: var TTable) = proc tableEnlarge(t: var TTable) =
var n: TPairSeq var n: TPairSeq
newSeq(n, len(t.data) * GrowthFactor) newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)): for i in countup(0, high(t.data)):
if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val) if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n) swap(t.data, n)
proc tablePut(t: var TTable, key, val: RootRef) = proc tablePut(t: var TTable, key, val: RootRef) =
var index = tableRawGet(t, key) var index = tableRawGet(t, key)
if index >= 0: if index >= 0:
t.data[index].val = val t.data[index].val = val
else: else:
if mustRehash(len(t.data), t.counter): tableEnlarge(t) if mustRehash(len(t.data), t.counter): tableEnlarge(t)
tableRawInsert(t.data, key, val) tableRawInsert(t.data, key, val)
inc(t.counter) inc(t.counter)
proc strTableContains(t: TStrTable, n: PSym): bool = proc strTableContains(t: TStrTable, n: PSym): bool =
var h: THash = n.name.h and high(t.data) # start with real hash value var h: THash = n.name.h and high(t.data) # start with real hash value
while t.data[h] != nil: while t.data[h] != nil:
if (t.data[h] == n): if (t.data[h] == n):
return true return true
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = false result = false
proc strTableRawInsert(data: var TSymSeq, n: PSym) = proc strTableRawInsert(data: var TSymSeq, n: PSym) =
var h: THash = n.name.h and high(data) var h: THash = n.name.h and high(data)
if sfImmediate notin n.flags: if sfImmediate notin n.flags:
# fast path: # fast path:
@ -614,18 +614,18 @@ proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
return return
h = nextTry(h, high(data)) h = nextTry(h, high(data))
assert false assert false
proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) = proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
symTabReplaceRaw(t.data, prevSym, newSym) symTabReplaceRaw(t.data, prevSym, newSym)
proc strTableEnlarge(t: var TStrTable) = proc strTableEnlarge(t: var TStrTable) =
var n: TSymSeq var n: TSymSeq
newSeq(n, len(t.data) * GrowthFactor) newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)): for i in countup(0, high(t.data)):
if t.data[i] != nil: strTableRawInsert(n, t.data[i]) if t.data[i] != nil: strTableRawInsert(n, t.data[i])
swap(t.data, n) swap(t.data, n)
proc strTableAdd(t: var TStrTable, n: PSym) = proc strTableAdd(t: var TStrTable, n: PSym) =
if mustRehash(len(t.data), t.counter): strTableEnlarge(t) if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
strTableRawInsert(t.data, n) strTableRawInsert(t.data, n)
inc(t.counter) inc(t.counter)
@ -666,103 +666,103 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
inc(t.counter) inc(t.counter)
result = false result = false
proc strTableGet(t: TStrTable, name: PIdent): PSym = proc strTableGet(t: TStrTable, name: PIdent): PSym =
var h: THash = name.h and high(t.data) var h: THash = name.h and high(t.data)
while true: while true:
result = t.data[h] result = t.data[h]
if result == nil: break if result == nil: break
if result.name.id == name.id: break if result.name.id == name.id: break
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym = proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
ti.h = s.h ti.h = s.h
ti.name = s ti.name = s
if tab.counter == 0: result = nil if tab.counter == 0: result = nil
else: result = nextIdentIter(ti, tab) else: result = nextIdentIter(ti, tab)
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
var h = ti.h and high(tab.data) var h = ti.h and high(tab.data)
var start = h var start = h
result = tab.data[h] result = tab.data[h]
while result != nil: while result != nil:
if result.name.id == ti.name.id: break if result.name.id == ti.name.id: break
h = nextTry(h, high(tab.data)) h = nextTry(h, high(tab.data))
if h == start: if h == start:
result = nil result = nil
break break
result = tab.data[h] result = tab.data[h]
ti.h = nextTry(h, high(tab.data)) ti.h = nextTry(h, high(tab.data))
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
excluding: IntSet): PSym = excluding: IntSet): PSym =
var h: THash = ti.h and high(tab.data) var h: THash = ti.h and high(tab.data)
var start = h var start = h
result = tab.data[h] result = tab.data[h]
while result != nil: while result != nil:
if result.name.id == ti.name.id and not contains(excluding, result.id): if result.name.id == ti.name.id and not contains(excluding, result.id):
break break
h = nextTry(h, high(tab.data)) h = nextTry(h, high(tab.data))
if h == start: if h == start:
result = nil result = nil
break break
result = tab.data[h] result = tab.data[h]
ti.h = nextTry(h, high(tab.data)) ti.h = nextTry(h, high(tab.data))
if result != nil and contains(excluding, result.id): result = nil if result != nil and contains(excluding, result.id): result = nil
proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent, proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
excluding: IntSet): PSym = excluding: IntSet): PSym =
ti.h = s.h ti.h = s.h
ti.name = s ti.name = s
if tab.counter == 0: result = nil if tab.counter == 0: result = nil
else: result = nextIdentExcluding(ti, tab, excluding) else: result = nextIdentExcluding(ti, tab, excluding)
proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym = proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym =
ti.h = 0 # we start by zero ... ti.h = 0 # we start by zero ...
if tab.counter == 0: if tab.counter == 0:
result = nil # FIX 1: removed endless loop result = nil # FIX 1: removed endless loop
else: else:
result = nextIter(ti, tab) result = nextIter(ti, tab)
proc nextIter(ti: var TTabIter, tab: TStrTable): PSym = proc nextIter(ti: var TTabIter, tab: TStrTable): PSym =
result = nil result = nil
while (ti.h <= high(tab.data)): while (ti.h <= high(tab.data)):
result = tab.data[ti.h] result = tab.data[ti.h]
inc(ti.h) # ... and increment by one always inc(ti.h) # ... and increment by one always
if result != nil: break if result != nil: break
iterator items*(tab: TStrTable): PSym = iterator items*(tab: TStrTable): PSym =
var it: TTabIter var it: TTabIter
var s = initTabIter(it, tab) var s = initTabIter(it, tab)
while s != nil: while s != nil:
yield s yield s
s = nextIter(it, tab) s = nextIter(it, tab)
proc hasEmptySlot(data: TIdPairSeq): bool = proc hasEmptySlot(data: TIdPairSeq): bool =
for h in countup(0, high(data)): for h in countup(0, high(data)):
if data[h].key == nil: if data[h].key == nil:
return true return true
result = false result = false
proc idTableRawGet(t: TIdTable, key: int): int = proc idTableRawGet(t: TIdTable, key: int): int =
var h: THash var h: THash
h = key and high(t.data) # start with real hash value h = key and high(t.data) # start with real hash value
while t.data[h].key != nil: while t.data[h].key != nil:
if t.data[h].key.id == key: if t.data[h].key.id == key:
return h return h
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = - 1 result = - 1
proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool = proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
var index = idTableRawGet(t, key.id) var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].key == key if index >= 0: result = t.data[index].key == key
else: result = false else: result = false
proc idTableGet(t: TIdTable, key: PIdObj): RootRef = proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
var index = idTableRawGet(t, key.id) var index = idTableRawGet(t, key.id)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: result = nil else: result = nil
proc idTableGet(t: TIdTable, key: int): RootRef = proc idTableGet(t: TIdTable, key: int): RootRef =
var index = idTableRawGet(t, key) var index = idTableRawGet(t, key)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: result = nil else: result = nil
@ -771,30 +771,30 @@ iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
for i in 0..high(t.data): for i in 0..high(t.data):
if t.data[i].key != nil: if t.data[i].key != nil:
yield (t.data[i].key.id, t.data[i].val) yield (t.data[i].key.id, t.data[i].val)
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) = proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
var h: THash var h: THash
h = key.id and high(data) h = key.id and high(data)
while data[h].key != nil: while data[h].key != nil:
assert(data[h].key.id != key.id) assert(data[h].key.id != key.id)
h = nextTry(h, high(data)) h = nextTry(h, high(data))
assert(data[h].key == nil) assert(data[h].key == nil)
data[h].key = key data[h].key = key
data[h].val = val data[h].val = val
proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) = proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
var var
index: int index: int
n: TIdPairSeq n: TIdPairSeq
index = idTableRawGet(t, key.id) index = idTableRawGet(t, key.id)
if index >= 0: if index >= 0:
assert(t.data[index].key != nil) assert(t.data[index].key != nil)
t.data[index].val = val t.data[index].val = val
else: else:
if mustRehash(len(t.data), t.counter): if mustRehash(len(t.data), t.counter):
newSeq(n, len(t.data) * GrowthFactor) newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)): for i in countup(0, high(t.data)):
if t.data[i].key != nil: if t.data[i].key != nil:
idTableRawInsert(n, t.data[i].key, t.data[i].val) idTableRawInsert(n, t.data[i].key, t.data[i].val)
assert(hasEmptySlot(n)) assert(hasEmptySlot(n))
swap(t.data, n) swap(t.data, n)
@ -805,7 +805,7 @@ iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
for i in 0 .. high(t.data): for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val) if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int = proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
var h: THash var h: THash
h = key.id and high(t.data) # start with real hash value h = key.id and high(t.data) # start with real hash value
while t.data[h].key != nil: while t.data[h].key != nil:
@ -814,7 +814,7 @@ proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = - 1 result = - 1
proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode = proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
var index: int var index: int
index = idNodeTableRawGet(t, key) index = idNodeTableRawGet(t, key)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
@ -823,28 +823,28 @@ proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode = proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
if not isNil(t.data): if not isNil(t.data):
result = idNodeTableGet(t, key) result = idNodeTableGet(t, key)
proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) = proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
var h: THash var h: THash
h = key.id and high(data) h = key.id and high(data)
while data[h].key != nil: while data[h].key != nil:
assert(data[h].key.id != key.id) assert(data[h].key.id != key.id)
h = nextTry(h, high(data)) h = nextTry(h, high(data))
assert(data[h].key == nil) assert(data[h].key == nil)
data[h].key = key data[h].key = key
data[h].val = val data[h].val = val
proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) = proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
var index = idNodeTableRawGet(t, key) var index = idNodeTableRawGet(t, key)
if index >= 0: if index >= 0:
assert(t.data[index].key != nil) assert(t.data[index].key != nil)
t.data[index].val = val t.data[index].val = val
else: else:
if mustRehash(len(t.data), t.counter): if mustRehash(len(t.data), t.counter):
var n: TIdNodePairSeq var n: TIdNodePairSeq
newSeq(n, len(t.data) * GrowthFactor) newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(t.data)): for i in countup(0, high(t.data)):
if t.data[i].key != nil: if t.data[i].key != nil:
idNodeTableRawInsert(n, t.data[i].key, t.data[i].val) idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n) swap(t.data, n)
idNodeTableRawInsert(t.data, key, val) idNodeTableRawInsert(t.data, key, val)
@ -858,46 +858,46 @@ iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
for i in 0 .. high(t.data): for i in 0 .. high(t.data):
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val) if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
proc initIITable(x: var TIITable) = proc initIITable(x: var TIITable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
proc iiTableRawGet(t: TIITable, key: int): int = proc iiTableRawGet(t: TIITable, key: int): int =
var h: THash var h: THash
h = key and high(t.data) # start with real hash value h = key and high(t.data) # start with real hash value
while t.data[h].key != InvalidKey: while t.data[h].key != InvalidKey:
if t.data[h].key == key: return h if t.data[h].key == key: return h
h = nextTry(h, high(t.data)) h = nextTry(h, high(t.data))
result = -1 result = -1
proc iiTableGet(t: TIITable, key: int): int = proc iiTableGet(t: TIITable, key: int): int =
var index = iiTableRawGet(t, key) var index = iiTableRawGet(t, key)
if index >= 0: result = t.data[index].val if index >= 0: result = t.data[index].val
else: result = InvalidKey else: result = InvalidKey
proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) = proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
var h: THash var h: THash
h = key and high(data) h = key and high(data)
while data[h].key != InvalidKey: while data[h].key != InvalidKey:
assert(data[h].key != key) assert(data[h].key != key)
h = nextTry(h, high(data)) h = nextTry(h, high(data))
assert(data[h].key == InvalidKey) assert(data[h].key == InvalidKey)
data[h].key = key data[h].key = key
data[h].val = val data[h].val = val
proc iiTablePut(t: var TIITable, key, val: int) = proc iiTablePut(t: var TIITable, key, val: int) =
var index = iiTableRawGet(t, key) var index = iiTableRawGet(t, key)
if index >= 0: if index >= 0:
assert(t.data[index].key != InvalidKey) assert(t.data[index].key != InvalidKey)
t.data[index].val = val t.data[index].val = val
else: else:
if mustRehash(len(t.data), t.counter): if mustRehash(len(t.data), t.counter):
var n: TIIPairSeq var n: TIIPairSeq
newSeq(n, len(t.data) * GrowthFactor) newSeq(n, len(t.data) * GrowthFactor)
for i in countup(0, high(n)): n[i].key = InvalidKey for i in countup(0, high(n)): n[i].key = InvalidKey
for i in countup(0, high(t.data)): for i in countup(0, high(t.data)):
if t.data[i].key != InvalidKey: if t.data[i].key != InvalidKey:
iiTableRawInsert(n, t.data[i].key, t.data[i].val) iiTableRawInsert(n, t.data[i].key, t.data[i].val)
swap(t.data, n) swap(t.data, n)
iiTableRawInsert(t.data, key, val) iiTableRawInsert(t.data, key, val)

View file

@ -291,6 +291,24 @@ y.v() --> y.v() is correct
""" """
proc skipAddrDeref(node: PNode): PNode =
var n = node
var isAddr = false
case n.kind
of nkAddr, nkHiddenAddr:
n = n.sons[0]
isAddr = true
of nkDerefExpr, nkHiddenDeref:
n = n.sons[0]
else: return n
if n.kind == nkObjDownConv: n = n.sons[0]
if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}:
result = n.sons[0]
elif n.kind in {nkAddr, nkHiddenAddr}:
result = n.sons[0]
else:
result = node
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope = proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
# 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
@ -301,7 +319,8 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
# skip the deref: # skip the deref:
var ri = ri[i] var ri = ri[i]
while ri.kind == nkObjDownConv: ri = ri[0] while ri.kind == nkObjDownConv: ri = ri[0]
if typ.sons[i].kind == tyVar: let t = typ.sons[i].skipTypes({tyGenericInst})
if t.kind == tyVar:
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)
@ -312,7 +331,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
else: else:
result = genArgNoParam(p, x) result = genArgNoParam(p, x)
result.app(".") result.app(".")
elif typ.sons[i].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.app(".")
@ -320,6 +339,8 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
result = genArgNoParam(p, ri) result = genArgNoParam(p, ri)
result.app("->") result.app("->")
else: else:
ri = skipAddrDeref(ri)
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.app(".")
@ -354,6 +375,11 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
elif pat[i+1] == '.': elif pat[i+1] == '.':
result.app genThisArg(p, ri, j, typ) result.app genThisArg(p, ri, j, typ)
inc i inc i
elif pat[i+1] == '[':
var arg = ri.sons[j].skipAddrDeref
while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
result.app genArgNoParam(p, arg)
#result.app debugTree(arg, 0, 10)
else: else:
result.app genOtherArg(p, ri, j, typ) result.app genOtherArg(p, ri, j, typ)
inc j inc j

View file

@ -541,6 +541,8 @@ elif defined(JS):
proc getTimezone(): int = result = newDate().getTimezoneOffset() proc getTimezone(): int = result = newDate().getTimezoneOffset()
proc epochTime*(): float {.tags: [TimeEffect].} = newDate().toSeconds()
proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
## gets the current date as a string of the format ``YYYY-MM-DD``. ## gets the current date as a string of the format ``YYYY-MM-DD``.
var ti = getLocalTime(getTime()) var ti = getLocalTime(getTime())