Merged
|
|
@ -726,9 +726,6 @@ type
|
||||||
flags*: TLocFlags # location's flags
|
flags*: TLocFlags # location's flags
|
||||||
t*: PType # type of location
|
t*: PType # type of location
|
||||||
r*: Rope # rope value of location (code generators)
|
r*: Rope # rope value of location (code generators)
|
||||||
heapRoot*: Rope # keeps track of the enclosing heap object that
|
|
||||||
# owns this location (required by GC algorithms
|
|
||||||
# employing heap snapshots or sliding views)
|
|
||||||
|
|
||||||
# ---------------- end of backend information ------------------------------
|
# ---------------- end of backend information ------------------------------
|
||||||
|
|
||||||
|
|
@ -857,9 +854,6 @@ type
|
||||||
key*, val*: RootRef
|
key*, val*: RootRef
|
||||||
|
|
||||||
TPairSeq* = seq[TPair]
|
TPairSeq* = seq[TPair]
|
||||||
TTable* = object # the same as table[PObject] of PObject
|
|
||||||
counter*: int
|
|
||||||
data*: TPairSeq
|
|
||||||
|
|
||||||
TIdPair* = object
|
TIdPair* = object
|
||||||
key*: PIdObj
|
key*: PIdObj
|
||||||
|
|
@ -1103,12 +1097,6 @@ proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
|
||||||
newSeq(dest.data, len(src.data))
|
newSeq(dest.data, len(src.data))
|
||||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||||
|
|
||||||
proc copyTable*(dest: var TTable, src: TTable) =
|
|
||||||
dest.counter = src.counter
|
|
||||||
if isNil(src.data): return
|
|
||||||
setLen(dest.data, len(src.data))
|
|
||||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
|
||||||
|
|
||||||
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
||||||
dest.counter = src.counter
|
dest.counter = src.counter
|
||||||
if isNil(src.data): return
|
if isNil(src.data): return
|
||||||
|
|
@ -1322,10 +1310,6 @@ proc initStrTable*(x: var TStrTable) =
|
||||||
proc newStrTable*: TStrTable =
|
proc newStrTable*: TStrTable =
|
||||||
initStrTable(result)
|
initStrTable(result)
|
||||||
|
|
||||||
proc initTable(x: var TTable) =
|
|
||||||
x.counter = 0
|
|
||||||
newSeq(x.data, StartSize)
|
|
||||||
|
|
||||||
proc initIdTable*(x: var TIdTable) =
|
proc initIdTable*(x: var TIdTable) =
|
||||||
x.counter = 0
|
x.counter = 0
|
||||||
newSeq(x.data, StartSize)
|
newSeq(x.data, StartSize)
|
||||||
|
|
@ -1506,19 +1490,9 @@ proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
|
||||||
return true
|
return true
|
||||||
result = false
|
result = false
|
||||||
|
|
||||||
proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
|
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
|
||||||
if n.sons[i].kind == oldKind: n.sons[i].kind = newKind
|
|
||||||
|
|
||||||
proc sonsNotNil(n: PNode): bool =
|
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
|
||||||
if n.sons[i] == nil:
|
|
||||||
return false
|
|
||||||
result = true
|
|
||||||
|
|
||||||
proc getInt*(a: PNode): BiggestInt =
|
proc getInt*(a: PNode): BiggestInt =
|
||||||
case a.kind
|
case a.kind
|
||||||
of nkIntLit..nkUInt64Lit: result = a.intVal
|
of nkCharLit..nkUInt64Lit: result = a.intVal
|
||||||
else:
|
else:
|
||||||
internalError(a.info, "getInt")
|
internalError(a.info, "getInt")
|
||||||
result = 0
|
result = 0
|
||||||
|
|
|
||||||
|
|
@ -31,17 +31,6 @@ proc objectSetIncl*(t: var TObjectSet, obj: RootRef)
|
||||||
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
|
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
|
||||||
# more are not needed ...
|
# more are not needed ...
|
||||||
|
|
||||||
# ----------------------- (key, val)-Hashtables ----------------------------
|
|
||||||
proc tablePut*(t: var TTable, key, val: RootRef)
|
|
||||||
proc tableGet*(t: TTable, key: RootRef): RootRef
|
|
||||||
type
|
|
||||||
TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found
|
|
||||||
|
|
||||||
proc tableSearch*(t: TTable, key, closure: RootRef,
|
|
||||||
comparator: TCmpProc): RootRef
|
|
||||||
# return val as soon as comparator returns true; if this never happens,
|
|
||||||
# nil is returned
|
|
||||||
|
|
||||||
# ----------------------- 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)
|
||||||
|
|
@ -251,20 +240,6 @@ proc symToYamlAux(n: PSym, marker: var IntSet,
|
||||||
indent, maxRecDepth: int): Rope
|
indent, maxRecDepth: int): Rope
|
||||||
proc typeToYamlAux(n: PType, marker: var IntSet,
|
proc typeToYamlAux(n: PType, marker: var IntSet,
|
||||||
indent, maxRecDepth: int): Rope
|
indent, maxRecDepth: int): Rope
|
||||||
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
|
||||||
maxRecDepth: int): Rope =
|
|
||||||
var istr = rspaces(indent + 2)
|
|
||||||
result = rope("[")
|
|
||||||
var mycount = 0
|
|
||||||
for i in countup(0, high(n.data)):
|
|
||||||
if n.data[i] != nil:
|
|
||||||
if mycount > 0: add(result, ",")
|
|
||||||
addf(result, "$N$1$2",
|
|
||||||
[istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
|
|
||||||
inc(mycount)
|
|
||||||
if mycount > 0: addf(result, "$N$1", [rspaces(indent)])
|
|
||||||
add(result, "]")
|
|
||||||
assert(mycount == n.counter)
|
|
||||||
|
|
||||||
proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
|
proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
|
||||||
# array of (name, value) pairs
|
# array of (name, value) pairs
|
||||||
|
|
@ -463,9 +438,6 @@ proc debug(n: PType) =
|
||||||
proc debug(n: PNode) =
|
proc debug(n: PNode) =
|
||||||
echo($debugTree(n, 0, 100))
|
echo($debugTree(n, 0, 100))
|
||||||
|
|
||||||
const
|
|
||||||
EmptySeq = @[]
|
|
||||||
|
|
||||||
proc nextTry(h, maxHash: Hash): Hash =
|
proc nextTry(h, maxHash: Hash): Hash =
|
||||||
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
|
||||||
|
|
@ -519,55 +491,6 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
result = false
|
result = false
|
||||||
|
|
||||||
proc tableRawGet(t: TTable, key: RootRef): int =
|
|
||||||
var h: Hash = hashNode(key) and high(t.data) # start with real hash value
|
|
||||||
while t.data[h].key != nil:
|
|
||||||
if t.data[h].key == key:
|
|
||||||
return h
|
|
||||||
h = nextTry(h, high(t.data))
|
|
||||||
result = -1
|
|
||||||
|
|
||||||
proc tableSearch(t: TTable, key, closure: RootRef,
|
|
||||||
comparator: TCmpProc): RootRef =
|
|
||||||
var h: Hash = hashNode(key) and high(t.data) # start with real hash value
|
|
||||||
while t.data[h].key != nil:
|
|
||||||
if t.data[h].key == key:
|
|
||||||
if comparator(t.data[h].val, closure):
|
|
||||||
# BUGFIX 1
|
|
||||||
return t.data[h].val
|
|
||||||
h = nextTry(h, high(t.data))
|
|
||||||
result = nil
|
|
||||||
|
|
||||||
proc tableGet(t: TTable, key: RootRef): RootRef =
|
|
||||||
var index = tableRawGet(t, key)
|
|
||||||
if index >= 0: result = t.data[index].val
|
|
||||||
else: result = nil
|
|
||||||
|
|
||||||
proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
|
|
||||||
var h: Hash = hashNode(key) and high(data)
|
|
||||||
while data[h].key != nil:
|
|
||||||
assert(data[h].key != key)
|
|
||||||
h = nextTry(h, high(data))
|
|
||||||
assert(data[h].key == nil)
|
|
||||||
data[h].key = key
|
|
||||||
data[h].val = val
|
|
||||||
|
|
||||||
proc tableEnlarge(t: var TTable) =
|
|
||||||
var n: TPairSeq
|
|
||||||
newSeq(n, len(t.data) * GrowthFactor)
|
|
||||||
for i in countup(0, high(t.data)):
|
|
||||||
if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
|
|
||||||
swap(t.data, n)
|
|
||||||
|
|
||||||
proc tablePut(t: var TTable, key, val: RootRef) =
|
|
||||||
var index = tableRawGet(t, key)
|
|
||||||
if index >= 0:
|
|
||||||
t.data[index].val = val
|
|
||||||
else:
|
|
||||||
if mustRehash(len(t.data), t.counter): tableEnlarge(t)
|
|
||||||
tableRawInsert(t.data, key, val)
|
|
||||||
inc(t.counter)
|
|
||||||
|
|
||||||
proc strTableContains(t: TStrTable, n: PSym): bool =
|
proc strTableContains(t: TStrTable, n: PSym): bool =
|
||||||
var h: Hash = n.name.h and high(t.data) # start with real hash value
|
var h: Hash = n.name.h and high(t.data) # start with real hash value
|
||||||
while t.data[h] != nil:
|
while t.data[h] != nil:
|
||||||
|
|
|
||||||
|
|
@ -411,7 +411,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
|
||||||
add(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: TLoc
|
||||||
initLocExpr(p, ri.sons[0], op)
|
initLocExpr(p, ri.sons[0], op)
|
||||||
# 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)
|
||||||
|
|
@ -458,7 +458,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
|
|
||||||
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||||
# generates a crappy ObjC call
|
# generates a crappy ObjC call
|
||||||
var op, a: TLoc
|
var op: TLoc
|
||||||
initLocExpr(p, ri.sons[0], op)
|
initLocExpr(p, ri.sons[0], op)
|
||||||
var pl = ~"["
|
var pl = ~"["
|
||||||
# getUniqueType() is too expensive here:
|
# getUniqueType() is too expensive here:
|
||||||
|
|
@ -536,8 +536,6 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
|
||||||
else:
|
else:
|
||||||
genPrefixCall(p, nil, e, d)
|
genPrefixCall(p, nil, e, d)
|
||||||
postStmtActions(p)
|
postStmtActions(p)
|
||||||
when false:
|
|
||||||
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
|
|
||||||
|
|
||||||
proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
if ri.sons[0].typ.skipTypes({tyGenericInst}).callConv == ccClosure:
|
if ri.sons[0].typ.skipTypes({tyGenericInst}).callConv == ccClosure:
|
||||||
|
|
@ -549,6 +547,3 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
else:
|
else:
|
||||||
genPrefixCall(p, le, ri, d)
|
genPrefixCall(p, le, ri, d)
|
||||||
postStmtActions(p)
|
postStmtActions(p)
|
||||||
when false:
|
|
||||||
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,19 +30,6 @@ proc intLiteral(i: BiggestInt): Rope =
|
||||||
else:
|
else:
|
||||||
result = ~"(IL64(-9223372036854775807) - IL64(1))"
|
result = ~"(IL64(-9223372036854775807) - IL64(1))"
|
||||||
|
|
||||||
proc int32Literal(i: int): Rope =
|
|
||||||
if i == int(low(int32)):
|
|
||||||
result = ~"(-2147483647 -1)"
|
|
||||||
else:
|
|
||||||
result = rope(i)
|
|
||||||
|
|
||||||
proc genHexLiteral(v: PNode): Rope =
|
|
||||||
# hex literals are unsigned in C
|
|
||||||
# so we don't generate hex literals any longer.
|
|
||||||
if v.kind notin {nkIntLit..nkUInt64Lit}:
|
|
||||||
internalError(v.info, "genHexLiteral")
|
|
||||||
result = intLiteral(v.intVal)
|
|
||||||
|
|
||||||
proc getStrLit(m: BModule, s: string): Rope =
|
proc getStrLit(m: BModule, s: string): Rope =
|
||||||
discard cgsym(m, "TGenericSeq")
|
discard cgsym(m, "TGenericSeq")
|
||||||
result = getTempName(m)
|
result = getTempName(m)
|
||||||
|
|
@ -171,7 +158,6 @@ proc getStorageLoc(n: PNode): TStorageLoc =
|
||||||
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
if dest.s == OnStack or not usesNativeGC():
|
if dest.s == OnStack or not usesNativeGC():
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||||
if needToKeepAlive in flags: keepAlive(p, dest)
|
|
||||||
elif dest.s == OnHeap:
|
elif dest.s == OnHeap:
|
||||||
# location is on heap
|
# location is on heap
|
||||||
# now the writer barrier is inlined for performance:
|
# now the writer barrier is inlined for performance:
|
||||||
|
|
@ -198,7 +184,6 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n",
|
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n",
|
||||||
addrLoc(dest), rdLoc(src))
|
addrLoc(dest), rdLoc(src))
|
||||||
if needToKeepAlive in flags: keepAlive(p, dest)
|
|
||||||
|
|
||||||
proc asgnComplexity(n: PNode): int =
|
proc asgnComplexity(n: PNode): int =
|
||||||
if n != nil:
|
if n != nil:
|
||||||
|
|
@ -218,7 +203,6 @@ proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc =
|
||||||
result.s = a.s
|
result.s = a.s
|
||||||
result.t = t
|
result.t = t
|
||||||
result.r = rdLoc(a) & "." & field
|
result.r = rdLoc(a) & "." & field
|
||||||
result.heapRoot = a.heapRoot
|
|
||||||
|
|
||||||
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
let newflags =
|
let newflags =
|
||||||
|
|
@ -268,7 +252,6 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
||||||
addrLoc(dest), addrLoc(src), rdLoc(dest))
|
addrLoc(dest), addrLoc(src), rdLoc(dest))
|
||||||
if needToKeepAlive in flags: keepAlive(p, dest)
|
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
|
linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
|
||||||
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
|
addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
|
||||||
|
|
@ -299,7 +282,6 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
else:
|
else:
|
||||||
if dest.s == OnStack or not usesNativeGC():
|
if dest.s == OnStack or not usesNativeGC():
|
||||||
linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
|
linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
|
||||||
if needToKeepAlive in flags: keepAlive(p, dest)
|
|
||||||
elif dest.s == OnHeap:
|
elif dest.s == OnHeap:
|
||||||
# we use a temporary to care for the dreaded self assignment:
|
# we use a temporary to care for the dreaded self assignment:
|
||||||
var tmp: TLoc
|
var tmp: TLoc
|
||||||
|
|
@ -310,7 +292,6 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
|
linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
|
||||||
addrLoc(dest), rdLoc(src))
|
addrLoc(dest), rdLoc(src))
|
||||||
if needToKeepAlive in flags: keepAlive(p, dest)
|
|
||||||
of tyProc:
|
of tyProc:
|
||||||
if needsComplexAssignment(dest.t):
|
if needsComplexAssignment(dest.t):
|
||||||
# optimize closure assignment:
|
# optimize closure assignment:
|
||||||
|
|
@ -400,9 +381,6 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||||
else: internalError("genDeepCopy: " & $ty.kind)
|
else: internalError("genDeepCopy: " & $ty.kind)
|
||||||
|
|
||||||
proc getDestLoc(p: BProc, d: var TLoc, typ: PType) =
|
|
||||||
if d.k == locNone: getTemp(p, typ, d)
|
|
||||||
|
|
||||||
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
|
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
|
||||||
if d.k != locNone:
|
if d.k != locNone:
|
||||||
if lfNoDeepCopy in d.flags: genAssignment(p, d, s, {})
|
if lfNoDeepCopy in d.flags: genAssignment(p, d, s, {})
|
||||||
|
|
@ -453,13 +431,6 @@ proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
||||||
initLocExpr(p, e.sons[1], a)
|
initLocExpr(p, e.sons[1], a)
|
||||||
lineCg(p, cpsStmts, frmt, [rdLoc(a)])
|
lineCg(p, cpsStmts, frmt, [rdLoc(a)])
|
||||||
|
|
||||||
proc binaryStmtChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
|
||||||
var a, b: TLoc
|
|
||||||
if (d.k != locNone): internalError(e.info, "binaryStmtChar")
|
|
||||||
initLocExpr(p, e.sons[1], a)
|
|
||||||
initLocExpr(p, e.sons[2], b)
|
|
||||||
lineCg(p, cpsStmts, frmt, [rdCharLoc(a), rdCharLoc(b)])
|
|
||||||
|
|
||||||
proc binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
proc binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
assert(e.sons[1].typ != nil)
|
assert(e.sons[1].typ != nil)
|
||||||
|
|
@ -670,6 +641,8 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||||
#if e[0].kind != nkBracketExpr:
|
#if e[0].kind != nkBracketExpr:
|
||||||
# message(e.info, warnUser, "CAME HERE " & renderTree(e))
|
# message(e.info, warnUser, "CAME HERE " & renderTree(e))
|
||||||
expr(p, e.sons[0], d)
|
expr(p, e.sons[0], d)
|
||||||
|
if e.sons[0].typ.skipTypes(abstractInst).kind == tyRef:
|
||||||
|
d.s = OnHeap
|
||||||
else:
|
else:
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
let typ = skipTypes(e.sons[0].typ, abstractInst)
|
let typ = skipTypes(e.sons[0].typ, abstractInst)
|
||||||
|
|
@ -726,8 +699,6 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
|
|
||||||
template inheritLocation(d: var TLoc, a: TLoc) =
|
template inheritLocation(d: var TLoc, a: TLoc) =
|
||||||
if d.k == locNone: d.s = a.s
|
if d.k == locNone: d.s = a.s
|
||||||
if d.heapRoot == nil:
|
|
||||||
d.heapRoot = if a.heapRoot != nil: a.heapRoot else: a.r
|
|
||||||
|
|
||||||
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
|
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, e.sons[0], a)
|
||||||
|
|
@ -891,7 +862,6 @@ proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||||
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
||||||
rdLoc(b), rdLoc(a), lenField(p))
|
rdLoc(b), rdLoc(a), lenField(p))
|
||||||
if d.k == locNone: d.s = OnHeap
|
if d.k == locNone: d.s = OnHeap
|
||||||
d.heapRoot = a.r
|
|
||||||
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
||||||
a.r = rfmt(nil, "(*$1)", a.r)
|
a.r = rfmt(nil, "(*$1)", a.r)
|
||||||
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
|
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
|
||||||
|
|
@ -1006,9 +976,8 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
||||||
add(p.s(cpsStmts), appends)
|
add(p.s(cpsStmts), appends)
|
||||||
if d.k == locNone:
|
if d.k == locNone:
|
||||||
d = tmp
|
d = tmp
|
||||||
keepAlive(p, tmp)
|
|
||||||
else:
|
else:
|
||||||
genAssignment(p, d, tmp, {needToKeepAlive}) # no need for deep copying
|
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||||
gcUsage(e)
|
gcUsage(e)
|
||||||
|
|
||||||
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
|
|
@ -1045,7 +1014,6 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
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, rope(L))
|
rdLoc(dest), lens, rope(L))
|
||||||
keepAlive(p, dest)
|
|
||||||
add(p.s(cpsStmts), appends)
|
add(p.s(cpsStmts), appends)
|
||||||
gcUsage(e)
|
gcUsage(e)
|
||||||
|
|
||||||
|
|
@ -1065,7 +1033,6 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
rdLoc(a),
|
rdLoc(a),
|
||||||
getTypeDesc(p.module, skipTypes(e.sons[1].typ, abstractVar)),
|
getTypeDesc(p.module, skipTypes(e.sons[1].typ, abstractVar)),
|
||||||
getTypeDesc(p.module, bt)])
|
getTypeDesc(p.module, bt)])
|
||||||
keepAlive(p, a)
|
|
||||||
#if bt != b.t:
|
#if bt != b.t:
|
||||||
# echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
|
# echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
|
||||||
initLoc(dest, locExpr, bt, OnHeap)
|
initLoc(dest, locExpr, bt, OnHeap)
|
||||||
|
|
@ -1092,7 +1059,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
||||||
genTypeInfo(p.module, refType),
|
genTypeInfo(p.module, refType),
|
||||||
sizeExpr]
|
sizeExpr]
|
||||||
if a.s == OnHeap and usesNativeGC():
|
if a.s == OnHeap and usesNativeGC():
|
||||||
# use newObjRC1 as an optimization; and we don't need 'keepAlive' either
|
# use newObjRC1 as an optimization
|
||||||
if canFormAcycle(a.t):
|
if canFormAcycle(a.t):
|
||||||
linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", a.rdLoc)
|
linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", a.rdLoc)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1101,7 +1068,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc)
|
linefmt(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc)
|
||||||
else:
|
else:
|
||||||
b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
|
b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
|
||||||
genAssignment(p, a, b, {needToKeepAlive}) # set the object type:
|
genAssignment(p, a, b, {}) # set the object type:
|
||||||
let bt = skipTypes(refType.sons[0], abstractRange)
|
let bt = skipTypes(refType.sons[0], abstractRange)
|
||||||
genObjectInit(p, cpsStmts, bt, a, false)
|
genObjectInit(p, cpsStmts, bt, a, false)
|
||||||
|
|
||||||
|
|
@ -1132,7 +1099,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
|
linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
|
||||||
else:
|
else:
|
||||||
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
|
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
|
||||||
genAssignment(p, dest, call, {needToKeepAlive})
|
genAssignment(p, dest, call, {})
|
||||||
|
|
||||||
proc genNewSeq(p: BProc, e: PNode) =
|
proc genNewSeq(p: BProc, e: PNode) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
|
|
@ -1197,7 +1164,6 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
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
|
||||||
tmp2.heapRoot = tmp.r
|
|
||||||
expr(p, it.sons[1], tmp2)
|
expr(p, it.sons[1], tmp2)
|
||||||
|
|
||||||
if d.k == locNone:
|
if d.k == locNone:
|
||||||
|
|
@ -1244,7 +1210,6 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||||
a, b, f: TLoc
|
a, b, f: TLoc
|
||||||
refType, bt: PType
|
refType, bt: PType
|
||||||
ti: Rope
|
ti: Rope
|
||||||
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)
|
||||||
|
|
@ -1254,7 +1219,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||||
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))])
|
||||||
genAssignment(p, a, b, {needToKeepAlive}) # set the object type:
|
genAssignment(p, a, b, {}) # set the object type:
|
||||||
bt = skipTypes(refType.lastSon, abstractRange)
|
bt = skipTypes(refType.lastSon, abstractRange)
|
||||||
genObjectInit(p, cpsStmts, bt, a, false)
|
genObjectInit(p, cpsStmts, bt, a, false)
|
||||||
gcUsage(e)
|
gcUsage(e)
|
||||||
|
|
@ -1364,7 +1329,7 @@ proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
|
||||||
initLocExpr(p, n.sons[1], a)
|
initLocExpr(p, n.sons[1], a)
|
||||||
a.r = ropecg(p.module, frmt, [rdLoc(a)])
|
a.r = ropecg(p.module, frmt, [rdLoc(a)])
|
||||||
if d.k == locNone: getTemp(p, n.typ, d)
|
if d.k == locNone: getTemp(p, n.typ, d)
|
||||||
genAssignment(p, d, a, {needToKeepAlive})
|
genAssignment(p, d, a, {})
|
||||||
gcUsage(n)
|
gcUsage(n)
|
||||||
|
|
||||||
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
|
|
@ -1406,12 +1371,10 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||||
lineCg(p, cpsStmts, setLenPattern, [
|
lineCg(p, cpsStmts, setLenPattern, [
|
||||||
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
|
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
|
||||||
getTypeDesc(p.module, t.sons[0])])
|
getTypeDesc(p.module, t.sons[0])])
|
||||||
keepAlive(p, a)
|
|
||||||
gcUsage(e)
|
gcUsage(e)
|
||||||
|
|
||||||
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
|
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n")
|
binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n")
|
||||||
keepAlive(p, d)
|
|
||||||
gcUsage(e)
|
gcUsage(e)
|
||||||
|
|
||||||
proc genSwap(p: BProc, e: PNode, d: var TLoc) =
|
proc genSwap(p: BProc, e: PNode, d: var TLoc) =
|
||||||
|
|
@ -1681,7 +1644,6 @@ 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: 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)
|
||||||
|
|
@ -1719,10 +1681,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
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: binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n")
|
||||||
binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n")
|
|
||||||
# strictly speaking we need to generate "keepAlive" here too, but this
|
|
||||||
# very likely not needed and would slow down the code too much I fear
|
|
||||||
of mAppendStrStr: genStrAppend(p, e, d)
|
of mAppendStrStr: genStrAppend(p, e, d)
|
||||||
of mAppendSeqElem: genSeqElemAppend(p, e, d)
|
of mAppendSeqElem: genSeqElemAppend(p, e, d)
|
||||||
of mEqStr: genStrEquals(p, e, d)
|
of mEqStr: genStrEquals(p, e, d)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ proc registerGcRoot(p: BProc, v: PSym) =
|
||||||
# we register a specialized marked proc here; this has the advantage
|
# we register a specialized marked proc here; this has the advantage
|
||||||
# that it works out of the box for thread local storage then :-)
|
# that it works out of the box for thread local storage then :-)
|
||||||
let prc = genTraverseProcForGlobal(p.module, v)
|
let prc = genTraverseProcForGlobal(p.module, v)
|
||||||
appcg(p.module, p.module.initProc.procSec(cpsStmts),
|
appcg(p.module, p.module.initProc.procSec(cpsInit),
|
||||||
"#nimRegisterGlobalMarker($1);$n", [prc])
|
"#nimRegisterGlobalMarker($1);$n", [prc])
|
||||||
|
|
||||||
proc isAssignedImmediately(n: PNode): bool {.inline.} =
|
proc isAssignedImmediately(n: PNode): bool {.inline.} =
|
||||||
|
|
@ -459,7 +459,6 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||||
# significantly worse code
|
# significantly worse code
|
||||||
var
|
var
|
||||||
a: TLoc
|
a: TLoc
|
||||||
labl: TLabel
|
|
||||||
assert(sonsLen(t) == 2)
|
assert(sonsLen(t) == 2)
|
||||||
inc(p.withinLoop)
|
inc(p.withinLoop)
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
|
|
@ -757,16 +756,6 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
|
||||||
else:
|
else:
|
||||||
genOrdinalCase(p, t, d)
|
genOrdinalCase(p, t, d)
|
||||||
|
|
||||||
proc hasGeneralExceptSection(t: PNode): bool =
|
|
||||||
var length = sonsLen(t)
|
|
||||||
var i = 1
|
|
||||||
while (i < length) and (t.sons[i].kind == nkExceptBranch):
|
|
||||||
var blen = sonsLen(t.sons[i])
|
|
||||||
if blen == 1:
|
|
||||||
return true
|
|
||||||
inc(i)
|
|
||||||
result = false
|
|
||||||
|
|
||||||
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
# code to generate:
|
# code to generate:
|
||||||
#
|
#
|
||||||
|
|
@ -1089,7 +1078,6 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||||
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
|
||||||
var a, tmp: TLoc
|
var a, tmp: TLoc
|
||||||
var dotExpr = e.sons[0]
|
var dotExpr = e.sons[0]
|
||||||
var d: PSym
|
|
||||||
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.sons[0]
|
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.sons[0]
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, e.sons[0], a)
|
||||||
getTemp(p, a.t, tmp)
|
getTemp(p, a.t, tmp)
|
||||||
|
|
|
||||||
|
|
@ -744,14 +744,6 @@ proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
|
||||||
"void* ClEnv;$n} $1;$n",
|
"void* ClEnv;$n} $1;$n",
|
||||||
[result, rettype, desc])
|
[result, rettype, desc])
|
||||||
|
|
||||||
proc getTypeDesc(m: BModule, magic: string): Rope =
|
|
||||||
var sym = magicsys.getCompilerProc(magic)
|
|
||||||
if sym != nil:
|
|
||||||
result = getTypeDesc(m, sym.typ)
|
|
||||||
else:
|
|
||||||
rawMessage(errSystemNeeds, magic)
|
|
||||||
result = nil
|
|
||||||
|
|
||||||
proc finishTypeDescriptions(m: BModule) =
|
proc finishTypeDescriptions(m: BModule) =
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < len(m.typeStack):
|
while i < len(m.typeStack):
|
||||||
|
|
@ -1000,9 +992,6 @@ proc fakeClosureType(owner: PSym): PType =
|
||||||
type
|
type
|
||||||
TTypeInfoReason = enum ## for what do we need the type info?
|
TTypeInfoReason = enum ## for what do we need the type info?
|
||||||
tiNew, ## for 'new'
|
tiNew, ## for 'new'
|
||||||
tiNewSeq, ## for 'newSeq'
|
|
||||||
tiNonVariantAsgn, ## for generic assignment without variants
|
|
||||||
tiVariantAsgn ## for generic assignment with variants
|
|
||||||
|
|
||||||
include ccgtrav
|
include ccgtrav
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -167,10 +167,6 @@ proc linefmt(p: BProc, s: TCProcSection, frmt: FormatStr,
|
||||||
args: varargs[Rope]) =
|
args: varargs[Rope]) =
|
||||||
add(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 Rope, frmt: FormatStr,
|
|
||||||
args: varargs[Rope]) =
|
|
||||||
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
|
||||||
|
|
@ -259,8 +255,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||||
|
|
||||||
type
|
type
|
||||||
TAssignmentFlag = enum
|
TAssignmentFlag = enum
|
||||||
needToCopy, needForSubtypeCheck, afDestIsNil, afDestIsNotNil, afSrcIsNil,
|
needToCopy, afDestIsNil, afDestIsNotNil, afSrcIsNil, afSrcIsNotNil
|
||||||
afSrcIsNotNil, needToKeepAlive
|
|
||||||
TAssignmentFlags = set[TAssignmentFlag]
|
TAssignmentFlags = set[TAssignmentFlag]
|
||||||
|
|
||||||
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
|
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
|
||||||
|
|
@ -338,31 +333,6 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||||
result.flags = {}
|
result.flags = {}
|
||||||
constructLoc(p, result, not needsInit)
|
constructLoc(p, result, not needsInit)
|
||||||
|
|
||||||
proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
|
||||||
when false:
|
|
||||||
# deactivated because of the huge slowdown this causes; GC will take care
|
|
||||||
# of interior pointers instead
|
|
||||||
if optRefcGC notin gGlobalOptions: return
|
|
||||||
var result: TLoc
|
|
||||||
var fid = rope(p.gcFrameId)
|
|
||||||
result.r = "GCFRAME.F" & fid
|
|
||||||
addf(p.gcFrameType, " $1 F$2;$n",
|
|
||||||
[getTypeDesc(p.module, toKeepAlive.t), fid])
|
|
||||||
inc(p.gcFrameId)
|
|
||||||
result.k = locTemp
|
|
||||||
#result.a = -1
|
|
||||||
result.t = toKeepAlive.t
|
|
||||||
result.s = OnStack
|
|
||||||
result.flags = {}
|
|
||||||
|
|
||||||
if not isComplexValueType(skipTypes(toKeepAlive.t, abstractVarRange)):
|
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(result), rdLoc(toKeepAlive))
|
|
||||||
else:
|
|
||||||
useStringh(p.module)
|
|
||||||
linefmt(p, cpsStmts,
|
|
||||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
|
||||||
addrLoc(result), addrLoc(toKeepAlive), rdLoc(result))
|
|
||||||
|
|
||||||
proc initGCFrame(p: BProc): Rope =
|
proc initGCFrame(p: BProc): Rope =
|
||||||
if p.gcFrameId > 0: result = "struct {$1} GCFRAME;$n" % [p.gcFrameType]
|
if p.gcFrameId > 0: result = "struct {$1} GCFRAME;$n" % [p.gcFrameType]
|
||||||
|
|
||||||
|
|
@ -620,9 +590,6 @@ proc generateHeaders(m: BModule) =
|
||||||
addf(m.s[cfsHeaders], "#include $1$N", [rope(it.data)])
|
addf(m.s[cfsHeaders], "#include $1$N", [rope(it.data)])
|
||||||
it = PStrEntry(it.next)
|
it = PStrEntry(it.next)
|
||||||
|
|
||||||
proc retIsNotVoid(s: PSym): bool =
|
|
||||||
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
|
|
||||||
|
|
||||||
proc initFrame(p: BProc, procname, filename: Rope): Rope =
|
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:
|
||||||
|
|
|
||||||
|
|
@ -505,10 +505,6 @@ proc noAbsolutePaths: bool {.inline.} =
|
||||||
# `optGenMapping` is included here for niminst.
|
# `optGenMapping` is included here for niminst.
|
||||||
result = gGlobalOptions * {optGenScript, optGenMapping} != {}
|
result = gGlobalOptions * {optGenScript, optGenMapping} != {}
|
||||||
|
|
||||||
const
|
|
||||||
specialFileA = 42
|
|
||||||
specialFileB = 42
|
|
||||||
|
|
||||||
var fileCounter: int
|
var fileCounter: int
|
||||||
|
|
||||||
proc add(s: var string, many: openArray[string]) =
|
proc add(s: var string, many: openArray[string]) =
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,6 @@ proc loadMaxIds*(project: string) =
|
||||||
if f.readLine(line):
|
if f.readLine(line):
|
||||||
var frontEndId = parseInt(line)
|
var frontEndId = parseInt(line)
|
||||||
if f.readLine(line):
|
if f.readLine(line):
|
||||||
var backEndId = parseInt(line)
|
# var backEndId = parseInt(line)
|
||||||
gFrontEndId = max(gFrontEndId, frontEndId)
|
gFrontEndId = max(gFrontEndId, frontEndId)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,6 @@ path = r"c:\Program Files (x86)\Inno Setup 5\iscc.exe"
|
||||||
flags = "/Q"
|
flags = "/Q"
|
||||||
|
|
||||||
[NSIS]
|
[NSIS]
|
||||||
path = r"c:\Program Files (x86)\NSIS\makensis.exe"
|
|
||||||
flags = "/V0"
|
flags = "/V0"
|
||||||
|
|
||||||
[C_Compiler]
|
[C_Compiler]
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# This is the JavaScript code generator.
|
# This is the JavaScript code generator.
|
||||||
# Soon also a PHP code generator. ;-)
|
# Also a PHP code generator. ;-)
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
The JS code generator contains only 2 tricks:
|
The JS code generator contains only 2 tricks:
|
||||||
|
|
@ -1280,14 +1280,15 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
assert(typ.kind == tyProc)
|
assert(typ.kind == tyProc)
|
||||||
genPatternCall(p, n, pat, typ, r)
|
genPatternCall(p, n, pat, typ, r)
|
||||||
return
|
return
|
||||||
gen(p, n.sons[1], r)
|
if n.len != 1:
|
||||||
if r.typ == etyBaseIndex:
|
gen(p, n.sons[1], r)
|
||||||
if r.address == nil:
|
if r.typ == etyBaseIndex:
|
||||||
globalError(n.info, "cannot invoke with infix syntax")
|
if r.address == nil:
|
||||||
r.res = "$1[$2]" % [r.address, r.res]
|
globalError(n.info, "cannot invoke with infix syntax")
|
||||||
r.address = nil
|
r.res = "$1[$2]" % [r.address, r.res]
|
||||||
r.typ = etyNone
|
r.address = nil
|
||||||
add(r.res, "." | "->")
|
r.typ = etyNone
|
||||||
|
add(r.res, "." | "->")
|
||||||
var op: TCompRes
|
var op: TCompRes
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
op.kind = resCallee
|
op.kind = resCallee
|
||||||
|
|
|
||||||
|
|
@ -211,9 +211,6 @@ proc closeLexer*(lex: var TLexer) =
|
||||||
inc(gLinesCompiled, lex.lineNumber)
|
inc(gLinesCompiled, lex.lineNumber)
|
||||||
closeBaseLexer(lex)
|
closeBaseLexer(lex)
|
||||||
|
|
||||||
proc getColumn(L: TLexer): int =
|
|
||||||
result = getColNumber(L, L.bufpos)
|
|
||||||
|
|
||||||
proc getLineInfo(L: TLexer): TLineInfo =
|
proc getLineInfo(L: TLexer): TLineInfo =
|
||||||
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
|
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
|
||||||
|
|
||||||
|
|
@ -237,12 +234,6 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||||
proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
|
proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
|
||||||
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
|
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
|
||||||
|
|
||||||
proc isFloatLiteral(s: string): bool =
|
|
||||||
for i in countup(0, len(s) - 1):
|
|
||||||
if s[i] in {'.', 'e', 'E'}:
|
|
||||||
return true
|
|
||||||
result = false
|
|
||||||
|
|
||||||
{.push overflowChecks: off.}
|
{.push overflowChecks: off.}
|
||||||
# We need to parse the largest uint literal without overflow checks
|
# We need to parse the largest uint literal without overflow checks
|
||||||
proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
|
proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,6 @@ proc getModule*(fileIdx: int32): PSym =
|
||||||
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
|
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
|
||||||
result = gCompiledModules[fileIdx]
|
result = gCompiledModules[fileIdx]
|
||||||
|
|
||||||
template hash(x: PSym): untyped =
|
|
||||||
gMemCacheData[x.position].hash
|
|
||||||
|
|
||||||
proc hashChanged(fileIdx: int32): bool =
|
proc hashChanged(fileIdx: int32): bool =
|
||||||
internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
|
internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
|
||||||
|
|
||||||
|
|
@ -220,12 +217,6 @@ proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
|
||||||
addDep(s, fileIdx)
|
addDep(s, fileIdx)
|
||||||
doHash(fileIdx)
|
doHash(fileIdx)
|
||||||
|
|
||||||
proc `==^`(a, b: string): bool =
|
|
||||||
try:
|
|
||||||
result = sameFile(a, b)
|
|
||||||
except OSError:
|
|
||||||
result = false
|
|
||||||
|
|
||||||
proc compileSystemModule* =
|
proc compileSystemModule* =
|
||||||
if magicsys.systemModule == nil:
|
if magicsys.systemModule == nil:
|
||||||
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
|
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ type
|
||||||
errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
|
errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
|
||||||
errAmbiguousCallXYZ, errWrongNumberOfArguments,
|
errAmbiguousCallXYZ, errWrongNumberOfArguments,
|
||||||
errXCannotBePassedToProcVar,
|
errXCannotBePassedToProcVar,
|
||||||
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
|
errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed,
|
||||||
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
|
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
|
||||||
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
|
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
|
||||||
errInvalidOrderInArrayConstructor,
|
errInvalidOrderInArrayConstructor,
|
||||||
|
|
@ -274,7 +274,7 @@ const
|
||||||
errWrongNumberOfArguments: "wrong number of arguments",
|
errWrongNumberOfArguments: "wrong number of arguments",
|
||||||
errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
|
errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
|
||||||
errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration",
|
errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration",
|
||||||
errPragmaOnlyInHeaderOfProc: "pragmas are only allowed in the header of a proc",
|
errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
|
||||||
errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
|
errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
|
||||||
errImplOfXexpected: "implementation of \'$1\' expected",
|
errImplOfXexpected: "implementation of \'$1\' expected",
|
||||||
errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
|
errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
|
||||||
|
|
@ -660,8 +660,6 @@ const
|
||||||
WarningColor = fgYellow
|
WarningColor = fgYellow
|
||||||
HintTitle = "Hint: "
|
HintTitle = "Hint: "
|
||||||
HintColor = fgGreen
|
HintColor = fgGreen
|
||||||
InfoTitle = "Info: "
|
|
||||||
InfoColor = fgCyan
|
|
||||||
|
|
||||||
proc getInfoContextLen*(): int = return msgContext.len
|
proc getInfoContextLen*(): int = return msgContext.len
|
||||||
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
|
proc setInfoContextLen*(L: int) = setLen(msgContext, L)
|
||||||
|
|
|
||||||
|
|
@ -63,18 +63,6 @@ proc addNimblePath(p: string, info: TLineInfo) =
|
||||||
message(info, hintPath, p)
|
message(info, hintPath, p)
|
||||||
lists.prependStr(options.lazyPaths, p)
|
lists.prependStr(options.lazyPaths, p)
|
||||||
|
|
||||||
proc addPathWithNimFiles(p: string, info: TLineInfo) =
|
|
||||||
proc hasNimFile(dir: string): bool =
|
|
||||||
for kind, path in walkDir(dir):
|
|
||||||
if kind == pcFile and path.endsWith(".nim"):
|
|
||||||
result = true
|
|
||||||
break
|
|
||||||
if hasNimFile(p):
|
|
||||||
addNimblePath(p, info)
|
|
||||||
else:
|
|
||||||
for kind, p2 in walkDir(p):
|
|
||||||
if hasNimFile(p2): addNimblePath(p2, info)
|
|
||||||
|
|
||||||
proc addPathRec(dir: string, info: TLineInfo) =
|
proc addPathRec(dir: string, info: TLineInfo) =
|
||||||
var packages = newStringTable(modeStyleInsensitive)
|
var packages = newStringTable(modeStyleInsensitive)
|
||||||
var pos = dir.len-1
|
var pos = dir.len-1
|
||||||
|
|
|
||||||
|
|
@ -340,26 +340,6 @@ proc parseSymbol(p: var TParser, allowNil = false): PNode =
|
||||||
if not isKeyword(p.tok.tokType): getTok(p)
|
if not isKeyword(p.tok.tokType): getTok(p)
|
||||||
result = ast.emptyNode
|
result = ast.emptyNode
|
||||||
|
|
||||||
proc indexExpr(p: var TParser): PNode =
|
|
||||||
#| indexExpr = expr
|
|
||||||
result = parseExpr(p)
|
|
||||||
|
|
||||||
proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
|
|
||||||
endToken: TTokType): PNode =
|
|
||||||
#| indexExprList = indexExpr ^+ comma
|
|
||||||
result = newNodeP(k, p)
|
|
||||||
addSon(result, first)
|
|
||||||
getTok(p)
|
|
||||||
optInd(p, result)
|
|
||||||
while p.tok.tokType notin {endToken, tkEof}:
|
|
||||||
var a = indexExpr(p)
|
|
||||||
addSon(result, a)
|
|
||||||
if p.tok.tokType != tkComma: break
|
|
||||||
getTok(p)
|
|
||||||
skipComment(p, a)
|
|
||||||
optPar(p)
|
|
||||||
eat(p, endToken)
|
|
||||||
|
|
||||||
proc colonOrEquals(p: var TParser, a: PNode): PNode =
|
proc colonOrEquals(p: var TParser, a: PNode): PNode =
|
||||||
if p.tok.tokType == tkColon:
|
if p.tok.tokType == tkColon:
|
||||||
result = newNodeP(nkExprColonExpr, p)
|
result = newNodeP(nkExprColonExpr, p)
|
||||||
|
|
|
||||||
|
|
@ -90,43 +90,38 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
|
||||||
else:
|
else:
|
||||||
invalidPragma(it)
|
invalidPragma(it)
|
||||||
|
|
||||||
proc setExternName(s: PSym, extname: string) =
|
proc setExternName(s: PSym, extname: string, info: TLineInfo) =
|
||||||
s.loc.r = rope(extname % s.name.s)
|
# special cases to improve performance:
|
||||||
|
if extname == "$1":
|
||||||
|
s.loc.r = rope(s.name.s)
|
||||||
|
elif '$' notin extname:
|
||||||
|
s.loc.r = rope(extname)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
s.loc.r = rope(extname % s.name.s)
|
||||||
|
except ValueError:
|
||||||
|
localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
|
||||||
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)
|
||||||
|
|
||||||
proc makeExternImport(s: PSym, extname: string) =
|
proc makeExternImport(s: PSym, extname: string, info: TLineInfo) =
|
||||||
setExternName(s, extname)
|
setExternName(s, extname, info)
|
||||||
incl(s.flags, sfImportc)
|
incl(s.flags, sfImportc)
|
||||||
excl(s.flags, sfForward)
|
excl(s.flags, sfForward)
|
||||||
|
|
||||||
proc validateExternCName(s: PSym, info: TLineInfo) =
|
|
||||||
## Validates that the symbol name in s.loc.r is a valid C identifier.
|
|
||||||
##
|
|
||||||
## Valid identifiers are those alphanumeric including the underscore not
|
|
||||||
## starting with a number. If the check fails, a generic error will be
|
|
||||||
## displayed to the user.
|
|
||||||
let target = $s.loc.r
|
|
||||||
if target.len < 1 or target[0] notin IdentStartChars or
|
|
||||||
not target.allCharsInSet(IdentChars):
|
|
||||||
localError(info, errGenerated, "invalid exported symbol")
|
|
||||||
|
|
||||||
proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
|
proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
|
||||||
setExternName(s, extname)
|
setExternName(s, extname, info)
|
||||||
# XXX to fix make it work with nimrtl.
|
|
||||||
#if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}:
|
|
||||||
# validateExternCName(s, info)
|
|
||||||
incl(s.flags, sfExportc)
|
incl(s.flags, sfExportc)
|
||||||
|
|
||||||
proc processImportCompilerProc(s: PSym, extname: string) =
|
proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) =
|
||||||
setExternName(s, extname)
|
setExternName(s, extname, info)
|
||||||
incl(s.flags, sfImportc)
|
incl(s.flags, sfImportc)
|
||||||
excl(s.flags, sfForward)
|
excl(s.flags, sfForward)
|
||||||
incl(s.loc.flags, lfImportCompilerProc)
|
incl(s.loc.flags, lfImportCompilerProc)
|
||||||
|
|
||||||
proc processImportCpp(s: PSym, extname: string) =
|
proc processImportCpp(s: PSym, extname: string, info: TLineInfo) =
|
||||||
setExternName(s, extname)
|
setExternName(s, extname, info)
|
||||||
incl(s.flags, sfImportc)
|
incl(s.flags, sfImportc)
|
||||||
incl(s.flags, sfInfixCall)
|
incl(s.flags, sfInfixCall)
|
||||||
excl(s.flags, sfForward)
|
excl(s.flags, sfForward)
|
||||||
|
|
@ -134,8 +129,8 @@ proc processImportCpp(s: PSym, extname: string) =
|
||||||
incl(m.flags, sfCompileToCpp)
|
incl(m.flags, sfCompileToCpp)
|
||||||
extccomp.gMixedMode = true
|
extccomp.gMixedMode = true
|
||||||
|
|
||||||
proc processImportObjC(s: PSym, extname: string) =
|
proc processImportObjC(s: PSym, extname: string, info: TLineInfo) =
|
||||||
setExternName(s, extname)
|
setExternName(s, extname, info)
|
||||||
incl(s.flags, sfImportc)
|
incl(s.flags, sfImportc)
|
||||||
incl(s.flags, sfNamedParamCall)
|
incl(s.flags, sfNamedParamCall)
|
||||||
excl(s.flags, sfForward)
|
excl(s.flags, sfForward)
|
||||||
|
|
@ -625,10 +620,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
of wExportc:
|
of wExportc:
|
||||||
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
|
makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||||
incl(sym.flags, sfUsed) # avoid wrong hints
|
incl(sym.flags, sfUsed) # avoid wrong hints
|
||||||
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
|
of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||||
of wImportCompilerProc:
|
of wImportCompilerProc:
|
||||||
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
|
processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||||
of wExtern: setExternName(sym, expectStrLit(c, it))
|
of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
|
||||||
of wImmediate:
|
of wImmediate:
|
||||||
if sym.kind in {skTemplate, skMacro}:
|
if sym.kind in {skTemplate, skMacro}:
|
||||||
incl(sym.flags, sfImmediate)
|
incl(sym.flags, sfImmediate)
|
||||||
|
|
@ -639,9 +634,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
|
if sym.kind == skTemplate: incl(sym.flags, sfDirty)
|
||||||
else: invalidPragma(it)
|
else: invalidPragma(it)
|
||||||
of wImportCpp:
|
of wImportCpp:
|
||||||
processImportCpp(sym, getOptionalStr(c, it, "$1"))
|
processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||||
of wImportObjC:
|
of wImportObjC:
|
||||||
processImportObjC(sym, getOptionalStr(c, it, "$1"))
|
processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info)
|
||||||
of wAlign:
|
of wAlign:
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
var align = expectIntLit(c, it)
|
var align = expectIntLit(c, it)
|
||||||
|
|
|
||||||
|
|
@ -146,12 +146,6 @@ proc put(g: var TSrcGen, kind: TTokType, s: string) =
|
||||||
else:
|
else:
|
||||||
g.pendingWhitespace = s.len
|
g.pendingWhitespace = s.len
|
||||||
|
|
||||||
proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) =
|
|
||||||
# use this for tokens over multiple lines.
|
|
||||||
addPendingNL(g)
|
|
||||||
addTok(g, kind, s)
|
|
||||||
g.lineLen = lineLen
|
|
||||||
|
|
||||||
proc toNimChar(c: char): string =
|
proc toNimChar(c: char): string =
|
||||||
case c
|
case c
|
||||||
of '\0': result = "\\0"
|
of '\0': result = "\\0"
|
||||||
|
|
@ -264,9 +258,6 @@ proc pushCom(g: var TSrcGen, n: PNode) =
|
||||||
proc popAllComs(g: var TSrcGen) =
|
proc popAllComs(g: var TSrcGen) =
|
||||||
setLen(g.comStack, 0)
|
setLen(g.comStack, 0)
|
||||||
|
|
||||||
proc popCom(g: var TSrcGen) =
|
|
||||||
setLen(g.comStack, len(g.comStack) - 1)
|
|
||||||
|
|
||||||
const
|
const
|
||||||
Space = " "
|
Space = " "
|
||||||
|
|
||||||
|
|
@ -492,7 +483,7 @@ proc fits(g: TSrcGen, x: int): bool =
|
||||||
|
|
||||||
type
|
type
|
||||||
TSubFlag = enum
|
TSubFlag = enum
|
||||||
rfLongMode, rfNoIndent, rfInConstExpr
|
rfLongMode, rfInConstExpr
|
||||||
TSubFlags = set[TSubFlag]
|
TSubFlags = set[TSubFlag]
|
||||||
TContext = tuple[spacing: int, flags: TSubFlags]
|
TContext = tuple[spacing: int, flags: TSubFlags]
|
||||||
|
|
||||||
|
|
@ -675,16 +666,6 @@ proc gfor(g: var TSrcGen, n: PNode) =
|
||||||
gcoms(g)
|
gcoms(g)
|
||||||
gstmts(g, n.sons[length - 1], c)
|
gstmts(g, n.sons[length - 1], c)
|
||||||
|
|
||||||
proc gmacro(g: var TSrcGen, n: PNode) =
|
|
||||||
var c: TContext
|
|
||||||
initContext(c)
|
|
||||||
gsub(g, n.sons[0])
|
|
||||||
putWithSpace(g, tkColon, ":")
|
|
||||||
if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
|
|
||||||
incl(c.flags, rfLongMode)
|
|
||||||
gcoms(g)
|
|
||||||
gsons(g, n, c, 1)
|
|
||||||
|
|
||||||
proc gcase(g: var TSrcGen, n: PNode) =
|
proc gcase(g: var TSrcGen, n: PNode) =
|
||||||
var c: TContext
|
var c: TContext
|
||||||
initContext(c)
|
initContext(c)
|
||||||
|
|
|
||||||
|
|
@ -310,15 +310,19 @@ proc equalsFile*(r: Rope, f: File): bool =
|
||||||
buf: array[bufSize, char]
|
buf: array[bufSize, char]
|
||||||
bpos = buf.len
|
bpos = buf.len
|
||||||
blen = buf.len
|
blen = buf.len
|
||||||
|
btotal = 0
|
||||||
|
rtotal = 0
|
||||||
|
|
||||||
for s in leaves(r):
|
for s in leaves(r):
|
||||||
var spos = 0
|
var spos = 0
|
||||||
let slen = s.len
|
let slen = s.len
|
||||||
|
rtotal += slen
|
||||||
while spos < slen:
|
while spos < slen:
|
||||||
if bpos == blen:
|
if bpos == blen:
|
||||||
# Read more data
|
# Read more data
|
||||||
bpos = 0
|
bpos = 0
|
||||||
blen = readBuffer(f, addr(buf[0]), buf.len)
|
blen = readBuffer(f, addr(buf[0]), buf.len)
|
||||||
|
btotal += blen
|
||||||
if blen == 0: # no more data in file
|
if blen == 0: # no more data in file
|
||||||
result = false
|
result = false
|
||||||
return
|
return
|
||||||
|
|
@ -330,7 +334,8 @@ proc equalsFile*(r: Rope, f: File): bool =
|
||||||
spos += n
|
spos += n
|
||||||
bpos += n
|
bpos += n
|
||||||
|
|
||||||
result = readBuffer(f, addr(buf[0]), 1) == 0 # check that we've read all
|
result = readBuffer(f, addr(buf[0]), 1) == 0 and
|
||||||
|
btotal == rtotal # check that we've read all
|
||||||
|
|
||||||
proc equalsFile*(r: Rope, filename: string): bool =
|
proc equalsFile*(r: Rope, filename: string): bool =
|
||||||
## 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
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ proc semStmt(c: PContext, n: PNode): PNode
|
||||||
proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
||||||
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
|
||||||
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
proc activate(c: PContext, n: PNode)
|
proc activate(c: PContext, n: PNode)
|
||||||
proc semQuoteAst(c: PContext, n: PNode): PNode
|
proc semQuoteAst(c: PContext, n: PNode): PNode
|
||||||
|
|
@ -187,7 +186,6 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
# identifier with visibility
|
# identifier with visibility
|
||||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym
|
allowed: TSymFlags): PSym
|
||||||
proc semStmtScope(c: PContext, n: PNode): PNode
|
|
||||||
|
|
||||||
proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
|
proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
|
||||||
let t = typeAllowed(typ, kind)
|
let t = typeAllowed(typ, kind)
|
||||||
|
|
|
||||||
|
|
@ -40,67 +40,49 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
filter: TSymKinds,
|
filter: TSymKinds,
|
||||||
best, alt: var TCandidate,
|
best, alt: var TCandidate,
|
||||||
errors: var CandidateErrors) =
|
errors: var CandidateErrors) =
|
||||||
var o: TOverloadIter
|
while true:
|
||||||
# thanks to the lazy semchecking for operands, we need to iterate over the
|
block pickAttempt:
|
||||||
# symbol table *before* any call to 'initCandidate' which might invoke
|
var o: TOverloadIter
|
||||||
# semExpr which might modify the symbol table in cases like
|
var sym = initOverloadIter(o, c, headSymbol)
|
||||||
# 'init(a, 1, (var b = new(Type2); b))'.
|
# Thanks to the lazy semchecking for operands, we need to check whether
|
||||||
var symx = initOverloadIter(o, c, headSymbol)
|
# 'initCandidate' modifies the symbol table (via semExpr).
|
||||||
let symScope = o.lastOverloadScope
|
# This can occur in cases like 'init(a, 1, (var b = new(Type2); b))'
|
||||||
|
let counterInitial = c.currentScope.symbols.counter
|
||||||
var syms: seq[tuple[a: PSym, b: int]] = @[]
|
# Initialise 'best' and 'alt' with the first available symbol
|
||||||
while symx != nil:
|
while sym != nil:
|
||||||
if symx.kind in filter:
|
if sym.kind in filter:
|
||||||
syms.add((symx, o.lastOverloadScope))
|
initCandidate(c, best, sym, initialBinding, o.lastOverloadScope)
|
||||||
symx = nextOverloadIter(o, c, headSymbol)
|
initCandidate(c, alt, sym, initialBinding, o.lastOverloadScope)
|
||||||
if syms.len == 0:
|
best.state = csNoMatch
|
||||||
when false:
|
break
|
||||||
if skIterator notin filter:
|
else:
|
||||||
# also try iterators, but these are 2nd class:
|
sym = nextOverloadIter(o, c, headSymbol)
|
||||||
symx = initOverloadIter(o, c, headSymbol)
|
var z: TCandidate
|
||||||
while symx != nil:
|
while sym != nil:
|
||||||
if symx.kind == skIterator:
|
if sym.kind notin filter:
|
||||||
syms.add((symx, 100))
|
sym = nextOverloadIter(o, c, headSymbol)
|
||||||
symx = nextOverloadIter(o, c, headSymbol)
|
continue
|
||||||
if syms.len == 0: return
|
determineType(c, sym)
|
||||||
else:
|
initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
|
||||||
return
|
if c.currentScope.symbols.counter != counterInitial: break pickAttempt
|
||||||
|
matches(c, n, orig, z)
|
||||||
var z: TCandidate
|
if errors != nil:
|
||||||
initCandidate(c, best, syms[0][0], initialBinding, symScope)
|
errors.safeAdd((sym, int z.mutabilityProblem))
|
||||||
initCandidate(c, alt, syms[0][0], initialBinding, symScope)
|
if z.errors != nil:
|
||||||
best.state = csNoMatch
|
for err in z.errors:
|
||||||
|
errors.add(err)
|
||||||
for i in 0 .. <syms.len:
|
if z.state == csMatch:
|
||||||
let sym = syms[i][0]
|
# little hack so that iterators are preferred over everything else:
|
||||||
determineType(c, sym)
|
if sym.kind == skIterator: inc(z.exactMatches, 200)
|
||||||
initCandidate(c, z, sym, initialBinding, syms[i][1])
|
case best.state
|
||||||
|
of csEmpty, csNoMatch: best = z
|
||||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
of csMatch:
|
||||||
# gDebug = true
|
var cmp = cmpCandidates(best, z)
|
||||||
matches(c, n, orig, z)
|
if cmp < 0: best = z # x is better than the best so far
|
||||||
if errors != nil:
|
elif cmp == 0: alt = z # x is as good as the best so far
|
||||||
errors.safeAdd((sym, int z.mutabilityProblem))
|
else: discard
|
||||||
if z.errors != nil:
|
sym = nextOverloadIter(o, c, headSymbol)
|
||||||
for err in z.errors:
|
break # pick attempt was successful
|
||||||
errors.add(err)
|
|
||||||
if z.state == csMatch:
|
|
||||||
# little hack so that iterators are preferred over everything else:
|
|
||||||
if sym.kind == skIterator: inc(z.exactMatches, 200)
|
|
||||||
case best.state
|
|
||||||
of csEmpty, csNoMatch: best = z
|
|
||||||
of csMatch:
|
|
||||||
var cmp = cmpCandidates(best, z)
|
|
||||||
if cmp < 0: best = z # x is better than the best so far
|
|
||||||
elif cmp == 0: alt = z # x is as good as the best so far
|
|
||||||
else: discard
|
|
||||||
#if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516:
|
|
||||||
# echo "Matches ", n.info, " ", typeToString(sym.typ)
|
|
||||||
# debug sym
|
|
||||||
# writeMatches(z)
|
|
||||||
# for i in 1 .. <len(z.call):
|
|
||||||
# z.call[i].typ.debug
|
|
||||||
# quit 1
|
|
||||||
|
|
||||||
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||||
|
|
@ -462,3 +444,9 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||||
var resolved = semOverloadedCall(c, call, call, {fn.kind})
|
var resolved = semOverloadedCall(c, call, call, {fn.kind})
|
||||||
if resolved != nil:
|
if resolved != nil:
|
||||||
result = resolved.sons[0].sym
|
result = resolved.sons[0].sym
|
||||||
|
if not compareTypes(result.typ.sons[0], fn.typ.sons[0], dcEqIgnoreDistinct):
|
||||||
|
result = nil
|
||||||
|
elif result.magic in {mArrPut, mArrGet}:
|
||||||
|
# cannot borrow these magics for now
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -414,8 +414,6 @@ proc arrayConstrType(c: PContext, n: PNode): PType =
|
||||||
if sonsLen(n) == 0:
|
if sonsLen(n) == 0:
|
||||||
rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
|
rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
|
||||||
else:
|
else:
|
||||||
var x = n.sons[0]
|
|
||||||
var lastIndex: BiggestInt = sonsLen(n) - 1
|
|
||||||
var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
|
var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
|
||||||
addSonSkipIntLit(typ, t)
|
addSonSkipIntLit(typ, t)
|
||||||
typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
|
typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
|
||||||
|
|
@ -512,16 +510,6 @@ proc fixAbstractType(c: PContext, n: PNode) =
|
||||||
#if (it.typ == nil):
|
#if (it.typ == nil):
|
||||||
# InternalError(it.info, "fixAbstractType: " & renderTree(it))
|
# InternalError(it.info, "fixAbstractType: " & renderTree(it))
|
||||||
|
|
||||||
proc skipObjConv(n: PNode): PNode =
|
|
||||||
case n.kind
|
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
|
||||||
if skipTypes(n.sons[1].typ, abstractPtrs).kind in {tyTuple, tyObject}:
|
|
||||||
result = n.sons[1]
|
|
||||||
else:
|
|
||||||
result = n
|
|
||||||
of nkObjUpConv, nkObjDownConv: result = n.sons[0]
|
|
||||||
else: result = n
|
|
||||||
|
|
||||||
proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
|
proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult =
|
||||||
result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
|
result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr)
|
||||||
|
|
||||||
|
|
@ -701,9 +689,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||||
# error correction, prevents endless for loop elimination in transf.
|
# error correction, prevents endless for loop elimination in transf.
|
||||||
# See bug #2051:
|
# See bug #2051:
|
||||||
result.sons[0] = newSymNode(errorSym(c, n))
|
result.sons[0] = newSymNode(errorSym(c, n))
|
||||||
if sfNoSideEffect notin callee.flags:
|
|
||||||
if {sfImportc, sfSideEffect} * callee.flags != {}:
|
|
||||||
incl(c.p.owner.flags, sfSideEffect)
|
|
||||||
|
|
||||||
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
|
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||||
|
|
||||||
|
|
@ -804,9 +789,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
else:
|
else:
|
||||||
result = m.call
|
result = m.call
|
||||||
instGenericConvertersSons(c, result, m)
|
instGenericConvertersSons(c, result, m)
|
||||||
# we assume that a procedure that calls something indirectly
|
|
||||||
# has side-effects:
|
|
||||||
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
|
|
||||||
elif t != nil and t.kind == tyTypeDesc:
|
elif t != nil and t.kind == tyTypeDesc:
|
||||||
if n.len == 1: return semObjConstr(c, n, flags)
|
if n.len == 1: return semObjConstr(c, n, flags)
|
||||||
return semConv(c, n)
|
return semConv(c, n)
|
||||||
|
|
@ -1040,9 +1022,6 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
markUsed(n.info, s)
|
markUsed(n.info, s)
|
||||||
styleCheckUse(n.info, s)
|
styleCheckUse(n.info, s)
|
||||||
# if a proc accesses a global variable, it is not side effect free:
|
|
||||||
if sfGlobal in s.flags:
|
|
||||||
incl(c.p.owner.flags, sfSideEffect)
|
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
# We cannot check for access to outer vars for example because it's still
|
# We cannot check for access to outer vars for example because it's still
|
||||||
# not sure the symbol really ends up being used:
|
# not sure the symbol really ends up being used:
|
||||||
|
|
@ -1421,8 +1400,9 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||||
# a = b # both are vars, means: a[] = b[]
|
# a = b # both are vars, means: a[] = b[]
|
||||||
# a = b # b no 'var T' means: a = addr(b)
|
# a = b # b no 'var T' means: a = addr(b)
|
||||||
var le = a.typ
|
var le = a.typ
|
||||||
if skipTypes(le, {tyGenericInst}).kind != tyVar and
|
if (skipTypes(le, {tyGenericInst}).kind != tyVar and
|
||||||
isAssignable(c, a) == arNone:
|
isAssignable(c, a) == arNone) or
|
||||||
|
skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}:
|
||||||
# Direct assignment to a discriminant is allowed!
|
# Direct assignment to a discriminant is allowed!
|
||||||
localError(a.info, errXCannotBeAssignedTo,
|
localError(a.info, errXCannotBeAssignedTo,
|
||||||
renderTree(a, {renderNoComments}))
|
renderTree(a, {renderNoComments}))
|
||||||
|
|
|
||||||
|
|
@ -458,32 +458,6 @@ proc getConstIfExpr(c: PSym, n: PNode): PNode =
|
||||||
if result == nil: result = getConstExpr(c, it.sons[0])
|
if result == nil: result = getConstExpr(c, it.sons[0])
|
||||||
else: internalError(it.info, "getConstIfExpr()")
|
else: internalError(it.info, "getConstIfExpr()")
|
||||||
|
|
||||||
proc partialAndExpr(c: PSym, n: PNode): PNode =
|
|
||||||
# partial evaluation
|
|
||||||
result = n
|
|
||||||
var a = getConstExpr(c, n.sons[1])
|
|
||||||
var b = getConstExpr(c, n.sons[2])
|
|
||||||
if a != nil:
|
|
||||||
if getInt(a) == 0: result = a
|
|
||||||
elif b != nil: result = b
|
|
||||||
else: result = n.sons[2]
|
|
||||||
elif b != nil:
|
|
||||||
if getInt(b) == 0: result = b
|
|
||||||
else: result = n.sons[1]
|
|
||||||
|
|
||||||
proc partialOrExpr(c: PSym, n: PNode): PNode =
|
|
||||||
# partial evaluation
|
|
||||||
result = n
|
|
||||||
var a = getConstExpr(c, n.sons[1])
|
|
||||||
var b = getConstExpr(c, n.sons[2])
|
|
||||||
if a != nil:
|
|
||||||
if getInt(a) != 0: result = a
|
|
||||||
elif b != nil: result = b
|
|
||||||
else: result = n.sons[2]
|
|
||||||
elif b != nil:
|
|
||||||
if getInt(b) != 0: result = b
|
|
||||||
else: result = n.sons[1]
|
|
||||||
|
|
||||||
proc leValueConv(a, b: PNode): bool =
|
proc leValueConv(a, b: PNode): bool =
|
||||||
result = false
|
result = false
|
||||||
case a.kind
|
case a.kind
|
||||||
|
|
|
||||||
|
|
@ -202,24 +202,25 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
if s != nil:
|
if s != nil:
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
|
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
|
||||||
let scOption = if s.name.id in ctx.toMixin: scForceOpen else: scOpen
|
let sc = symChoice(c, fn, s,
|
||||||
|
if s.name.id in ctx.toMixin: scForceOpen else: scOpen)
|
||||||
case s.kind
|
case s.kind
|
||||||
of skMacro:
|
of skMacro:
|
||||||
if macroToExpand(s):
|
if macroToExpand(s) and sc.safeLen <= 1:
|
||||||
styleCheckUse(fn.info, s)
|
styleCheckUse(fn.info, s)
|
||||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||||
result = semGenericStmt(c, result, flags, ctx)
|
result = semGenericStmt(c, result, flags, ctx)
|
||||||
else:
|
else:
|
||||||
n.sons[0] = symChoice(c, fn, s, scOption)
|
n.sons[0] = sc
|
||||||
result = n
|
result = n
|
||||||
mixinContext = true
|
mixinContext = true
|
||||||
of skTemplate:
|
of skTemplate:
|
||||||
if macroToExpand(s):
|
if macroToExpand(s) and sc.safeLen <= 1:
|
||||||
styleCheckUse(fn.info, s)
|
styleCheckUse(fn.info, s)
|
||||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||||
result = semGenericStmt(c, result, flags, ctx)
|
result = semGenericStmt(c, result, flags, ctx)
|
||||||
else:
|
else:
|
||||||
n.sons[0] = symChoice(c, fn, s, scOption)
|
n.sons[0] = sc
|
||||||
result = n
|
result = n
|
||||||
# BUGFIX: we must not return here, we need to do first phase of
|
# BUGFIX: we must not return here, we need to do first phase of
|
||||||
# symbol lookup. Also since templates and macros can do scope injections
|
# symbol lookup. Also since templates and macros can do scope injections
|
||||||
|
|
@ -230,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
# Leave it as an identifier.
|
# Leave it as an identifier.
|
||||||
discard
|
discard
|
||||||
of skProc, skMethod, skIterator, skConverter, skModule:
|
of skProc, skMethod, skIterator, skConverter, skModule:
|
||||||
result.sons[0] = symChoice(c, fn, s, scOption)
|
result.sons[0] = sc
|
||||||
# do not check of 's.magic==mRoof' here because it might be some
|
# do not check of 's.magic==mRoof' here because it might be some
|
||||||
# other '^' but after overload resolution the proper one:
|
# other '^' but after overload resolution the proper one:
|
||||||
if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^":
|
if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^":
|
||||||
|
|
|
||||||
|
|
@ -97,22 +97,6 @@ proc genericCacheGet(genericSym: PSym, entry: TInstantiation;
|
||||||
if inst.compilesId == id and sameInstantiation(entry, inst[]):
|
if inst.compilesId == id and sameInstantiation(entry, inst[]):
|
||||||
return inst.sym
|
return inst.sym
|
||||||
|
|
||||||
proc removeDefaultParamValues(n: PNode) =
|
|
||||||
# we remove default params, because they cannot be instantiated properly
|
|
||||||
# and they are not needed anyway for instantiation (each param is already
|
|
||||||
# provided).
|
|
||||||
when false:
|
|
||||||
for i in countup(1, sonsLen(n)-1):
|
|
||||||
var a = n.sons[i]
|
|
||||||
if a.kind != nkIdentDefs: IllFormedAst(a)
|
|
||||||
var L = a.len
|
|
||||||
if a.sons[L-1].kind != nkEmpty and a.sons[L-2].kind != nkEmpty:
|
|
||||||
# ``param: typ = defaultVal``.
|
|
||||||
# We don't need defaultVal for semantic checking and it's wrong for
|
|
||||||
# ``cmp: proc (a, b: T): int = cmp``. Hm, for ``cmp = cmp`` that is
|
|
||||||
# not possible... XXX We don't solve this issue here.
|
|
||||||
a.sons[L-1] = ast.emptyNode
|
|
||||||
|
|
||||||
proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
|
proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
|
||||||
# we need to create a fresh set of gensym'ed symbols:
|
# we need to create a fresh set of gensym'ed symbols:
|
||||||
if n.kind == nkSym and sfGenSym in n.sym.flags and n.sym.owner == orig:
|
if n.kind == nkSym and sfGenSym in n.sym.flags and n.sym.owner == orig:
|
||||||
|
|
@ -128,17 +112,6 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
|
||||||
|
|
||||||
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
|
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
|
||||||
|
|
||||||
proc addProcDecls(c: PContext, fn: PSym) =
|
|
||||||
# get the proc itself in scope (e.g. for recursion)
|
|
||||||
addDecl(c, fn)
|
|
||||||
|
|
||||||
for i in 1 .. <fn.typ.n.len:
|
|
||||||
var param = fn.typ.n.sons[i].sym
|
|
||||||
param.owner = fn
|
|
||||||
addParamOrResult(c, param, fn.kind)
|
|
||||||
|
|
||||||
maybeAddResult(c, fn, fn.ast)
|
|
||||||
|
|
||||||
proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
|
proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
|
||||||
if n.sons[bodyPos].kind != nkEmpty:
|
if n.sons[bodyPos].kind != nkEmpty:
|
||||||
inc c.inGenericInst
|
inc c.inGenericInst
|
||||||
|
|
@ -172,9 +145,10 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
||||||
proc sideEffectsCheck(c: PContext, s: PSym) =
|
proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||||
if {sfNoSideEffect, sfSideEffect} * s.flags ==
|
when false:
|
||||||
{sfNoSideEffect, sfSideEffect}:
|
if {sfNoSideEffect, sfSideEffect} * s.flags ==
|
||||||
localError(s.info, errXhasSideEffects, s.name.s)
|
{sfNoSideEffect, sfSideEffect}:
|
||||||
|
localError(s.info, errXhasSideEffects, s.name.s)
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||||
allowMetaTypes = false): PType =
|
allowMetaTypes = false): PType =
|
||||||
|
|
@ -187,9 +161,6 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||||
cl.allowMetaTypes = allowMetaTypes
|
cl.allowMetaTypes = allowMetaTypes
|
||||||
result = replaceTypeVarsT(cl, header)
|
result = replaceTypeVarsT(cl, header)
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
|
||||||
result = instGenericContainer(c, n.info, header)
|
|
||||||
|
|
||||||
proc instantiateProcType(c: PContext, pt: TIdTable,
|
proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||||
prc: PSym, info: TLineInfo) =
|
prc: PSym, info: TLineInfo) =
|
||||||
# XXX: Instantiates a generic proc signature, while at the same
|
# XXX: Instantiates a generic proc signature, while at the same
|
||||||
|
|
|
||||||
|
|
@ -151,13 +151,6 @@ proc isStrangeArray(t: PType): bool =
|
||||||
let t = t.skipTypes(abstractInst)
|
let t = t.skipTypes(abstractInst)
|
||||||
result = t.kind == tyArray and t.firstOrd != 0
|
result = t.kind == tyArray and t.firstOrd != 0
|
||||||
|
|
||||||
proc isNegative(n: PNode): bool =
|
|
||||||
let n = n.skipConv
|
|
||||||
if n.kind in {nkCharLit..nkUInt64Lit}:
|
|
||||||
result = n.intVal < 0
|
|
||||||
elif n.kind in nkCallKinds and n.sons[0].kind == nkSym:
|
|
||||||
result = n.sons[0].sym.magic in {mUnaryMinusI, mUnaryMinusI64}
|
|
||||||
|
|
||||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
case n[0].sym.magic
|
case n[0].sym.magic
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ type
|
||||||
init: seq[int] # list of initialized variables
|
init: seq[int] # list of initialized variables
|
||||||
guards: TModel # nested guards
|
guards: TModel # nested guards
|
||||||
locked: seq[PNode] # locked locations
|
locked: seq[PNode] # locked locations
|
||||||
gcUnsafe, isRecursive, isToplevel: bool
|
gcUnsafe, isRecursive, isToplevel, hasSideEffect: bool
|
||||||
maxLockLevel, currLockLevel: TLockLevel
|
maxLockLevel, currLockLevel: TLockLevel
|
||||||
PEffects = var TEffects
|
PEffects = var TEffects
|
||||||
|
|
||||||
|
|
@ -192,6 +192,14 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
|
||||||
a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
|
a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
|
||||||
a.owner, reason.info)
|
a.owner, reason.info)
|
||||||
|
|
||||||
|
when true:
|
||||||
|
template markSideEffect(a: PEffects; reason: typed) =
|
||||||
|
a.hasSideEffect = true
|
||||||
|
else:
|
||||||
|
template markSideEffect(a: PEffects; reason: typed) =
|
||||||
|
a.hasSideEffect = true
|
||||||
|
markGcUnsafe(a, reason)
|
||||||
|
|
||||||
proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
|
proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
|
||||||
let u = s.gcUnsafetyReason
|
let u = s.gcUnsafetyReason
|
||||||
if u != nil and not cycleCheck.containsOrIncl(u.id):
|
if u != nil and not cycleCheck.containsOrIncl(u.id):
|
||||||
|
|
@ -226,12 +234,16 @@ proc useVar(a: PEffects, n: PNode) =
|
||||||
message(n.info, warnUninit, s.name.s)
|
message(n.info, warnUninit, s.name.s)
|
||||||
# prevent superfluous warnings about the same variable:
|
# prevent superfluous warnings about the same variable:
|
||||||
a.init.add s.id
|
a.init.add s.id
|
||||||
if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet}:
|
if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
|
||||||
|
s.magic != mNimVm:
|
||||||
if s.guard != nil: guardGlobal(a, n, s.guard)
|
if s.guard != nil: guardGlobal(a, n, s.guard)
|
||||||
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and
|
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and
|
||||||
(tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
|
(tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
|
||||||
#if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
#if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||||
markGcUnsafe(a, s)
|
markGcUnsafe(a, s)
|
||||||
|
else:
|
||||||
|
markSideEffect(a, s)
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TIntersection = seq[tuple[id, count: int]] # a simple count table
|
TIntersection = seq[tuple[id, count: int]] # a simple count table
|
||||||
|
|
@ -268,10 +280,6 @@ proc createTag(n: PNode): PNode =
|
||||||
result.typ = sysTypeFromName"TEffect"
|
result.typ = sysTypeFromName"TEffect"
|
||||||
if not n.isNil: result.info = n.info
|
if not n.isNil: result.info = n.info
|
||||||
|
|
||||||
proc createAnyGlobal(n: PNode): PNode =
|
|
||||||
result = newSymNode(anyGlobal)
|
|
||||||
result.info = n.info
|
|
||||||
|
|
||||||
proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
|
proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
|
||||||
assert e.kind != nkRaiseStmt
|
assert e.kind != nkRaiseStmt
|
||||||
var aa = a.exc
|
var aa = a.exc
|
||||||
|
|
@ -495,6 +503,8 @@ 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, s)
|
markGcUnsafe(tracked, s)
|
||||||
|
if tfNoSideEffect notin s.typ.flags:
|
||||||
|
markSideEffect(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) =
|
||||||
|
|
@ -550,12 +560,16 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
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, a)
|
markGcUnsafe(tracked, a)
|
||||||
|
elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner):
|
||||||
|
markSideEffect(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, a)
|
markGcUnsafe(tracked, a)
|
||||||
|
elif tfNoSideEffect notin op.flags:
|
||||||
|
markSideEffect(tracked, a)
|
||||||
notNilCheck(tracked, n, paramType)
|
notNilCheck(tracked, n, paramType)
|
||||||
|
|
||||||
proc breaksBlock(n: PNode): bool =
|
proc breaksBlock(n: PNode): bool =
|
||||||
|
|
@ -684,6 +698,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
if a.sym == tracked.owner: tracked.isRecursive = true
|
if a.sym == tracked.owner: tracked.isRecursive = true
|
||||||
# even for recursive calls we need to check the lock levels (!):
|
# even for recursive calls we need to check the lock levels (!):
|
||||||
mergeLockLevels(tracked, n, a.sym.getLockLevel)
|
mergeLockLevels(tracked, n, a.sym.getLockLevel)
|
||||||
|
if sfSideEffect in a.sym.flags: markSideEffect(tracked, a)
|
||||||
else:
|
else:
|
||||||
mergeLockLevels(tracked, n, op.lockLevel)
|
mergeLockLevels(tracked, n, op.lockLevel)
|
||||||
var effectList = op.n.sons[0]
|
var effectList = op.n.sons[0]
|
||||||
|
|
@ -702,6 +717,10 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
if not (a.kind == nkSym and a.sym == tracked.owner):
|
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||||
markGcUnsafe(tracked, a)
|
markGcUnsafe(tracked, a)
|
||||||
|
if tfNoSideEffect notin op.flags and not importedFromC(a):
|
||||||
|
# and it's not a recursive call:
|
||||||
|
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||||
|
markSideEffect(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:
|
||||||
|
|
@ -793,9 +812,6 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
proc subtypeRelation(spec, real: PNode): bool =
|
proc subtypeRelation(spec, real: PNode): bool =
|
||||||
result = safeInheritanceDiff(real.excType, spec.typ) <= 0
|
result = safeInheritanceDiff(real.excType, spec.typ) <= 0
|
||||||
|
|
||||||
proc symbolPredicate(spec, real: PNode): bool =
|
|
||||||
result = real.sym.id == spec.sym.id
|
|
||||||
|
|
||||||
proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool;
|
proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool;
|
||||||
effectPredicate: proc (a, b: PNode): bool {.nimcall.}) =
|
effectPredicate: proc (a, b: PNode): bool {.nimcall.}) =
|
||||||
# check that any real exception is listed in 'spec'; mark those as used;
|
# check that any real exception is listed in 'spec'; mark those as used;
|
||||||
|
|
@ -912,8 +928,15 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||||
else:
|
else:
|
||||||
listGcUnsafety(s, onlyWarning=true)
|
listGcUnsafety(s, onlyWarning=true)
|
||||||
#localError(s.info, warnGcUnsafe2, s.name.s)
|
#localError(s.info, warnGcUnsafe2, s.name.s)
|
||||||
|
if sfNoSideEffect in s.flags and t.hasSideEffect:
|
||||||
|
when false:
|
||||||
|
listGcUnsafety(s, onlyWarning=false)
|
||||||
|
else:
|
||||||
|
localError(s.info, errXhasSideEffects, s.name.s)
|
||||||
if not t.gcUnsafe:
|
if not t.gcUnsafe:
|
||||||
s.typ.flags.incl tfGcSafe
|
s.typ.flags.incl tfGcSafe
|
||||||
|
if not t.hasSideEffect and sfSideEffect notin s.flags:
|
||||||
|
s.typ.flags.incl tfNoSideEffect
|
||||||
if s.typ.lockLevel == UnspecifiedLockLevel:
|
if s.typ.lockLevel == UnspecifiedLockLevel:
|
||||||
s.typ.lockLevel = t.maxLockLevel
|
s.typ.lockLevel = t.maxLockLevel
|
||||||
elif t.maxLockLevel > s.typ.lockLevel:
|
elif t.maxLockLevel > s.typ.lockLevel:
|
||||||
|
|
|
||||||
|
|
@ -304,8 +304,14 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
|
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
|
||||||
result = fitNode(c, typ, n)
|
result = fitNode(c, typ, n)
|
||||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||||
changeType(result.sons[1], typ, check=true)
|
let r1 = result.sons[1]
|
||||||
result = result.sons[1]
|
if r1.kind in {nkCharLit..nkUInt64Lit} and typ.skipTypes(abstractRange).kind in {tyFloat..tyFloat128}:
|
||||||
|
result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal)
|
||||||
|
result.info = n.info
|
||||||
|
result.typ = typ
|
||||||
|
else:
|
||||||
|
changeType(r1, typ, check=true)
|
||||||
|
result = r1
|
||||||
elif not sameType(result.typ, typ):
|
elif not sameType(result.typ, typ):
|
||||||
changeType(result, typ, check=false)
|
changeType(result, typ, check=false)
|
||||||
|
|
||||||
|
|
@ -1135,11 +1141,6 @@ type
|
||||||
TProcCompilationSteps = enum
|
TProcCompilationSteps = enum
|
||||||
stepRegisterSymbol,
|
stepRegisterSymbol,
|
||||||
stepDetermineType,
|
stepDetermineType,
|
||||||
stepCompileBody
|
|
||||||
|
|
||||||
proc isForwardDecl(s: PSym): bool =
|
|
||||||
internalAssert s.kind == skProc
|
|
||||||
result = s.ast[bodyPos].kind != nkEmpty
|
|
||||||
|
|
||||||
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
validPragmas: TSpecialWords,
|
validPragmas: TSpecialWords,
|
||||||
|
|
@ -1177,8 +1178,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
s.ast = n
|
s.ast = n
|
||||||
#s.scope = c.currentScope
|
#s.scope = c.currentScope
|
||||||
|
|
||||||
# if typeIsDetermined: assert phase == stepCompileBody
|
|
||||||
# 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
|
||||||
|
|
@ -1228,7 +1227,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
implicitPragmas(c, s, n, validPragmas)
|
implicitPragmas(c, s, n, validPragmas)
|
||||||
else:
|
else:
|
||||||
if n.sons[pragmasPos].kind != nkEmpty:
|
if n.sons[pragmasPos].kind != nkEmpty:
|
||||||
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
|
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX,
|
||||||
|
"'" & proto.name.s & "' from " & $proto.info)
|
||||||
if sfForward notin proto.flags:
|
if sfForward notin proto.flags:
|
||||||
wrongRedefinition(n.info, proto.name.s)
|
wrongRedefinition(n.info, proto.name.s)
|
||||||
excl(proto.flags, sfForward)
|
excl(proto.flags, sfForward)
|
||||||
|
|
@ -1397,6 +1397,11 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||||
if namePos >= result.safeLen: return result
|
if namePos >= result.safeLen: return result
|
||||||
var s = result.sons[namePos].sym
|
var s = result.sons[namePos].sym
|
||||||
var t = s.typ
|
var t = s.typ
|
||||||
|
var allUntyped = true
|
||||||
|
for i in 1 .. t.n.len-1:
|
||||||
|
let param = t.n.sons[i].sym
|
||||||
|
if param.typ.kind != tyExpr: allUntyped = false
|
||||||
|
if allUntyped: incl(s.flags, sfAllUntyped)
|
||||||
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
|
if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
|
||||||
if n.sons[bodyPos].kind == nkEmpty:
|
if n.sons[bodyPos].kind == nkEmpty:
|
||||||
localError(n.info, errImplOfXexpected, s.name.s)
|
localError(n.info, errImplOfXexpected, s.name.s)
|
||||||
|
|
@ -1560,8 +1565,3 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
proc semStmt(c: PContext, n: PNode): PNode =
|
proc semStmt(c: PContext, n: PNode): PNode =
|
||||||
# now: simply an alias:
|
# now: simply an alias:
|
||||||
result = semExprNoType(c, n)
|
result = semExprNoType(c, n)
|
||||||
|
|
||||||
proc semStmtScope(c: PContext, n: PNode): PNode =
|
|
||||||
openScope(c)
|
|
||||||
result = semStmt(c, n)
|
|
||||||
closeScope(c)
|
|
||||||
|
|
|
||||||
|
|
@ -287,35 +287,6 @@ proc semTemplBodySons(c: var TemplCtx, n: PNode): PNode =
|
||||||
for i in 0.. < n.len:
|
for i in 0.. < n.len:
|
||||||
result.sons[i] = semTemplBody(c, n.sons[i])
|
result.sons[i] = semTemplBody(c, n.sons[i])
|
||||||
|
|
||||||
proc wrapInBind(c: var TemplCtx; n: PNode; opr: string): PNode =
|
|
||||||
let ident = getIdent(opr)
|
|
||||||
if ident.id in c.toInject: return n
|
|
||||||
|
|
||||||
let s = searchInScopes(c.c, ident)
|
|
||||||
if s != nil:
|
|
||||||
var callee: PNode
|
|
||||||
if contains(c.toBind, s.id):
|
|
||||||
callee = symChoice(c.c, n, s, scClosed)
|
|
||||||
elif contains(c.toMixin, s.name.id):
|
|
||||||
callee = symChoice(c.c, n, s, scForceOpen)
|
|
||||||
elif s.owner == c.owner and sfGenSym in s.flags:
|
|
||||||
# template tmp[T](x: var seq[T]) =
|
|
||||||
# var yz: T
|
|
||||||
incl(s.flags, sfUsed)
|
|
||||||
callee = newSymNode(s, n.info)
|
|
||||||
styleCheckUse(n.info, s)
|
|
||||||
else:
|
|
||||||
callee = semTemplSymbol(c.c, n, s)
|
|
||||||
|
|
||||||
let call = newNodeI(nkCall, n.info)
|
|
||||||
call.add(callee)
|
|
||||||
for i in 0 .. n.len-1: call.add(n[i])
|
|
||||||
result = newNodeI(nkBind, n.info, 2)
|
|
||||||
result.sons[0] = n
|
|
||||||
result.sons[1] = call
|
|
||||||
else:
|
|
||||||
result = n
|
|
||||||
|
|
||||||
proc oprIsRoof(n: PNode): bool =
|
proc oprIsRoof(n: PNode): bool =
|
||||||
const roof = "^"
|
const roof = "^"
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,8 @@ proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
|
||||||
result = newOrPrevType(kind, prev, c)
|
result = newOrPrevType(kind, prev, c)
|
||||||
if sonsLen(n) == 2:
|
if sonsLen(n) == 2:
|
||||||
var base = semTypeNode(c, n.sons[1], nil)
|
var base = semTypeNode(c, n.sons[1], nil)
|
||||||
|
if base.kind == tyVoid:
|
||||||
|
localError(n.info, errTIsNotAConcreteType, typeToString(base))
|
||||||
addSonSkipIntLit(result, base)
|
addSonSkipIntLit(result, base)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errXExpectsOneTypeParam, kindStr)
|
localError(n.info, errXExpectsOneTypeParam, kindStr)
|
||||||
|
|
|
||||||
|
|
@ -221,13 +221,14 @@ proc cmpCandidates*(a, b: TCandidate): int =
|
||||||
if result != 0: return
|
if result != 0: return
|
||||||
result = a.convMatches - b.convMatches
|
result = a.convMatches - b.convMatches
|
||||||
if result != 0: return
|
if result != 0: return
|
||||||
result = a.calleeScope - b.calleeScope
|
|
||||||
if result != 0: return
|
|
||||||
# the other way round because of other semantics:
|
# the other way round because of other semantics:
|
||||||
result = b.inheritancePenalty - a.inheritancePenalty
|
result = b.inheritancePenalty - a.inheritancePenalty
|
||||||
if result != 0: return
|
if result != 0: return
|
||||||
# prefer more specialized generic over more general generic:
|
# prefer more specialized generic over more general generic:
|
||||||
result = complexDisambiguation(a.callee, b.callee)
|
result = complexDisambiguation(a.callee, b.callee)
|
||||||
|
# only as a last resort, consider scoping:
|
||||||
|
if result != 0: return
|
||||||
|
result = a.calleeScope - b.calleeScope
|
||||||
|
|
||||||
proc writeMatches*(c: TCandidate) =
|
proc writeMatches*(c: TCandidate) =
|
||||||
writeLine(stdout, "exact matches: " & $c.exactMatches)
|
writeLine(stdout, "exact matches: " & $c.exactMatches)
|
||||||
|
|
@ -1309,8 +1310,9 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
var call = newNodeI(nkCall, arg.info)
|
var call = newNodeI(nkCall, arg.info)
|
||||||
call.add(f.n.copyTree)
|
call.add(f.n.copyTree)
|
||||||
call.add(arg.copyTree)
|
call.add(arg.copyTree)
|
||||||
result = c.semOverloadedCall(c, call, call, routineKinds)
|
result = c.semExpr(c, call)
|
||||||
if result != nil:
|
if result != nil:
|
||||||
|
if result.typ == nil: return nil
|
||||||
# resulting type must be consistent with the other arguments:
|
# resulting type must be consistent with the other arguments:
|
||||||
var r = typeRel(m, f.sons[0], result.typ)
|
var r = typeRel(m, f.sons[0], result.typ)
|
||||||
if r < isGeneric: return nil
|
if r < isGeneric: return nil
|
||||||
|
|
@ -1319,13 +1321,6 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
if r == isGeneric:
|
if r == isGeneric:
|
||||||
result.typ = getInstantiatedType(c, arg, m, base(f))
|
result.typ = getInstantiatedType(c, arg, m, base(f))
|
||||||
m.baseTypeMatch = true
|
m.baseTypeMatch = true
|
||||||
# bug #4545: allow the call to go through a 'var T':
|
|
||||||
let vt = result.sons[0].typ.sons[1]
|
|
||||||
if vt.kind == tyVar:
|
|
||||||
let x = result.sons[1]
|
|
||||||
let va = newNodeIT(nkHiddenAddr, x.info, vt)
|
|
||||||
va.add x
|
|
||||||
result.sons[1] = va
|
|
||||||
|
|
||||||
proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
|
proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
|
||||||
case r
|
case r
|
||||||
|
|
|
||||||
|
|
@ -474,12 +474,14 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||||
|
|
||||||
type
|
type
|
||||||
TPutArgInto = enum
|
TPutArgInto = enum
|
||||||
paDirectMapping, paFastAsgn, paVarAsgn
|
paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray
|
||||||
|
|
||||||
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
||||||
# This analyses how to treat the mapping "formal <-> arg" in an
|
# This analyses how to treat the mapping "formal <-> arg" in an
|
||||||
# inline context.
|
# inline context.
|
||||||
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
|
if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
|
||||||
|
if arg.kind == nkStmtListExpr:
|
||||||
|
return paComplexOpenarray
|
||||||
return paDirectMapping # XXX really correct?
|
return paDirectMapping # XXX really correct?
|
||||||
# what if ``arg`` has side-effects?
|
# what if ``arg`` has side-effects?
|
||||||
case arg.kind
|
case arg.kind
|
||||||
|
|
@ -569,6 +571,14 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
|
assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
|
||||||
idNodeTablePut(newC.mapping, formal, arg)
|
idNodeTablePut(newC.mapping, formal, arg)
|
||||||
# XXX BUG still not correct if the arg has a side effect!
|
# XXX BUG still not correct if the arg has a side effect!
|
||||||
|
of paComplexOpenarray:
|
||||||
|
let typ = newType(tySequence, formal.owner)
|
||||||
|
addSonSkipIntLit(typ, formal.typ.sons[0])
|
||||||
|
var temp = newTemp(c, typ, formal.info)
|
||||||
|
addVar(v, temp)
|
||||||
|
add(stmtList, newAsgnStmt(c, temp, arg.PTransNode))
|
||||||
|
idNodeTablePut(newC.mapping, formal, temp)
|
||||||
|
|
||||||
var body = iter.getBody.copyTree
|
var body = iter.getBody.copyTree
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
# XXX optimize this somehow. But the check "c.inlining" is not correct:
|
# XXX optimize this somehow. But the check "c.inlining" is not correct:
|
||||||
|
|
@ -584,13 +594,6 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
popTransCon(c)
|
popTransCon(c)
|
||||||
# echo "transformed: ", stmtList.PNode.renderTree
|
# echo "transformed: ", stmtList.PNode.renderTree
|
||||||
|
|
||||||
proc getMagicOp(call: PNode): TMagic =
|
|
||||||
if call.sons[0].kind == nkSym and
|
|
||||||
call.sons[0].sym.kind in {skProc, skMethod, skConverter}:
|
|
||||||
result = call.sons[0].sym.magic
|
|
||||||
else:
|
|
||||||
result = mNone
|
|
||||||
|
|
||||||
proc transformCase(c: PTransf, n: PNode): PTransNode =
|
proc transformCase(c: PTransf, n: PNode): PTransNode =
|
||||||
# removes `elif` branches of a case stmt
|
# removes `elif` branches of a case stmt
|
||||||
# adds ``else: nil`` if needed for the code generator
|
# adds ``else: nil`` if needed for the code generator
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ proc isOrdinalType*(t: PType): bool
|
||||||
proc enumHasHoles*(t: PType): bool
|
proc enumHasHoles*(t: PType): bool
|
||||||
|
|
||||||
const
|
const
|
||||||
|
# TODO: Remove tyTypeDesc from each abstractX and (where necessary)
|
||||||
|
# replace with typedescX
|
||||||
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
|
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
|
||||||
tyConst, tyMutable, tyTypeDesc}
|
tyConst, tyMutable, tyTypeDesc}
|
||||||
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
|
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
|
||||||
|
|
@ -61,6 +63,7 @@ const
|
||||||
|
|
||||||
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
|
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
|
||||||
tyTypeDesc}
|
tyTypeDesc}
|
||||||
|
# typedescX is used if we're sure tyTypeDesc should be included (or skipped)
|
||||||
typedescPtrs* = abstractPtrs + {tyTypeDesc}
|
typedescPtrs* = abstractPtrs + {tyTypeDesc}
|
||||||
typedescInst* = abstractInst + {tyTypeDesc}
|
typedescInst* = abstractInst + {tyTypeDesc}
|
||||||
|
|
||||||
|
|
@ -142,10 +145,6 @@ proc elemType*(t: PType): PType =
|
||||||
else: result = t.lastSon
|
else: result = t.lastSon
|
||||||
assert(result != nil)
|
assert(result != nil)
|
||||||
|
|
||||||
proc skipGeneric(t: PType): PType =
|
|
||||||
result = t
|
|
||||||
while result.kind == tyGenericInst: result = lastSon(result)
|
|
||||||
|
|
||||||
proc isOrdinalType(t: PType): bool =
|
proc isOrdinalType(t: PType): bool =
|
||||||
assert(t != nil)
|
assert(t != nil)
|
||||||
const
|
const
|
||||||
|
|
@ -575,10 +574,6 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
result = typeToStr[t.kind]
|
result = typeToStr[t.kind]
|
||||||
result.addTypeFlags(t)
|
result.addTypeFlags(t)
|
||||||
|
|
||||||
proc resultType(t: PType): PType =
|
|
||||||
assert(t.kind == tyProc)
|
|
||||||
result = t.sons[0] # nil is allowed
|
|
||||||
|
|
||||||
proc base(t: PType): PType =
|
proc base(t: PType): PType =
|
||||||
result = t.sons[0]
|
result = t.sons[0]
|
||||||
|
|
||||||
|
|
@ -658,7 +653,14 @@ proc lengthOrd(t: PType): BiggestInt =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyInt64, tyInt32, tyInt: result = lastOrd(t)
|
of tyInt64, tyInt32, tyInt: result = lastOrd(t)
|
||||||
of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0])
|
of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0])
|
||||||
else: result = lastOrd(t) - firstOrd(t) + 1
|
else:
|
||||||
|
let last = lastOrd t
|
||||||
|
let first = firstOrd t
|
||||||
|
# XXX use a better overflow check here:
|
||||||
|
if last == high(BiggestInt) and first <= 0:
|
||||||
|
result = last
|
||||||
|
else:
|
||||||
|
result = lastOrd(t) - firstOrd(t) + 1
|
||||||
|
|
||||||
# -------------- type equality -----------------------------------------------
|
# -------------- type equality -----------------------------------------------
|
||||||
|
|
||||||
|
|
@ -769,18 +771,6 @@ proc equalParams(a, b: PNode): TParamsEquality =
|
||||||
result = paramsIncompatible # overloading by different
|
result = paramsIncompatible # overloading by different
|
||||||
# result types does not work
|
# result types does not work
|
||||||
|
|
||||||
proc sameLiteral(x, y: PNode): bool =
|
|
||||||
if x.kind == y.kind:
|
|
||||||
case x.kind
|
|
||||||
of nkCharLit..nkInt64Lit: result = x.intVal == y.intVal
|
|
||||||
of nkFloatLit..nkFloat64Lit: result = x.floatVal == y.floatVal
|
|
||||||
of nkNilLit: result = true
|
|
||||||
else: assert(false)
|
|
||||||
|
|
||||||
proc sameRanges(a, b: PNode): bool =
|
|
||||||
result = sameLiteral(a.sons[0], b.sons[0]) and
|
|
||||||
sameLiteral(a.sons[1], b.sons[1])
|
|
||||||
|
|
||||||
proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
|
proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
|
||||||
# two tuples are equivalent iff the names, types and positions are the same;
|
# two tuples are equivalent iff the names, types and positions are the same;
|
||||||
# however, both types may not have any field names (t.n may be nil) which
|
# however, both types may not have any field names (t.n may be nil) which
|
||||||
|
|
@ -1067,10 +1057,10 @@ proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
|
||||||
of nkNone..nkNilLit:
|
of nkNone..nkNilLit:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
|
if n.kind == nkRecCase and kind in {skProc, skConst}:
|
||||||
|
return n[0].typ
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
let it = n.sons[i]
|
let it = n.sons[i]
|
||||||
if it.kind == nkRecCase and kind in {skProc, skConst}:
|
|
||||||
return n.typ
|
|
||||||
result = typeAllowedNode(marker, it, kind, flags)
|
result = typeAllowedNode(marker, it, kind, flags)
|
||||||
if result != nil: break
|
if result != nil: break
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,10 +109,6 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
|
||||||
mapTypeToBracketX(name, m, t, info, inst)
|
mapTypeToBracketX(name, m, t, info, inst)
|
||||||
template newNodeX(kind): untyped =
|
template newNodeX(kind): untyped =
|
||||||
newNodeIT(kind, if t.n.isNil: info else: t.n.info, t)
|
newNodeIT(kind, if t.n.isNil: info else: t.n.info, t)
|
||||||
template newIdent(s): untyped =
|
|
||||||
var r = newNodeX(nkIdent)
|
|
||||||
r.add !s
|
|
||||||
r
|
|
||||||
template newIdentDefs(n,t): untyped =
|
template newIdentDefs(n,t): untyped =
|
||||||
var id = newNodeX(nkIdentDefs)
|
var id = newNodeX(nkIdentDefs)
|
||||||
id.add n # name
|
id.add n # name
|
||||||
|
|
|
||||||
|
|
@ -748,7 +748,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
||||||
let tmp = c.genx(arg)
|
let tmp = c.genx(arg)
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
c.gABC(n, opc, dest, tmp)
|
c.gABC(n, opc, dest, tmp)
|
||||||
c.gABx(n, opc, 0, genType(c, n.typ))
|
c.gABx(n, opc, 0, genType(c, n.typ.skipTypes({tyStatic})))
|
||||||
c.gABx(n, opc, 0, genType(c, arg.typ.skipTypes({tyStatic})))
|
c.gABx(n, opc, 0, genType(c, arg.typ.skipTypes({tyStatic})))
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
|
|
@ -1127,14 +1127,6 @@ proc fitsRegister*(t: PType): bool =
|
||||||
t.skipTypes(abstractInst-{tyTypeDesc}).kind in {
|
t.skipTypes(abstractInst-{tyTypeDesc}).kind in {
|
||||||
tyRange, tyEnum, tyBool, tyInt..tyUInt64, tyChar}
|
tyRange, tyEnum, tyBool, tyInt..tyUInt64, tyChar}
|
||||||
|
|
||||||
proc requiresCopy(n: PNode): bool =
|
|
||||||
if n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind in atomicTypes:
|
|
||||||
result = false
|
|
||||||
elif n.kind in ({nkCurly, nkBracket, nkPar, nkObjConstr}+nkCallKinds):
|
|
||||||
result = false
|
|
||||||
else:
|
|
||||||
result = true
|
|
||||||
|
|
||||||
proc unneededIndirection(n: PNode): bool =
|
proc unneededIndirection(n: PNode): bool =
|
||||||
n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind == tyRef
|
n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind == tyRef
|
||||||
|
|
||||||
|
|
@ -1215,8 +1207,6 @@ proc whichAsgnOpc(n: PNode): TOpcode =
|
||||||
else:
|
else:
|
||||||
opcAsgnComplex
|
opcAsgnComplex
|
||||||
|
|
||||||
proc isRef(t: PType): bool = t.skipTypes(abstractRange-{tyTypeDesc}).kind == tyRef
|
|
||||||
|
|
||||||
proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = opc
|
proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = opc
|
||||||
|
|
||||||
proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
|
proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
|
||||||
|
|
@ -1268,9 +1258,6 @@ proc isTemp(c: PCtx; dest: TDest): bool =
|
||||||
template needsAdditionalCopy(n): untyped =
|
template needsAdditionalCopy(n): untyped =
|
||||||
not c.isTemp(dest) and not fitsRegister(n.typ)
|
not c.isTemp(dest) and not fitsRegister(n.typ)
|
||||||
|
|
||||||
proc skipDeref(n: PNode): PNode =
|
|
||||||
result = if n.kind in {nkDerefExpr, nkHiddenDeref}: n.sons[0] else: n
|
|
||||||
|
|
||||||
proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
|
proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
|
||||||
dest, idx, value: TRegister) =
|
dest, idx, value: TRegister) =
|
||||||
# opcLdObj et al really means "load address". We sometimes have to create a
|
# opcLdObj et al really means "load address". We sometimes have to create a
|
||||||
|
|
@ -1848,7 +1835,6 @@ proc genParams(c: PCtx; params: PNode) =
|
||||||
# res.sym.position is already 0
|
# res.sym.position is already 0
|
||||||
c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
|
c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
|
||||||
for i in 1.. <params.len:
|
for i in 1.. <params.len:
|
||||||
let param = params.sons[i].sym
|
|
||||||
c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
|
c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
|
||||||
c.prc.maxSlots = max(params.len, 1)
|
c.prc.maxSlots = max(params.len, 1)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,20 @@ spelled*:
|
||||||
.. code-block::
|
.. code-block::
|
||||||
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
|
proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
|
||||||
|
|
||||||
Note that this pragma is somewhat of a misnomer: Other backends will provide
|
Note that this pragma is somewhat of a misnomer: Other backends do provide
|
||||||
the same feature under the same name. Also, if one is interfacing with C++
|
the same feature under the same name. Also, if one is interfacing with C++
|
||||||
the `ImportCpp pragma <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
|
the `ImportCpp pragma <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
|
||||||
interfacing with Objective-C the `ImportObjC pragma
|
interfacing with Objective-C the `ImportObjC pragma
|
||||||
<manual.html#implementation-specific-pragmas-importobjc-pragma>`_ can be used.
|
<manual.html#implementation-specific-pragmas-importobjc-pragma>`_ can be used.
|
||||||
|
|
||||||
|
The string literal passed to ``importc`` can be a format string:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
proc p(s: cstring) {.importc: "prefix$1".}
|
||||||
|
|
||||||
|
In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
|
||||||
|
is available and a literal dollar sign must be written as ``$$``.
|
||||||
|
|
||||||
|
|
||||||
Exportc pragma
|
Exportc pragma
|
||||||
--------------
|
--------------
|
||||||
|
|
@ -33,9 +41,19 @@ name is the Nim identifier *exactly as spelled*:
|
||||||
.. code-block:: Nim
|
.. code-block:: Nim
|
||||||
proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
|
proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
|
||||||
|
|
||||||
Note that this pragma is somewhat of a misnomer: Other backends will provide
|
Note that this pragma is somewhat of a misnomer: Other backends do provide
|
||||||
the same feature under the same name.
|
the same feature under the same name.
|
||||||
|
|
||||||
|
The string literal passed to ``exportc`` can be a format string:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
proc p(s: string) {.exportc: "prefix$1".} =
|
||||||
|
echo s
|
||||||
|
|
||||||
|
In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
|
||||||
|
is available and a literal dollar sign must be written as ``$$``.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Extern pragma
|
Extern pragma
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -46,7 +64,9 @@ mangling. The string literal passed to ``extern`` can be a format string:
|
||||||
proc p(s: string) {.extern: "prefix$1".} =
|
proc p(s: string) {.extern: "prefix$1".} =
|
||||||
echo s
|
echo s
|
||||||
|
|
||||||
In the example the external name of ``p`` is set to ``prefixp``.
|
In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
|
||||||
|
is available and a literal dollar sign must be written as ``$$``.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Bycopy pragma
|
Bycopy pragma
|
||||||
|
|
|
||||||
4
koch.nim
|
|
@ -244,11 +244,13 @@ proc boot(args: string) =
|
||||||
var finalDest = "bin" / "nim".exe
|
var finalDest = "bin" / "nim".exe
|
||||||
# default to use the 'c' command:
|
# default to use the 'c' command:
|
||||||
let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: ""
|
let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: ""
|
||||||
|
let smartNimcache = if "release" in args: "rnimcache" else: "dnimcache"
|
||||||
|
|
||||||
copyExe(findStartNim(), 0.thVersion)
|
copyExe(findStartNim(), 0.thVersion)
|
||||||
for i in 0..2:
|
for i in 0..2:
|
||||||
echo "iteration: ", i+1
|
echo "iteration: ", i+1
|
||||||
exec i.thVersion & " $# $# compiler" / "nim.nim" % [bootOptions, args]
|
exec i.thVersion & " $# $# --nimcache:$# compiler" / "nim.nim" % [bootOptions, args,
|
||||||
|
smartNimcache]
|
||||||
if sameFileContent(output, i.thVersion):
|
if sameFileContent(output, i.thVersion):
|
||||||
copyExe(output, finalDest)
|
copyExe(output, finalDest)
|
||||||
echo "executables are equal: SUCCESS!"
|
echo "executables are equal: SUCCESS!"
|
||||||
|
|
|
||||||
|
|
@ -333,7 +333,7 @@ proc parseStmt*(s: string): NimNode {.noSideEffect, compileTime.} =
|
||||||
let x = internalErrorFlag()
|
let x = internalErrorFlag()
|
||||||
if x.len > 0: raise newException(ValueError, x)
|
if x.len > 0: raise newException(ValueError, x)
|
||||||
|
|
||||||
proc getAst*(macroOrTemplate: expr): NimNode {.magic: "ExpandToAst", noSideEffect.}
|
proc getAst*(macroOrTemplate: untyped): NimNode {.magic: "ExpandToAst", noSideEffect.}
|
||||||
## Obtains the AST nodes returned from a macro or template invocation.
|
## Obtains the AST nodes returned from a macro or template invocation.
|
||||||
## Example:
|
## Example:
|
||||||
##
|
##
|
||||||
|
|
@ -342,7 +342,7 @@ proc getAst*(macroOrTemplate: expr): NimNode {.magic: "ExpandToAst", noSideEffec
|
||||||
## macro FooMacro() =
|
## macro FooMacro() =
|
||||||
## var ast = getAst(BarTemplate())
|
## var ast = getAst(BarTemplate())
|
||||||
|
|
||||||
proc quote*(bl: stmt, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.}
|
proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.}
|
||||||
## Quasi-quoting operator.
|
## Quasi-quoting operator.
|
||||||
## Accepts an expression or a block and returns the AST that represents it.
|
## Accepts an expression or a block and returns the AST that represents it.
|
||||||
## Within the quoted AST, you are able to interpolate NimNode expressions
|
## Within the quoted AST, you are able to interpolate NimNode expressions
|
||||||
|
|
@ -663,7 +663,7 @@ proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}=
|
||||||
for i in 0 .. < src.len:
|
for i in 0 .. < src.len:
|
||||||
dest.add src[i].copyNimTree
|
dest.add src[i].copyNimTree
|
||||||
|
|
||||||
template expectRoutine(node: NimNode): stmt =
|
template expectRoutine(node: NimNode) =
|
||||||
expectKind(node, RoutineNodes)
|
expectKind(node, RoutineNodes)
|
||||||
|
|
||||||
proc name*(someProc: NimNode): NimNode {.compileTime.} =
|
proc name*(someProc: NimNode): NimNode {.compileTime.} =
|
||||||
|
|
@ -870,7 +870,7 @@ proc hasArgOfName* (params: NimNode; name: string): bool {.compiletime.}=
|
||||||
## Search nnkFormalParams for an argument.
|
## Search nnkFormalParams for an argument.
|
||||||
assert params.kind == nnkFormalParams
|
assert params.kind == nnkFormalParams
|
||||||
for i in 1 .. <params.len:
|
for i in 1 .. <params.len:
|
||||||
template node: expr = params[i]
|
template node: untyped = params[i]
|
||||||
if name.eqIdent( $ node[0]):
|
if name.eqIdent( $ node[0]):
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
@ -891,7 +891,7 @@ proc boolVal*(n: NimNode): bool {.compileTime, noSideEffect.} =
|
||||||
else: n == bindSym"true" # hacky solution for now
|
else: n == bindSym"true" # hacky solution for now
|
||||||
|
|
||||||
when not defined(booting):
|
when not defined(booting):
|
||||||
template emit*(e: static[string]): stmt {.deprecated.} =
|
template emit*(e: static[string]): untyped {.deprecated.} =
|
||||||
## accepts a single string argument and treats it as nim code
|
## accepts a single string argument and treats it as nim code
|
||||||
## that should be inserted verbatim in the program
|
## that should be inserted verbatim in the program
|
||||||
## Example:
|
## Example:
|
||||||
|
|
@ -900,6 +900,6 @@ when not defined(booting):
|
||||||
## emit("echo " & '"' & "hello world".toUpper & '"')
|
## emit("echo " & '"' & "hello world".toUpper & '"')
|
||||||
##
|
##
|
||||||
## Deprecated since version 0.15 since it's so rarely useful.
|
## Deprecated since version 0.15 since it's so rarely useful.
|
||||||
macro payload: stmt {.gensym.} =
|
macro payload: untyped {.gensym.} =
|
||||||
result = parseStmt(e)
|
result = parseStmt(e)
|
||||||
payload()
|
payload()
|
||||||
|
|
|
||||||
|
|
@ -129,10 +129,10 @@ proc ftpClient*(address: string, port = Port(21),
|
||||||
result.csock = socket()
|
result.csock = socket()
|
||||||
if result.csock == invalidSocket: raiseOSError(osLastError())
|
if result.csock == invalidSocket: raiseOSError(osLastError())
|
||||||
|
|
||||||
template blockingOperation(sock: Socket, body: stmt) {.immediate.} =
|
template blockingOperation(sock: Socket, body: untyped) =
|
||||||
body
|
body
|
||||||
|
|
||||||
template blockingOperation(sock: asyncio.AsyncSocket, body: stmt) {.immediate.} =
|
template blockingOperation(sock: asyncio.AsyncSocket, body: untyped) =
|
||||||
sock.setBlocking(true)
|
sock.setBlocking(true)
|
||||||
body
|
body
|
||||||
sock.setBlocking(false)
|
sock.setBlocking(false)
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ template sortedByIt*(seq1, op: untyped): untyped =
|
||||||
##
|
##
|
||||||
## echo people.sortedByIt((it.age, it.name))
|
## echo people.sortedByIt((it.age, it.name))
|
||||||
##
|
##
|
||||||
var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int =
|
var result = sorted(seq1, proc(x, y: type(seq1[0])): int =
|
||||||
var it {.inject.} = x
|
var it {.inject.} = x
|
||||||
let a = op
|
let a = op
|
||||||
it = y
|
it = y
|
||||||
|
|
|
||||||
|
|
@ -371,7 +371,7 @@ template filterIt*(seq1, pred: untyped): untyped =
|
||||||
## notAcceptable = filterIt(temperatures, it > 50 or it < -10)
|
## notAcceptable = filterIt(temperatures, it > 50 or it < -10)
|
||||||
## assert acceptable == @[-2.0, 24.5, 44.31]
|
## assert acceptable == @[-2.0, 24.5, 44.31]
|
||||||
## assert notAcceptable == @[-272.15, 99.9, -113.44]
|
## assert notAcceptable == @[-272.15, 99.9, -113.44]
|
||||||
var result {.gensym.} = newSeq[type(seq1[0])]()
|
var result = newSeq[type(seq1[0])]()
|
||||||
for it {.inject.} in items(seq1):
|
for it {.inject.} in items(seq1):
|
||||||
if pred: result.add(it)
|
if pred: result.add(it)
|
||||||
result
|
result
|
||||||
|
|
@ -420,7 +420,7 @@ template allIt*(seq1, pred: untyped): bool =
|
||||||
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||||
## assert allIt(numbers, it < 10) == true
|
## assert allIt(numbers, it < 10) == true
|
||||||
## assert allIt(numbers, it < 9) == false
|
## assert allIt(numbers, it < 9) == false
|
||||||
var result {.gensym.} = true
|
var result = true
|
||||||
for it {.inject.} in items(seq1):
|
for it {.inject.} in items(seq1):
|
||||||
if not pred:
|
if not pred:
|
||||||
result = false
|
result = false
|
||||||
|
|
@ -451,7 +451,7 @@ template anyIt*(seq1, pred: untyped): bool =
|
||||||
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
## let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||||
## assert anyIt(numbers, it > 8) == true
|
## assert anyIt(numbers, it > 8) == true
|
||||||
## assert anyIt(numbers, it > 9) == false
|
## assert anyIt(numbers, it > 9) == false
|
||||||
var result {.gensym.} = false
|
var result = false
|
||||||
for it {.inject.} in items(seq1):
|
for it {.inject.} in items(seq1):
|
||||||
if pred:
|
if pred:
|
||||||
result = true
|
result = true
|
||||||
|
|
@ -512,7 +512,7 @@ template foldl*(sequence, operation: untyped): untyped =
|
||||||
## assert concatenation == "nimiscool"
|
## assert concatenation == "nimiscool"
|
||||||
let s = sequence
|
let s = sequence
|
||||||
assert s.len > 0, "Can't fold empty sequences"
|
assert s.len > 0, "Can't fold empty sequences"
|
||||||
var result {.gensym.}: type(s[0])
|
var result: type(s[0])
|
||||||
result = s[0]
|
result = s[0]
|
||||||
for i in 1..<s.len:
|
for i in 1..<s.len:
|
||||||
let
|
let
|
||||||
|
|
@ -537,7 +537,7 @@ template foldl*(sequence, operation, first): untyped =
|
||||||
## numbers = @[0, 8, 1, 5]
|
## numbers = @[0, 8, 1, 5]
|
||||||
## digits = foldl(numbers, a & (chr(b + ord('0'))), "")
|
## digits = foldl(numbers, a & (chr(b + ord('0'))), "")
|
||||||
## assert digits == "0815"
|
## assert digits == "0815"
|
||||||
var result {.gensym.}: type(first)
|
var result: type(first)
|
||||||
result = first
|
result = first
|
||||||
for x in items(sequence):
|
for x in items(sequence):
|
||||||
let
|
let
|
||||||
|
|
@ -574,7 +574,7 @@ template foldr*(sequence, operation: untyped): untyped =
|
||||||
## assert concatenation == "nimiscool"
|
## assert concatenation == "nimiscool"
|
||||||
let s = sequence
|
let s = sequence
|
||||||
assert s.len > 0, "Can't fold empty sequences"
|
assert s.len > 0, "Can't fold empty sequences"
|
||||||
var result {.gensym.}: type(s[0])
|
var result: type(s[0])
|
||||||
result = sequence[s.len - 1]
|
result = sequence[s.len - 1]
|
||||||
for i in countdown(s.len - 2, 0):
|
for i in countdown(s.len - 2, 0):
|
||||||
let
|
let
|
||||||
|
|
@ -598,7 +598,7 @@ template mapIt*(seq1, typ, op: untyped): untyped =
|
||||||
## assert strings == @["4", "8", "12", "16"]
|
## assert strings == @["4", "8", "12", "16"]
|
||||||
## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
|
## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
|
||||||
## template instead.
|
## template instead.
|
||||||
var result {.gensym.}: seq[typ] = @[]
|
var result: seq[typ] = @[]
|
||||||
for it {.inject.} in items(seq1):
|
for it {.inject.} in items(seq1):
|
||||||
result.add(op)
|
result.add(op)
|
||||||
result
|
result
|
||||||
|
|
@ -662,7 +662,7 @@ template newSeqWith*(len: int, init: untyped): untyped =
|
||||||
## import random
|
## import random
|
||||||
## var seqRand = newSeqWith(20, random(10))
|
## var seqRand = newSeqWith(20, random(10))
|
||||||
## echo seqRand
|
## echo seqRand
|
||||||
var result {.gensym.} = newSeq[type(init)](len)
|
var result = newSeq[type(init)](len)
|
||||||
for i in 0 .. <len:
|
for i in 0 .. <len:
|
||||||
result[i] = init
|
result[i] = init
|
||||||
result
|
result
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,8 @@ template delImpl() {.dirty.} =
|
||||||
|
|
||||||
template clearImpl() {.dirty.} =
|
template clearImpl() {.dirty.} =
|
||||||
for i in 0 .. <t.data.len:
|
for i in 0 .. <t.data.len:
|
||||||
t.data[i].hcode = 0
|
when compiles(t.data[i].hcode): # CountTable records don't contain a hcode
|
||||||
|
t.data[i].hcode = 0
|
||||||
t.data[i].key = default(type(t.data[i].key))
|
t.data[i].key = default(type(t.data[i].key))
|
||||||
t.data[i].val = default(type(t.data[i].val))
|
t.data[i].val = default(type(t.data[i].val))
|
||||||
t.counter = 0
|
t.counter = 0
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ template dataLen(t): untyped = len(t.data)
|
||||||
|
|
||||||
include tableimpl
|
include tableimpl
|
||||||
|
|
||||||
proc clear*[A, B](t: Table[A, B] | TableRef[A, B]) =
|
proc clear*[A, B](t: var Table[A, B] | TableRef[A, B]) =
|
||||||
## Resets the table so that it is empty.
|
## Resets the table so that it is empty.
|
||||||
clearImpl()
|
clearImpl()
|
||||||
|
|
||||||
|
|
@ -457,7 +457,7 @@ proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
proc clear*[A, B](t: OrderedTable[A, B] | OrderedTableRef[A, B]) =
|
proc clear*[A, B](t: var OrderedTable[A, B] | OrderedTableRef[A, B]) =
|
||||||
## Resets the table so that it is empty.
|
## Resets the table so that it is empty.
|
||||||
clearImpl()
|
clearImpl()
|
||||||
t.first = -1
|
t.first = -1
|
||||||
|
|
@ -786,7 +786,7 @@ proc len*[A](t: CountTable[A]): int =
|
||||||
## returns the number of keys in `t`.
|
## returns the number of keys in `t`.
|
||||||
result = t.counter
|
result = t.counter
|
||||||
|
|
||||||
proc clear*[A](t: CountTable[A] | CountTableRef[A]) =
|
proc clear*[A](t: var CountTable[A] | CountTableRef[A]) =
|
||||||
## Resets the table so that it is empty.
|
## Resets the table so that it is empty.
|
||||||
clearImpl()
|
clearImpl()
|
||||||
t.counter = 0
|
t.counter = 0
|
||||||
|
|
|
||||||
|
|
@ -297,9 +297,20 @@ var
|
||||||
gSomeReady : Semaphore
|
gSomeReady : Semaphore
|
||||||
readyWorker: ptr Worker
|
readyWorker: ptr Worker
|
||||||
|
|
||||||
|
# A workaround for recursion deadlock issue
|
||||||
|
# https://github.com/nim-lang/Nim/issues/4597
|
||||||
|
var
|
||||||
|
numSlavesLock: Lock
|
||||||
|
numSlavesRunning {.guard: numSlavesLock}: int
|
||||||
|
numSlavesWaiting {.guard: numSlavesLock}: int
|
||||||
|
isSlave {.threadvar.}: bool
|
||||||
|
|
||||||
|
numSlavesLock.initLock
|
||||||
|
|
||||||
gSomeReady.initSemaphore()
|
gSomeReady.initSemaphore()
|
||||||
|
|
||||||
proc slave(w: ptr Worker) {.thread.} =
|
proc slave(w: ptr Worker) {.thread.} =
|
||||||
|
isSlave = true
|
||||||
while true:
|
while true:
|
||||||
when declared(atomicStoreN):
|
when declared(atomicStoreN):
|
||||||
atomicStoreN(addr(w.ready), true, ATOMIC_SEQ_CST)
|
atomicStoreN(addr(w.ready), true, ATOMIC_SEQ_CST)
|
||||||
|
|
@ -311,7 +322,15 @@ proc slave(w: ptr Worker) {.thread.} =
|
||||||
# XXX Somebody needs to look into this (why does this assertion fail
|
# XXX Somebody needs to look into this (why does this assertion fail
|
||||||
# in Visual Studio?)
|
# in Visual Studio?)
|
||||||
when not defined(vcc): assert(not w.ready)
|
when not defined(vcc): assert(not w.ready)
|
||||||
|
|
||||||
|
withLock numSlavesLock:
|
||||||
|
inc numSlavesRunning
|
||||||
|
|
||||||
w.f(w, w.data)
|
w.f(w, w.data)
|
||||||
|
|
||||||
|
withLock numSlavesLock:
|
||||||
|
dec numSlavesRunning
|
||||||
|
|
||||||
if w.q.len != 0: w.cleanFlowVars
|
if w.q.len != 0: w.cleanFlowVars
|
||||||
if w.shutdown:
|
if w.shutdown:
|
||||||
w.shutdown = false
|
w.shutdown = false
|
||||||
|
|
@ -464,10 +483,34 @@ proc nimSpawn3(fn: WorkerProc; data: pointer) {.compilerProc.} =
|
||||||
fn(self, data)
|
fn(self, data)
|
||||||
await(self.taskStarted)
|
await(self.taskStarted)
|
||||||
return
|
return
|
||||||
else:
|
|
||||||
await(gSomeReady)
|
if isSlave:
|
||||||
else:
|
# Run under lock until `numSlavesWaiting` increment to avoid a
|
||||||
await(gSomeReady)
|
# race (otherwise two last threads might start waiting together)
|
||||||
|
withLock numSlavesLock:
|
||||||
|
if numSlavesRunning <= numSlavesWaiting + 1:
|
||||||
|
# All the other slaves are waiting
|
||||||
|
# If we wait now, we-re deadlocked until
|
||||||
|
# an external spawn happens !
|
||||||
|
if currentPoolSize < maxPoolSize:
|
||||||
|
if not workersData[currentPoolSize].initialized:
|
||||||
|
activateWorkerThread(currentPoolSize)
|
||||||
|
let w = addr(workersData[currentPoolSize])
|
||||||
|
atomicInc currentPoolSize
|
||||||
|
if selectWorker(w, fn, data):
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# There is no place in the pool. We're deadlocked.
|
||||||
|
# echo "Deadlock!"
|
||||||
|
discard
|
||||||
|
|
||||||
|
inc numSlavesWaiting
|
||||||
|
|
||||||
|
await(gSomeReady)
|
||||||
|
|
||||||
|
if isSlave:
|
||||||
|
withLock numSlavesLock:
|
||||||
|
dec numSlavesWaiting
|
||||||
|
|
||||||
var
|
var
|
||||||
distinguishedLock: Lock
|
distinguishedLock: Lock
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,10 @@ const
|
||||||
MAX_KQUEUE_CHANGE_EVENTS = 64
|
MAX_KQUEUE_CHANGE_EVENTS = 64
|
||||||
# Maximum number of events that can be returned.
|
# Maximum number of events that can be returned.
|
||||||
MAX_KQUEUE_RESULT_EVENTS = 64
|
MAX_KQUEUE_RESULT_EVENTS = 64
|
||||||
|
# SIG_IGN and SIG_DFL declared in posix.nim as variables, but we need them
|
||||||
|
# to be constants and GC-safe.
|
||||||
|
SIG_DFL = cast[proc(x: cint) {.noconv,gcsafe.}](0)
|
||||||
|
SIG_IGN = cast[proc(x: cint) {.noconv,gcsafe.}](1)
|
||||||
|
|
||||||
when defined(macosx) or defined(freebsd):
|
when defined(macosx) or defined(freebsd):
|
||||||
when defined(macosx):
|
when defined(macosx):
|
||||||
|
|
|
||||||
|
|
@ -580,7 +580,7 @@ type
|
||||||
of JNull:
|
of JNull:
|
||||||
nil
|
nil
|
||||||
of JObject:
|
of JObject:
|
||||||
fields*: Table[string, JsonNode]
|
fields*: OrderedTable[string, JsonNode]
|
||||||
of JArray:
|
of JArray:
|
||||||
elems*: seq[JsonNode]
|
elems*: seq[JsonNode]
|
||||||
|
|
||||||
|
|
@ -630,7 +630,7 @@ proc newJObject*(): JsonNode =
|
||||||
## Creates a new `JObject JsonNode`
|
## Creates a new `JObject JsonNode`
|
||||||
new(result)
|
new(result)
|
||||||
result.kind = JObject
|
result.kind = JObject
|
||||||
result.fields = initTable[string, JsonNode](4)
|
result.fields = initOrderedTable[string, JsonNode](4)
|
||||||
|
|
||||||
proc newJArray*(): JsonNode =
|
proc newJArray*(): JsonNode =
|
||||||
## Creates a new `JArray JsonNode`
|
## Creates a new `JArray JsonNode`
|
||||||
|
|
@ -670,8 +670,8 @@ proc getBVal*(n: JsonNode, default: bool = false): bool =
|
||||||
else: return n.bval
|
else: return n.bval
|
||||||
|
|
||||||
proc getFields*(n: JsonNode,
|
proc getFields*(n: JsonNode,
|
||||||
default = initTable[string, JsonNode](4)):
|
default = initOrderedTable[string, JsonNode](4)):
|
||||||
Table[string, JsonNode] =
|
OrderedTable[string, JsonNode] =
|
||||||
## Retrieves the key, value pairs of a `JObject JsonNode`.
|
## Retrieves the key, value pairs of a `JObject JsonNode`.
|
||||||
##
|
##
|
||||||
## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil.
|
## Returns ``default`` if ``n`` is not a ``JObject``, or if ``n`` is nil.
|
||||||
|
|
@ -760,12 +760,12 @@ proc toJson(x: NimNode): NimNode {.compiletime.} =
|
||||||
|
|
||||||
result = prefix(result, "%")
|
result = prefix(result, "%")
|
||||||
|
|
||||||
macro `%*`*(x: expr): expr =
|
macro `%*`*(x: untyped): untyped =
|
||||||
## Convert an expression to a JsonNode directly, without having to specify
|
## Convert an expression to a JsonNode directly, without having to specify
|
||||||
## `%` for every element.
|
## `%` for every element.
|
||||||
result = toJson(x)
|
result = toJson(x)
|
||||||
|
|
||||||
proc `==`* (a,b: JsonNode): bool =
|
proc `==`* (a, b: JsonNode): bool =
|
||||||
## Check two nodes for equality
|
## Check two nodes for equality
|
||||||
if a.isNil:
|
if a.isNil:
|
||||||
if b.isNil: return true
|
if b.isNil: return true
|
||||||
|
|
@ -773,23 +773,29 @@ proc `==`* (a,b: JsonNode): bool =
|
||||||
elif b.isNil or a.kind != b.kind:
|
elif b.isNil or a.kind != b.kind:
|
||||||
return false
|
return false
|
||||||
else:
|
else:
|
||||||
return case a.kind
|
case a.kind
|
||||||
of JString:
|
of JString:
|
||||||
a.str == b.str
|
result = a.str == b.str
|
||||||
of JInt:
|
of JInt:
|
||||||
a.num == b.num
|
result = a.num == b.num
|
||||||
of JFloat:
|
of JFloat:
|
||||||
a.fnum == b.fnum
|
result = a.fnum == b.fnum
|
||||||
of JBool:
|
of JBool:
|
||||||
a.bval == b.bval
|
result = a.bval == b.bval
|
||||||
of JNull:
|
of JNull:
|
||||||
true
|
result = true
|
||||||
of JArray:
|
of JArray:
|
||||||
a.elems == b.elems
|
result = a.elems == b.elems
|
||||||
of JObject:
|
of JObject:
|
||||||
a.fields == b.fields
|
# we cannot use OrderedTable's equality here as
|
||||||
|
# the order does not matter for equality here.
|
||||||
|
if a.fields.len != b.fields.len: return false
|
||||||
|
for key, val in a.fields:
|
||||||
|
if not b.fields.hasKey(key): return false
|
||||||
|
if b.fields[key] != val: return false
|
||||||
|
result = true
|
||||||
|
|
||||||
proc hash*(n: Table[string, JsonNode]): Hash {.noSideEffect.}
|
proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
|
||||||
|
|
||||||
proc hash*(n: JsonNode): Hash =
|
proc hash*(n: JsonNode): Hash =
|
||||||
## Compute the hash for a JSON node
|
## Compute the hash for a JSON node
|
||||||
|
|
@ -807,9 +813,9 @@ proc hash*(n: JsonNode): Hash =
|
||||||
of JString:
|
of JString:
|
||||||
result = hash(n.str)
|
result = hash(n.str)
|
||||||
of JNull:
|
of JNull:
|
||||||
result = hash(0)
|
result = Hash(0)
|
||||||
|
|
||||||
proc hash*(n: Table[string, JsonNode]): Hash =
|
proc hash*(n: OrderedTable[string, JsonNode]): Hash =
|
||||||
for key, val in n:
|
for key, val in n:
|
||||||
result = result xor (hash(key) !& hash(val))
|
result = result xor (hash(key) !& hash(val))
|
||||||
result = !$result
|
result = !$result
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,10 @@ proc newSocket*(fd: SocketHandle, domain: Domain = AF_INET,
|
||||||
if buffered:
|
if buffered:
|
||||||
result.currPos = 0
|
result.currPos = 0
|
||||||
|
|
||||||
|
# Set SO_NOSIGPIPE on OS X.
|
||||||
|
when defined(macosx):
|
||||||
|
setSockOptInt(fd, SOL_SOCKET, SO_NOSIGPIPE, 1)
|
||||||
|
|
||||||
proc newSocket*(domain, sockType, protocol: cint, buffered = true): Socket =
|
proc newSocket*(domain, sockType, protocol: cint, buffered = true): Socket =
|
||||||
## Creates a new socket.
|
## Creates a new socket.
|
||||||
##
|
##
|
||||||
|
|
@ -342,8 +346,6 @@ when defineSsl:
|
||||||
result = SSLContext(context: newCTX, extraInternalIndex: 0,
|
result = SSLContext(context: newCTX, extraInternalIndex: 0,
|
||||||
referencedData: initSet[int]())
|
referencedData: initSet[int]())
|
||||||
result.extraInternalIndex = getExtraDataIndex(result)
|
result.extraInternalIndex = getExtraDataIndex(result)
|
||||||
# The PSK callback functions assume the internal index is 0.
|
|
||||||
assert result.extraInternalIndex == 0
|
|
||||||
|
|
||||||
let extraInternal = new(SslContextExtraInternal)
|
let extraInternal = new(SslContextExtraInternal)
|
||||||
result.setExtraData(result.extraInternalIndex, extraInternal)
|
result.setExtraData(result.extraInternalIndex, extraInternal)
|
||||||
|
|
@ -392,6 +394,8 @@ when defineSsl:
|
||||||
##
|
##
|
||||||
## Only used in PSK ciphersuites.
|
## Only used in PSK ciphersuites.
|
||||||
ctx.getExtraInternal().clientGetPskFunc = fun
|
ctx.getExtraInternal().clientGetPskFunc = fun
|
||||||
|
assert ctx.extraInternalIndex == 0,
|
||||||
|
"The pskClientCallback assumes the extraInternalIndex is 0"
|
||||||
ctx.context.SSL_CTX_set_psk_client_callback(
|
ctx.context.SSL_CTX_set_psk_client_callback(
|
||||||
if fun == nil: nil else: pskClientCallback)
|
if fun == nil: nil else: pskClientCallback)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,7 @@ proc genOid*(): Oid =
|
||||||
|
|
||||||
var t = gettime(nil)
|
var t = gettime(nil)
|
||||||
|
|
||||||
var i = int32(incr)
|
var i = int32(atomicInc(incr))
|
||||||
atomicInc(incr)
|
|
||||||
|
|
||||||
if fuzz == 0:
|
if fuzz == 0:
|
||||||
# racy, but fine semantically:
|
# racy, but fine semantically:
|
||||||
|
|
|
||||||
|
|
@ -1248,8 +1248,11 @@ proc parse*(value, layout: string): TimeInfo =
|
||||||
else:
|
else:
|
||||||
parseToken(info, token, value, j)
|
parseToken(info, token, value, j)
|
||||||
token = ""
|
token = ""
|
||||||
# Reset weekday as it might not have been provided and the default may be wrong
|
# Reset weekday (might not have been provided and the default may be wrong)
|
||||||
info.weekday = getLocalTime(toTime(info)).weekday
|
# and yearday (is never provided directly and therefore probably wrong)
|
||||||
|
let processed = getLocalTime(toTime(info))
|
||||||
|
info.weekday = processed.weekday
|
||||||
|
info.yearday = processed.yearday
|
||||||
return info
|
return info
|
||||||
|
|
||||||
# Leap year calculations are adapted from:
|
# Leap year calculations are adapted from:
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ proc `<=%`*(a, b: Rune): bool = return int(a) <=% int(b)
|
||||||
proc `<%`*(a, b: Rune): bool = return int(a) <% int(b)
|
proc `<%`*(a, b: Rune): bool = return int(a) <% int(b)
|
||||||
proc `==`*(a, b: Rune): bool = return int(a) == int(b)
|
proc `==`*(a, b: Rune): bool = return int(a) == int(b)
|
||||||
|
|
||||||
template ones(n: expr): expr = ((1 shl n)-1)
|
template ones(n: untyped): untyped = ((1 shl n)-1)
|
||||||
|
|
||||||
proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
|
proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
|
||||||
## Returns the number of Unicode characters of the string ``s``
|
## Returns the number of Unicode characters of the string ``s``
|
||||||
|
|
@ -49,7 +49,7 @@ proc runeLenAt*(s: string, i: Natural): int =
|
||||||
elif ord(s[i]) shr 1 == 0b1111110: result = 6
|
elif ord(s[i]) shr 1 == 0b1111110: result = 6
|
||||||
else: result = 1
|
else: result = 1
|
||||||
|
|
||||||
template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
|
template fastRuneAt*(s: string, i: int, result: untyped, doInc = true) =
|
||||||
## Returns the Unicode character ``s[i]`` in ``result``. If ``doInc == true``
|
## Returns the Unicode character ``s[i]`` in ``result``. If ``doInc == true``
|
||||||
## ``i`` is incremented by the number of bytes that have been processed.
|
## ``i`` is incremented by the number of bytes that have been processed.
|
||||||
bind ones
|
bind ones
|
||||||
|
|
@ -1628,7 +1628,7 @@ proc reversed*(s: string): string =
|
||||||
blockPos = 0
|
blockPos = 0
|
||||||
r: Rune
|
r: Rune
|
||||||
|
|
||||||
template reverseUntil(pos): stmt =
|
template reverseUntil(pos) =
|
||||||
var j = pos - 1
|
var j = pos - 1
|
||||||
while j > blockPos:
|
while j > blockPos:
|
||||||
result[newPos] = s[j]
|
result[newPos] = s[j]
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,15 @@ checkpoints = @[]
|
||||||
proc shouldRun(testName: string): bool =
|
proc shouldRun(testName: string): bool =
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
proc startSuite(name: string) =
|
||||||
|
template rawPrint() = echo("\n[Suite] ", name)
|
||||||
|
when not defined(ECMAScript):
|
||||||
|
if colorOutput:
|
||||||
|
styledEcho styleBright, fgBlue, "\n[Suite] ", fgWhite, name
|
||||||
|
else: rawPrint()
|
||||||
|
else: rawPrint()
|
||||||
|
|
||||||
|
|
||||||
template suite*(name, body) {.dirty.} =
|
template suite*(name, body) {.dirty.} =
|
||||||
## Declare a test suite identified by `name` with optional ``setup``
|
## Declare a test suite identified by `name` with optional ``setup``
|
||||||
## and/or ``teardown`` section.
|
## and/or ``teardown`` section.
|
||||||
|
|
@ -103,9 +112,11 @@ template suite*(name, body) {.dirty.} =
|
||||||
##
|
##
|
||||||
## .. code-block::
|
## .. code-block::
|
||||||
##
|
##
|
||||||
## [OK] 2 + 2 = 4
|
## [Suite] test suite for addition
|
||||||
## [OK] (2 + -2) != 4
|
## [OK] 2 + 2 = 4
|
||||||
|
## [OK] (2 + -2) != 4
|
||||||
block:
|
block:
|
||||||
|
bind startSuite
|
||||||
template setup(setupBody: untyped) {.dirty.} =
|
template setup(setupBody: untyped) {.dirty.} =
|
||||||
var testSetupIMPLFlag = true
|
var testSetupIMPLFlag = true
|
||||||
template testSetupIMPL: untyped {.dirty.} = setupBody
|
template testSetupIMPL: untyped {.dirty.} = setupBody
|
||||||
|
|
@ -114,14 +125,16 @@ template suite*(name, body) {.dirty.} =
|
||||||
var testTeardownIMPLFlag = true
|
var testTeardownIMPLFlag = true
|
||||||
template testTeardownIMPL: untyped {.dirty.} = teardownBody
|
template testTeardownIMPL: untyped {.dirty.} = teardownBody
|
||||||
|
|
||||||
|
let testInSuiteImplFlag = true
|
||||||
|
startSuite name
|
||||||
body
|
body
|
||||||
|
|
||||||
proc testDone(name: string, s: TestStatus) =
|
proc testDone(name: string, s: TestStatus, indent: bool) =
|
||||||
if s == FAILED:
|
if s == FAILED:
|
||||||
programResult += 1
|
programResult += 1
|
||||||
|
let prefix = if indent: " " else: ""
|
||||||
if outputLevel != PRINT_NONE and (outputLevel == PRINT_ALL or s == FAILED):
|
if outputLevel != PRINT_NONE and (outputLevel == PRINT_ALL or s == FAILED):
|
||||||
template rawPrint() = echo("[", $s, "] ", name)
|
template rawPrint() = echo(prefix, "[", $s, "] ", name)
|
||||||
when not defined(ECMAScript):
|
when not defined(ECMAScript):
|
||||||
if colorOutput and not defined(ECMAScript):
|
if colorOutput and not defined(ECMAScript):
|
||||||
var color = case s
|
var color = case s
|
||||||
|
|
@ -129,7 +142,7 @@ proc testDone(name: string, s: TestStatus) =
|
||||||
of FAILED: fgRed
|
of FAILED: fgRed
|
||||||
of SKIPPED: fgYellow
|
of SKIPPED: fgYellow
|
||||||
else: fgWhite
|
else: fgWhite
|
||||||
styledEcho styleBright, color, "[", $s, "] ", fgWhite, name
|
styledEcho styleBright, color, prefix, "[", $s, "] ", fgWhite, name
|
||||||
else:
|
else:
|
||||||
rawPrint()
|
rawPrint()
|
||||||
else:
|
else:
|
||||||
|
|
@ -168,7 +181,7 @@ template test*(name, body) {.dirty.} =
|
||||||
fail()
|
fail()
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
testDone name, testStatusIMPL
|
testDone name, testStatusIMPL, declared(testInSuiteImplFlag)
|
||||||
|
|
||||||
proc checkpoint*(msg: string) =
|
proc checkpoint*(msg: string) =
|
||||||
## Set a checkpoint identified by `msg`. Upon test failure all
|
## Set a checkpoint identified by `msg`. Upon test failure all
|
||||||
|
|
@ -198,8 +211,9 @@ template fail* =
|
||||||
##
|
##
|
||||||
## outputs "Checkpoint A" before quitting.
|
## outputs "Checkpoint A" before quitting.
|
||||||
bind checkpoints
|
bind checkpoints
|
||||||
|
let prefix = if declared(testInSuiteImplFlag): " " else: ""
|
||||||
for msg in items(checkpoints):
|
for msg in items(checkpoints):
|
||||||
echo msg
|
echo prefix, msg
|
||||||
|
|
||||||
when not defined(ECMAScript):
|
when not defined(ECMAScript):
|
||||||
if abortOnError: quit(1)
|
if abortOnError: quit(1)
|
||||||
|
|
|
||||||
|
|
@ -3229,7 +3229,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] =
|
||||||
when low(a) < 0:
|
when low(a) < 0:
|
||||||
{.error: "Slicing for arrays with negative indices is unsupported.".}
|
{.error: "Slicing for arrays with negative indices is unsupported.".}
|
||||||
var L = x.b - x.a + 1
|
var L = x.b - x.a + 1
|
||||||
newSeq(result, L)
|
result = newSeq[T](L)
|
||||||
for i in 0.. <L: result[i] = a[i + x.a]
|
for i in 0.. <L: result[i] = a[i + x.a]
|
||||||
|
|
||||||
proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) =
|
proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) =
|
||||||
|
|
|
||||||
|
|
@ -1233,7 +1233,7 @@ when defined(windows) or defined(nimdoc):
|
||||||
|
|
||||||
registerWaitableHandle(p, hProcess, flags, pcd, proccb)
|
registerWaitableHandle(p, hProcess, flags, pcd, proccb)
|
||||||
|
|
||||||
proc newEvent*(): AsyncEvent =
|
proc newAsyncEvent*(): AsyncEvent =
|
||||||
## Creates new ``AsyncEvent`` object.
|
## Creates new ``AsyncEvent`` object.
|
||||||
var sa = SECURITY_ATTRIBUTES(
|
var sa = SECURITY_ATTRIBUTES(
|
||||||
nLength: sizeof(SECURITY_ATTRIBUTES).cint,
|
nLength: sizeof(SECURITY_ATTRIBUTES).cint,
|
||||||
|
|
@ -1314,7 +1314,7 @@ else:
|
||||||
readCB: Callback
|
readCB: Callback
|
||||||
writeCB: Callback
|
writeCB: Callback
|
||||||
|
|
||||||
AsyncEvent = SelectEvent
|
AsyncEvent* = SelectEvent
|
||||||
|
|
||||||
PDispatcher* = ref object of PDispatcherBase
|
PDispatcher* = ref object of PDispatcherBase
|
||||||
selector: Selector[AsyncData]
|
selector: Selector[AsyncData]
|
||||||
|
|
@ -1686,11 +1686,11 @@ else:
|
||||||
|
|
||||||
proc setEvent*(ev: AsyncEvent) =
|
proc setEvent*(ev: AsyncEvent) =
|
||||||
## Sets new ``AsyncEvent`` to signaled state.
|
## Sets new ``AsyncEvent`` to signaled state.
|
||||||
setEvent(SelectEvent(ev))
|
ioselectors.setEvent(SelectEvent(ev))
|
||||||
|
|
||||||
proc close*(ev: AsyncEvent) =
|
proc close*(ev: AsyncEvent) =
|
||||||
## Closes ``AsyncEvent``
|
## Closes ``AsyncEvent``
|
||||||
close(SelectEvent(ev))
|
ioselectors.close(SelectEvent(ev))
|
||||||
|
|
||||||
proc addEvent*(ev: AsyncEvent, cb: Callback) =
|
proc addEvent*(ev: AsyncEvent, cb: Callback) =
|
||||||
## Start watching for event ``ev``, and call callback ``cb``, when
|
## Start watching for event ``ev``, and call callback ``cb``, when
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ discard """
|
||||||
errormsg: "invalid context for '^' as 'foo()' has side effects"
|
errormsg: "invalid context for '^' as 'foo()' has side effects"
|
||||||
line: "9"
|
line: "9"
|
||||||
"""
|
"""
|
||||||
|
# XXX This needs to be fixed properly!
|
||||||
proc foo(): seq[int] =
|
proc foo(): seq[int] {.sideEffect.} =
|
||||||
echo "ha"
|
echo "ha"
|
||||||
|
|
||||||
let f = foo()[^1]
|
let f = foo()[^1]
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ when not defined(windows):
|
||||||
var rc2 = selector.select(100)
|
var rc2 = selector.select(100)
|
||||||
assert(len(rc2) == 1)
|
assert(len(rc2) == 1)
|
||||||
|
|
||||||
var read_count = posix.recv(server2_socket, addr (buffer[0]), 128, 0)
|
var read_count = posix.recv(server2_socket, addr buffer[0], 128, 0)
|
||||||
if read_count == -1:
|
if read_count == -1:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
|
|
@ -233,7 +233,7 @@ when not defined(windows):
|
||||||
|
|
||||||
proc mt_event_test(): bool =
|
proc mt_event_test(): bool =
|
||||||
var
|
var
|
||||||
thr: array [0..7, Thread[SelectEvent]]
|
thr: array[0..7, Thread[SelectEvent]]
|
||||||
var selector = newSelector[int]()
|
var selector = newSelector[int]()
|
||||||
var sock = newNativeSocket()
|
var sock = newNativeSocket()
|
||||||
var event = newSelectEvent()
|
var event = newSelectEvent()
|
||||||
|
|
@ -317,7 +317,7 @@ else:
|
||||||
var rc2 = selector.select(100)
|
var rc2 = selector.select(100)
|
||||||
assert(len(rc2) == 1)
|
assert(len(rc2) == 1)
|
||||||
|
|
||||||
var read_count = recv(server2_socket, addr (buffer[0]), 128, 0)
|
var read_count = recv(server2_socket, addr buffer[0], 128, 0)
|
||||||
if read_count == -1:
|
if read_count == -1:
|
||||||
raiseOSError(osLastError())
|
raiseOSError(osLastError())
|
||||||
|
|
||||||
|
|
@ -391,7 +391,7 @@ else:
|
||||||
assert(selector.isEmpty())
|
assert(selector.isEmpty())
|
||||||
|
|
||||||
proc mt_event_test(): bool =
|
proc mt_event_test(): bool =
|
||||||
var thr: array [0..7, Thread[SelectEvent]]
|
var thr: array[0..7, Thread[SelectEvent]]
|
||||||
var event = newSelectEvent()
|
var event = newSelectEvent()
|
||||||
for i in 0..high(thr):
|
for i in 0..high(thr):
|
||||||
createThread(thr[i], event_wait_thread, event)
|
createThread(thr[i], event_wait_thread, event)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
discard """
|
discard """
|
||||||
line: 18
|
line: 18
|
||||||
errormsg: "type mismatch: got (proc (s: TScgi) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.gcsafe, locks: 0.}"
|
errormsg: "type mismatch: got (proc (s: TScgi) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.noSideEffect, gcsafe, locks: 0.}"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#bug #442
|
#bug #442
|
||||||
|
|
|
||||||
26
tests/ccgbugs/twrong_rc_for_refarray.nim
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
discard """
|
||||||
|
output: '''m[0][0] = 1.0
|
||||||
|
m[0][0] = 2.0'''
|
||||||
|
"""
|
||||||
|
# bug #4653
|
||||||
|
type
|
||||||
|
Vector = ref array[2, float64]
|
||||||
|
Matrix = ref array[2, Vector]
|
||||||
|
|
||||||
|
proc newVector(): Vector =
|
||||||
|
new(result)
|
||||||
|
|
||||||
|
proc newMatrix(): Matrix =
|
||||||
|
new(result)
|
||||||
|
for ix in 0 .. 1:
|
||||||
|
result[ix] = newVector()
|
||||||
|
|
||||||
|
let m = newMatrix()
|
||||||
|
|
||||||
|
m[0][0] = 1.0
|
||||||
|
echo "m[0][0] = ", m[0][0]
|
||||||
|
|
||||||
|
GC_fullCollect()
|
||||||
|
|
||||||
|
m[0][0] = 2.0
|
||||||
|
echo "m[0][0] = ", m[0][0]
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
import json, tables, sequtils
|
import json, tables, sequtils
|
||||||
|
|
||||||
proc run(json_params: Table) =
|
proc run(json_params: OrderedTable) =
|
||||||
let json_elems = json_params["files"].elems
|
let json_elems = json_params["files"].elems
|
||||||
# These fail compilation.
|
# These fail compilation.
|
||||||
var files = map(json_elems, proc (x: JsonNode): string = x.str)
|
var files = map(json_elems, proc (x: JsonNode): string = x.str)
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,29 @@ block mpairsTableTest1:
|
||||||
block SyntaxTest:
|
block SyntaxTest:
|
||||||
var x = toTable[int, string]({:})
|
var x = toTable[int, string]({:})
|
||||||
|
|
||||||
|
# Until #4448 is fixed, these tests will fail
|
||||||
|
when false:
|
||||||
|
block clearTableTest:
|
||||||
|
var t = data.toTable
|
||||||
|
assert t.len() != 0
|
||||||
|
t.clear()
|
||||||
|
assert t.len() == 0
|
||||||
|
|
||||||
|
block clearOrderedTableTest:
|
||||||
|
var t = data.toOrderedTable
|
||||||
|
assert t.len() != 0
|
||||||
|
t.clear()
|
||||||
|
assert t.len() == 0
|
||||||
|
|
||||||
|
block clearCountTableTest:
|
||||||
|
var t = initCountTable[string]()
|
||||||
|
t.inc("90", 3)
|
||||||
|
t.inc("12", 2)
|
||||||
|
t.inc("34", 1)
|
||||||
|
assert t.len() != 0
|
||||||
|
t.clear()
|
||||||
|
assert t.len() == 0
|
||||||
|
|
||||||
proc orderedTableSortTest() =
|
proc orderedTableSortTest() =
|
||||||
var t = initOrderedTable[string, int](2)
|
var t = initOrderedTable[string, int](2)
|
||||||
for key, val in items(data): t[key] = val
|
for key, val in items(data): t[key] = val
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,31 @@ block anonZipTest:
|
||||||
let values = @[1, 2, 3]
|
let values = @[1, 2, 3]
|
||||||
doAssert "{a: 1, b: 2, c: 3}" == $ toTable zip(keys, values)
|
doAssert "{a: 1, b: 2, c: 3}" == $ toTable zip(keys, values)
|
||||||
|
|
||||||
|
block clearTableTest:
|
||||||
|
var t = newTable[string, float]()
|
||||||
|
t["test"] = 1.2345
|
||||||
|
t["111"] = 1.000043
|
||||||
|
t["123"] = 1.23
|
||||||
|
assert t.len() != 0
|
||||||
|
t.clear()
|
||||||
|
assert t.len() == 0
|
||||||
|
|
||||||
|
block clearOrderedTableTest:
|
||||||
|
var t = newOrderedTable[string, int](2)
|
||||||
|
for key, val in items(data): t[key] = val
|
||||||
|
assert t.len() != 0
|
||||||
|
t.clear()
|
||||||
|
assert t.len() == 0
|
||||||
|
|
||||||
|
block clearCountTableTest:
|
||||||
|
var t = newCountTable[string]()
|
||||||
|
t.inc("90", 3)
|
||||||
|
t.inc("12", 2)
|
||||||
|
t.inc("34", 1)
|
||||||
|
assert t.len() != 0
|
||||||
|
t.clear()
|
||||||
|
assert t.len() == 0
|
||||||
|
|
||||||
orderedTableSortTest()
|
orderedTableSortTest()
|
||||||
echo "true"
|
echo "true"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ discard """
|
||||||
file: "tcurrncy.nim"
|
file: "tcurrncy.nim"
|
||||||
output: "25"
|
output: "25"
|
||||||
"""
|
"""
|
||||||
template Additive(typ: typeDesc): stmt =
|
template Additive(typ: untyped) =
|
||||||
proc `+` *(x, y: typ): typ {.borrow.}
|
proc `+` *(x, y: typ): typ {.borrow.}
|
||||||
proc `-` *(x, y: typ): typ {.borrow.}
|
proc `-` *(x, y: typ): typ {.borrow.}
|
||||||
|
|
||||||
|
|
@ -10,18 +10,18 @@ template Additive(typ: typeDesc): stmt =
|
||||||
proc `+` *(x: typ): typ {.borrow.}
|
proc `+` *(x: typ): typ {.borrow.}
|
||||||
proc `-` *(x: typ): typ {.borrow.}
|
proc `-` *(x: typ): typ {.borrow.}
|
||||||
|
|
||||||
template Multiplicative(typ, base: typeDesc): stmt {.immediate.} =
|
template Multiplicative(typ, base: untyped) =
|
||||||
proc `*` *(x: typ, y: base): typ {.borrow.}
|
proc `*` *(x: typ, y: base): typ {.borrow.}
|
||||||
proc `*` *(x: base, y: typ): typ {.borrow.}
|
proc `*` *(x: base, y: typ): typ {.borrow.}
|
||||||
proc `div` *(x: typ, y: base): typ {.borrow.}
|
proc `div` *(x: typ, y: base): typ {.borrow.}
|
||||||
proc `mod` *(x: typ, y: base): typ {.borrow.}
|
proc `mod` *(x: typ, y: base): typ {.borrow.}
|
||||||
|
|
||||||
template Comparable(typ: typeDesc): stmt =
|
template Comparable(typ: untyped) =
|
||||||
proc `<` * (x, y: typ): bool {.borrow.}
|
proc `<` * (x, y: typ): bool {.borrow.}
|
||||||
proc `<=` * (x, y: typ): bool {.borrow.}
|
proc `<=` * (x, y: typ): bool {.borrow.}
|
||||||
proc `==` * (x, y: typ): bool {.borrow.}
|
proc `==` * (x, y: typ): bool {.borrow.}
|
||||||
|
|
||||||
template DefineCurrency(typ, base: expr): stmt {.immediate.} =
|
template DefineCurrency(typ, base: untyped) =
|
||||||
type
|
type
|
||||||
typ* = distinct base
|
typ* = distinct base
|
||||||
Additive(typ)
|
Additive(typ)
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
discard """
|
discard """
|
||||||
file: "tsidee4.nim"
|
file: "tsidee4.nim"
|
||||||
line: 15
|
line: 12
|
||||||
errormsg: "type mismatch"
|
errormsg: "'noSideEffect' can have side effects"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
var
|
var
|
||||||
global: int
|
global: int
|
||||||
|
|
||||||
proc dontcare(x: int): int = return x
|
proc dontcare(x: int): int = return global
|
||||||
|
|
||||||
proc noSideEffect(x, y: int, p: proc (a: int): int {.noSideEffect.}): int {.noSideEffect.} =
|
proc noSideEffect(x, y: int, p: proc (a: int): int {.noSideEffect.}): int {.noSideEffect.} =
|
||||||
return x + y + dontcare(x)
|
return x + y + dontcare(x)
|
||||||
|
|
|
||||||
13
tests/generics/tlamba_in_generic.nim
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
discard """
|
||||||
|
output: '''!!Hi!!'''
|
||||||
|
"""
|
||||||
|
# bug #4658
|
||||||
|
import future
|
||||||
|
|
||||||
|
var x = 123
|
||||||
|
|
||||||
|
proc twice[T](f: T -> T): T -> T = (x: T) => f(f(x))
|
||||||
|
|
||||||
|
proc quote(s: string): string = "!" & s & "!"
|
||||||
|
|
||||||
|
echo twice(quote)("Hi")
|
||||||
8
tests/generics/ttempl_in_generic.nim
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
# bug #4600
|
||||||
|
template foo(x: untyped): untyped = echo 1
|
||||||
|
template foo(x,y: untyped): untyped = echo 2
|
||||||
|
|
||||||
|
proc bar1[T](x: T) = foo(x)
|
||||||
|
proc bar2(x: float) = foo(x,x)
|
||||||
|
proc bar3[T](x: T) = foo(x,x)
|
||||||
33
tests/iter/tcomplex_openarray.nim
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
# bug #3221
|
||||||
|
|
||||||
|
import algorithm, math, sequtils
|
||||||
|
|
||||||
|
|
||||||
|
iterator permutations[T](ys: openarray[T]): seq[T] =
|
||||||
|
var
|
||||||
|
d = 1
|
||||||
|
c = newSeq[int](ys.len)
|
||||||
|
xs = newSeq[T](ys.len)
|
||||||
|
for i, y in ys: xs[i] = y
|
||||||
|
yield xs
|
||||||
|
block outer:
|
||||||
|
while true:
|
||||||
|
while d > 1:
|
||||||
|
dec d
|
||||||
|
c[d] = 0
|
||||||
|
while c[d] >= d:
|
||||||
|
inc d
|
||||||
|
if d >= ys.len: break outer
|
||||||
|
let i = if (d and 1) == 1: c[d] else: 0
|
||||||
|
swap xs[i], xs[d]
|
||||||
|
yield xs
|
||||||
|
inc c[d]
|
||||||
|
|
||||||
|
proc dig_vectors(): void =
|
||||||
|
var v_nums: seq[int]
|
||||||
|
v_nums = newSeq[int](1)
|
||||||
|
for perm in permutations(toSeq(0 .. 1)):
|
||||||
|
v_nums[0] = 1
|
||||||
|
|
||||||
|
dig_vectors()
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
discard """
|
discard """
|
||||||
output: '''[OK] >:)'''
|
output: '''
|
||||||
|
[Suite] Bacon
|
||||||
|
[OK] >:)'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
|
||||||
67
tests/macros/tgettype2.nim
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
|
||||||
|
import macros, typetraits
|
||||||
|
|
||||||
|
type Foo = distinct int
|
||||||
|
type Bar = distinct int
|
||||||
|
type Baz = int
|
||||||
|
|
||||||
|
let foo = 0.Foo
|
||||||
|
let bar = 1.Bar
|
||||||
|
let baz = 2.Baz
|
||||||
|
|
||||||
|
type MyType[T] = distinct tuple[a,b:T]
|
||||||
|
type MySimpleType = distinct tuple[a,b: int]
|
||||||
|
|
||||||
|
var v: seq[int]
|
||||||
|
var vv: seq[float]
|
||||||
|
var t: MyType[int]
|
||||||
|
var tt: MyType[float]
|
||||||
|
var s: MySimpleType
|
||||||
|
|
||||||
|
echo "############"
|
||||||
|
echo "#### gt ####"
|
||||||
|
echo "############"
|
||||||
|
|
||||||
|
macro gt(a: typed): string =
|
||||||
|
let b = a.getType
|
||||||
|
var str = "gt(" & $a & "):\t" & b.repr
|
||||||
|
if b.kind == nnkSym: # bad predicat to check weather the type has an implementation
|
||||||
|
str = str & ", " & b.getType.repr # append the implementation to the result
|
||||||
|
result = newLit(str)
|
||||||
|
|
||||||
|
echo gt(Foo) # typeDesc[Foo]
|
||||||
|
echo gt(Bar) # typeDesc[Bar]
|
||||||
|
echo gt(Baz) # typeDesc[int] shouldn't it be typeDesc[Baz]?
|
||||||
|
echo gt(foo) # distinct[int] I would prefer Foo, distinct[int]
|
||||||
|
echo gt(bar) # distinct[int] I would prefer Bar, distinct[int]
|
||||||
|
echo gt(baz) # int, int I would prefer Baz, int
|
||||||
|
|
||||||
|
echo gt(v) # seq[int], ok
|
||||||
|
echo gt(vv) # seq[float], ok
|
||||||
|
echo gt(t) # MyType, distinct[tuple[int, int]] I would prefer MyType[int], distinct[tuple[int, int]]
|
||||||
|
echo gt(tt) # MyType, distinct[tuple[float, float]] I would prefer MyType[float], distinct[tuple[int, int]]
|
||||||
|
echo gt(s) # distinct[tuple[int, int]] I would prefer MySimpleType, distinct[tuple[int,int]]
|
||||||
|
|
||||||
|
echo "#############"
|
||||||
|
echo "#### gt2 ####"
|
||||||
|
echo "#############"
|
||||||
|
|
||||||
|
# get type name via typetraits
|
||||||
|
|
||||||
|
macro gt2(a: typed): string =
|
||||||
|
let prefix = "gt2(" & $a & "): \t"
|
||||||
|
result = quote do:
|
||||||
|
`prefix` & `a`.type.name
|
||||||
|
|
||||||
|
echo gt2(Foo) # Foo shouldn't this be typeDesc[Foo] ?
|
||||||
|
echo gt2(Bar) # Bar shouldn't this be typeDesc[Bar] ?
|
||||||
|
echo gt2(Baz) # Baz shouldn't this be typeDesc[Baz] ?
|
||||||
|
echo gt2(foo) # Foo
|
||||||
|
echo gt2(bar) # Bar
|
||||||
|
echo gt2(baz) # Baz
|
||||||
|
|
||||||
|
echo gt2(v) # seq[int]
|
||||||
|
echo gt2(vv) # seq[float]
|
||||||
|
echo gt2(t) # MyType[system.int] why is it system.int and not just int like in seq?
|
||||||
|
echo gt2(tt) # MyType[system.float] why is it system.float and not just float like in seq?
|
||||||
|
echo gt2(s) # MySimpleType
|
||||||
43
tests/metatype/twildtypedesc.nim
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
discard """
|
||||||
|
output: '''123
|
||||||
|
123
|
||||||
|
123
|
||||||
|
123
|
||||||
|
123
|
||||||
|
123'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
proc unpack(t: typedesc[string], v: string): string = $v
|
||||||
|
proc unpack(t: typedesc[int], v: string): int = parseInt(v)
|
||||||
|
|
||||||
|
proc unpack[T](v: string): T =
|
||||||
|
unpack T, v
|
||||||
|
|
||||||
|
var s = "123"
|
||||||
|
|
||||||
|
assert(unpack[string](s) is string)
|
||||||
|
assert(unpack[int](s) is int)
|
||||||
|
|
||||||
|
echo unpack[int](s)
|
||||||
|
echo unpack[string](s)
|
||||||
|
|
||||||
|
echo unpack(int,s)
|
||||||
|
echo unpack(string,s)
|
||||||
|
|
||||||
|
template `as`*(x: untyped, t: typedesc): untyped = unpack(t,x)
|
||||||
|
|
||||||
|
echo s as int
|
||||||
|
echo s as string
|
||||||
|
|
||||||
|
# bug #4534
|
||||||
|
|
||||||
|
proc unit(t: typedesc[int]): t = 0
|
||||||
|
proc unit(t: typedesc[string]): t = ""
|
||||||
|
proc unit(t: typedesc[float]): t = 0.0
|
||||||
|
|
||||||
|
assert unit(int) == 0
|
||||||
|
assert unit(string) == ""
|
||||||
|
assert unit(float) == 0.0
|
||||||
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
discard """
|
discard """
|
||||||
action: run
|
action: run
|
||||||
|
output: '''
|
||||||
|
[Suite] inet_ntop tests
|
||||||
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
discard """
|
discard """
|
||||||
action: run
|
action: run
|
||||||
|
output: '''
|
||||||
|
[Suite] parseutils'''
|
||||||
"""
|
"""
|
||||||
import unittest, strutils
|
import unittest, strutils
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,55 +39,49 @@ doAssert t4.format("M MM MMM MMMM") == "10 10 Oct October"
|
||||||
doAssert((t4 - initInterval(years = 2)).format("yyyy") == "1995")
|
doAssert((t4 - initInterval(years = 2)).format("yyyy") == "1995")
|
||||||
doAssert((t4 - initInterval(years = 7, minutes = 34, seconds = 24)).format("yyyy mm ss") == "1990 24 10")
|
doAssert((t4 - initInterval(years = 7, minutes = 34, seconds = 24)).format("yyyy mm ss") == "1990 24 10")
|
||||||
|
|
||||||
var s = "Tuesday at 09:04am on Dec 15, 2015"
|
proc parseTest(s, f, sExpected: string, ydExpected: int) =
|
||||||
var f = "dddd at hh:mmtt on MMM d, yyyy"
|
let parsed = s.parse(f)
|
||||||
doAssert($s.parse(f) == "Tue Dec 15 09:04:00 2015")
|
doAssert($parsed == sExpected)
|
||||||
|
doAssert(parsed.yearday == ydExpected)
|
||||||
|
proc parseTestTimeOnly(s, f, sExpected: string) =
|
||||||
|
doAssert(sExpected in $s.parse(f))
|
||||||
|
|
||||||
|
parseTest("Tuesday at 09:04am on Dec 15, 2015",
|
||||||
|
"dddd at hh:mmtt on MMM d, yyyy", "Tue Dec 15 09:04:00 2015", 348)
|
||||||
# ANSIC = "Mon Jan _2 15:04:05 2006"
|
# ANSIC = "Mon Jan _2 15:04:05 2006"
|
||||||
s = "Thu Jan 12 15:04:05 2006"
|
parseTest("Thu Jan 12 15:04:05 2006", "ddd MMM dd HH:mm:ss yyyy",
|
||||||
f = "ddd MMM dd HH:mm:ss yyyy"
|
"Thu Jan 12 15:04:05 2006", 11)
|
||||||
doAssert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
|
||||||
# UnixDate = "Mon Jan _2 15:04:05 MST 2006"
|
# UnixDate = "Mon Jan _2 15:04:05 MST 2006"
|
||||||
s = "Thu Jan 12 15:04:05 MST 2006"
|
parseTest("Thu Jan 12 15:04:05 MST 2006", "ddd MMM dd HH:mm:ss ZZZ yyyy",
|
||||||
f = "ddd MMM dd HH:mm:ss ZZZ yyyy"
|
"Thu Jan 12 15:04:05 2006", 11)
|
||||||
doAssert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
|
||||||
# RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
|
# RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
|
||||||
s = "Thu Jan 12 15:04:05 -07:00 2006"
|
parseTest("Mon Feb 29 15:04:05 -07:00 2016", "ddd MMM dd HH:mm:ss zzz yyyy",
|
||||||
f = "ddd MMM dd HH:mm:ss zzz yyyy"
|
"Mon Feb 29 15:04:05 2016", 59) # leap day
|
||||||
doAssert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
|
||||||
# RFC822 = "02 Jan 06 15:04 MST"
|
# RFC822 = "02 Jan 06 15:04 MST"
|
||||||
s = "12 Jan 16 15:04 MST"
|
parseTest("12 Jan 16 15:04 MST", "dd MMM yy HH:mm ZZZ",
|
||||||
f = "dd MMM yy HH:mm ZZZ"
|
"Tue Jan 12 15:04:00 2016", 11)
|
||||||
doAssert($s.parse(f) == "Tue Jan 12 15:04:00 2016")
|
|
||||||
# RFC822Z = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone
|
# RFC822Z = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone
|
||||||
s = "12 Jan 16 15:04 -07:00"
|
parseTest("01 Mar 16 15:04 -07:00", "dd MMM yy HH:mm zzz",
|
||||||
f = "dd MMM yy HH:mm zzz"
|
"Tue Mar 1 15:04:00 2016", 60) # day after february in leap year
|
||||||
doAssert($s.parse(f) == "Tue Jan 12 15:04:00 2016")
|
|
||||||
# RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
|
# RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
|
||||||
s = "Monday, 12-Jan-06 15:04:05 MST"
|
parseTest("Monday, 12-Jan-06 15:04:05 MST", "dddd, dd-MMM-yy HH:mm:ss ZZZ",
|
||||||
f = "dddd, dd-MMM-yy HH:mm:ss ZZZ"
|
"Thu Jan 12 15:04:05 2006", 11)
|
||||||
doAssert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
|
||||||
# RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
|
# RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
|
||||||
s = "Thu, 12 Jan 2006 15:04:05 MST"
|
parseTest("Sun, 01 Mar 2015 15:04:05 MST", "ddd, dd MMM yyyy HH:mm:ss ZZZ",
|
||||||
f = "ddd, dd MMM yyyy HH:mm:ss ZZZ"
|
"Sun Mar 1 15:04:05 2015", 59) # day after february in non-leap year
|
||||||
doAssert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
|
||||||
# RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone
|
# RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone
|
||||||
s = "Thu, 12 Jan 2006 15:04:05 -07:00"
|
parseTest("Thu, 12 Jan 2006 15:04:05 -07:00", "ddd, dd MMM yyyy HH:mm:ss zzz",
|
||||||
f = "ddd, dd MMM yyyy HH:mm:ss zzz"
|
"Thu Jan 12 15:04:05 2006", 11)
|
||||||
doAssert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
|
||||||
# RFC3339 = "2006-01-02T15:04:05Z07:00"
|
# RFC3339 = "2006-01-02T15:04:05Z07:00"
|
||||||
s = "2006-01-12T15:04:05Z-07:00"
|
parseTest("2006-01-12T15:04:05Z-07:00", "yyyy-MM-ddTHH:mm:ssZzzz",
|
||||||
f = "yyyy-MM-ddTHH:mm:ssZzzz"
|
"Thu Jan 12 15:04:05 2006", 11)
|
||||||
doAssert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
parseTest("2006-01-12T15:04:05Z-07:00", "yyyy-MM-dd'T'HH:mm:ss'Z'zzz",
|
||||||
f = "yyyy-MM-dd'T'HH:mm:ss'Z'zzz"
|
"Thu Jan 12 15:04:05 2006", 11)
|
||||||
doAssert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
|
||||||
# RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
|
# RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
|
||||||
s = "2006-01-12T15:04:05.999999999Z-07:00"
|
parseTest("2006-01-12T15:04:05.999999999Z-07:00",
|
||||||
f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz"
|
"yyyy-MM-ddTHH:mm:ss.999999999Zzzz", "Thu Jan 12 15:04:05 2006", 11)
|
||||||
doAssert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
|
||||||
# Kitchen = "3:04PM"
|
# Kitchen = "3:04PM"
|
||||||
s = "3:04PM"
|
parseTestTimeOnly("3:04PM", "h:mmtt", "15:04:00")
|
||||||
f = "h:mmtt"
|
|
||||||
doAssert "15:04:00" in $s.parse(f)
|
|
||||||
#when not defined(testing):
|
#when not defined(testing):
|
||||||
# echo "Kitchen: " & $s.parse(f)
|
# echo "Kitchen: " & $s.parse(f)
|
||||||
# var ti = timeToTimeInfo(getTime())
|
# var ti = timeToTimeInfo(getTime())
|
||||||
|
|
|
||||||
9
tests/template/ttemp_in_varargs.nim
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
discard """
|
||||||
|
output: '''a'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
# bug #4292
|
||||||
|
|
||||||
|
template foo(s: string): string = s
|
||||||
|
proc variadicProc*(v: varargs[string, foo]) = echo v[0]
|
||||||
|
variadicProc("a")
|
||||||
3
tests/vm/tconst_float_as_int.nim
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
# bug #4619
|
||||||
|
const x: float = 0
|
||||||
1
todo.txt
|
|
@ -1,6 +1,7 @@
|
||||||
version 1.0 battle plan
|
version 1.0 battle plan
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
- iters for js
|
||||||
- fix "high priority" bugs
|
- fix "high priority" bugs
|
||||||
- try to fix as many compiler crashes as reasonable
|
- try to fix as many compiler crashes as reasonable
|
||||||
|
|
||||||
|
|
|
||||||
BIN
web/assets/news/images/survey/dev_os.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
web/assets/news/images/survey/do_you_use_nim.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
web/assets/news/images/survey/editors.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
web/assets/news/images/survey/nim_at_work.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
web/assets/news/images/survey/nim_found.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
web/assets/news/images/survey/nim_time.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
web/assets/news/images/survey/nim_time_rust.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
web/assets/news/images/survey/nim_versions.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
web/assets/news/images/survey/planning_to_use_at_work.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
web/assets/news/images/survey/project_size.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
web/assets/news/images/survey/project_size_nim_rust.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
web/assets/news/images/survey/project_size_work.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
web/assets/news/images/survey/reliability.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
web/assets/news/images/survey/target_os.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
web/assets/news/images/survey/upgrades_broke_things.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
317
web/news/nim_community_survey_results.rst
Normal file
|
|
@ -0,0 +1,317 @@
|
||||||
|
Nim Community Survey Results
|
||||||
|
============================
|
||||||
|
|
||||||
|
.. container:: metadata
|
||||||
|
|
||||||
|
Posted by Dominik Picheta on 20/08/2016
|
||||||
|
|
||||||
|
We have recently closed the 2016 Nim Community Survey. I am happy to
|
||||||
|
say that we have received exactly 790 responses, huge thanks go to the people
|
||||||
|
that took the time to respond. We're very thankful for this very valuable
|
||||||
|
feedback.
|
||||||
|
|
||||||
|
This survey was inspired in part by the
|
||||||
|
`2016 State of Rust <https://blog.rust-lang.org/2016/06/30/State-of-Rust-Survey-2016.html>`_
|
||||||
|
survey. You will note that many of the questions were modelled after
|
||||||
|
Rust's survey. One of the reasons for doing this was to allow us to easily
|
||||||
|
compare our results against the results obtained in the Rust survey. In
|
||||||
|
addition, we of course also liked many of their questions.
|
||||||
|
|
||||||
|
Our survey ran from the 23rd of June 2016 until the 8th of August 2016. The
|
||||||
|
response numbers are impressive considering Nim's community size; at 790 they
|
||||||
|
make up just over 25% of the Rust survey's responses.
|
||||||
|
|
||||||
|
The goal of this survey was to primarily determine how our community is using
|
||||||
|
Nim, in order to better understand how we should be improving it. In particular,
|
||||||
|
we wanted to know what people feel is missing from Nim in the lead up to
|
||||||
|
version 1.0. We have also asked our respondents about how well the Nim tools
|
||||||
|
worked, the challenges of adopting Nim, the resources that they used to learn
|
||||||
|
Nim and more.
|
||||||
|
|
||||||
|
It is my hope that we will be able to run a similar survey in a years time,
|
||||||
|
doing so should give us an idea of whether we are improving.
|
||||||
|
With these general facts in mind, let's begin looking at specific questions.
|
||||||
|
|
||||||
|
How did you find out about Nim?
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
The rationale for the first question was simple, we wanted to know where our
|
||||||
|
respondents found out about Nim. This is an interesting question for us, as
|
||||||
|
we do occassionally get users asking us why it took so long for them to hear
|
||||||
|
about Nim. It allows us to see how effective each website is at spreading the
|
||||||
|
word about Nim.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/nim_found.png">
|
||||||
|
<img src="../assets/news/images/survey/nim_found.png" alt="How did you find out about Nim?" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
The majority of our respondents found Nim via Reddit, HackerNews or a search
|
||||||
|
engine such as Google. These results are not altogether surprising. There were
|
||||||
|
also a lot of "Other" responses, some of which were a bit more
|
||||||
|
interesting. These included multiple mentions of habrahabr.ru, Dr. Dobb's,
|
||||||
|
and lobste.rs.
|
||||||
|
|
||||||
|
Do you use Nim?
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Just like the Rust survey creators, we wanted to ensure that our survey was
|
||||||
|
open to both Nim users as well people who never used Nim. In addition to
|
||||||
|
those two groups, we have also included a third group of people: ex-Nim
|
||||||
|
users. All three are interesting, for many different reasons.
|
||||||
|
Nim users can tell us how they are using Nim and also how Nim's
|
||||||
|
tooling can improve. Ex-Nim users give us an
|
||||||
|
idea of why they stopped using Nim. Finally, respondents who never used Nim
|
||||||
|
can tell us the reasons for not adopting it.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/do_you_use_nim.png">
|
||||||
|
<img src="../assets/news/images/survey/do_you_use_nim.png" alt="Do you use Nim?" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
It's nice to see that we have such a good range of respondents. The Rust survey
|
||||||
|
had a much larger number of Rust users amongst their respondents, with
|
||||||
|
no distinction between users that never used Rust and users that stopped using
|
||||||
|
Rust.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="https://blog.rust-lang.org/images/2016-06-Survey/do_you_use_rust.png">
|
||||||
|
<img src="https://blog.rust-lang.org/images/2016-06-Survey/do_you_use_rust.png" alt="Do you use Rust?" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
Should we consider your answers to be invalid?
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
This was something I thought would be interesting to have, after I saw it
|
||||||
|
being used in another survey. While it does pinpoint possibly
|
||||||
|
invalid respondents, I have opted against filtering those out. Mainly because
|
||||||
|
that would require re-creating each of the charts generated by Google Forms
|
||||||
|
manually.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/reliability.png">
|
||||||
|
<img src="../assets/news/images/survey/reliability.png" alt="Should we consider your answers to be invalid?" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
According to the responses to this question, around 94% of our responses
|
||||||
|
can be considered reliable.
|
||||||
|
|
||||||
|
Nim users
|
||||||
|
---------
|
||||||
|
|
||||||
|
The following questions were answered only by the 38.9% of our respondents
|
||||||
|
who identified themselves as Nim users.
|
||||||
|
|
||||||
|
How long have you been using Nim?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/nim_time.png">
|
||||||
|
<img src="../assets/news/images/survey/nim_time.png" alt="How long have you been using Nim?" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
A large proportion of our Nim users were new. This is good news as it means that
|
||||||
|
our community is growing, with a large proportion of new Nim users that could
|
||||||
|
become long-term Nimians. In total, more than 35% of Nim users can be considered
|
||||||
|
new having used Nim for less than 3 months. With 18% of Nim users that can
|
||||||
|
be considered very new having used Nim for less than a month.
|
||||||
|
This could suggest that 18% of our users have only just found out about Nim in
|
||||||
|
the last week or so and have not yet got the chance to use it extensively.
|
||||||
|
|
||||||
|
The high percentages of long term Nim users are encouraging.
|
||||||
|
They suggest
|
||||||
|
that many users are continuing to use Nim after making it through the first
|
||||||
|
few months. The sharp drop at 7-9 months is interesting, but may simply be
|
||||||
|
due to the fact that there were fewer newcomers during that period, or it
|
||||||
|
could be because our respondents are more likely to estimate that they have
|
||||||
|
been using Nim for a year or half a year rather than the awkward 7-9 months.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/nim_time_rust.png">
|
||||||
|
<img src="../assets/news/images/survey/nim_time_rust.png" alt="Time using Nim and Rust" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
The results for Nim and Rust are actually remarkably similar. They both show a
|
||||||
|
drop at 7-9 months, although Rust's isn't as dramatic. Nim on the other hand
|
||||||
|
has a significantly higher percentage of new Nim users.
|
||||||
|
|
||||||
|
Do you use Nim at work?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
An important aspect of a language's adoption is whether it is being used for
|
||||||
|
"real" work. We wanted to know how many people are using Nim in their day
|
||||||
|
jobs and under what circumstances it is used.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/nim_at_work.png">
|
||||||
|
<img src="../assets/news/images/survey/nim_at_work.png" alt="Do you use Nim at work?" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
While a vast majority of our users are not using Nim at work, more than 25%
|
||||||
|
of them are. It's encouraging to see such a high number already, even before
|
||||||
|
we have released version 1.0. In fact, this percentage is likely close to 30%,
|
||||||
|
because many of the "Other" responses mention using Nim for the likes of
|
||||||
|
internal tools or small scripts to help with the respondent's work.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="https://blog.rust-lang.org/images/2016-06-Survey/rust_at_work.png">
|
||||||
|
<img src="https://blog.rust-lang.org/images/2016-06-Survey/rust_at_work.png" alt="Do you use Rust at work?" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
Interestingly, a larger percentage of Nim users are using Nim at work than
|
||||||
|
Rust users. The sample sizes are of course vastly different, but it's still an
|
||||||
|
interesting result. Combined, nearly 1/5th of Rust users are using Rust
|
||||||
|
commercially whereas more than a quarter of Nim users are using Nim
|
||||||
|
commercially.
|
||||||
|
|
||||||
|
Approximately how large are all the Nim projects that you work on?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Finding out how large the Nim projects worked on by Nim users are is also
|
||||||
|
very valuable.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/project_size.png">
|
||||||
|
<img src="../assets/news/images/survey/project_size.png" alt="Nim project size for all users" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
This shows us that currently Nim is primarily being used for small scripts and
|
||||||
|
applications, with nearly 60% of the projects consisting of less than 1,000
|
||||||
|
lines of code. This makes sense as many of our users are not using Nim
|
||||||
|
professionally, but are doing so in their spare time.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/project_size_work.png">
|
||||||
|
<img src="../assets/news/images/survey/project_size_work.png" alt="Nim project size for work users" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
The numbers for part-time and full-time work users of Nim tell a different
|
||||||
|
story. Over 70% of the projects written by full-time users are between 10,001
|
||||||
|
and 100,000 lines of code. Part-time users show a slightly different trend,
|
||||||
|
with many more small projects, the majority being between 1,000 and
|
||||||
|
10,000 lines of code.
|
||||||
|
|
||||||
|
Overall it's good to see that there is a few large projects out there which are
|
||||||
|
composed of more than 100,000 lines of code. We expect to see the amount of
|
||||||
|
large projects to grow with time, especially with version 1.0 on the way.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/project_size_nim_rust.png">
|
||||||
|
<img src="../assets/news/images/survey/project_size_nim_rust.png" alt="Nim project size for work users (Nim vs. Rust)" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
In comparison to Rust the proportion of project sizes for full-time users is
|
||||||
|
vastly different. This is likely due to our small sample size. Project sizes for
|
||||||
|
part-time users between Rust and Nim are somewhat similar, with differences of
|
||||||
|
around 10% for each project size.
|
||||||
|
|
||||||
|
Do you plan to try to use Nim at work?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/planning_to_use_at_work.png">
|
||||||
|
<img src="../assets/news/images/survey/planning_to_use_at_work.png" alt="Planning to use Nim at work?" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
It's also encouraging to see that over 50% of Nim users are planning to use
|
||||||
|
Nim at work! This is slightly more than Rust's 40% and should help Nim's
|
||||||
|
adoption into even more areas.
|
||||||
|
|
||||||
|
Nim and its tools
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
In this section of the survey, we wanted to find out the tools that Nim
|
||||||
|
users are utilising when developing Nim applications.
|
||||||
|
|
||||||
|
What editor(s) do you use when writing Nim?
|
||||||
|
___________________________________________
|
||||||
|
|
||||||
|
Programmers are very specific when it comes to their editor of choice, because
|
||||||
|
of that it's good to know which editor is most popular among our community.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/editors.png">
|
||||||
|
<img src="../assets/news/images/survey/editors.png" alt="Editors used by Nim users" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
Looks like Vim is the winner with almost 30%. Followed by Sublime Text and
|
||||||
|
Visual Studio Code. Aporia, the Nim IDE, gets a respectable 15.5%. There was
|
||||||
|
also more than
|
||||||
|
17% of answers which included "Other" editors, such as: Notepad++, Geany, gedit,
|
||||||
|
and Kate.
|
||||||
|
|
||||||
|
What operating system(s) do you compile for and run your Nim projects on?
|
||||||
|
_________________________________________________________________________
|
||||||
|
|
||||||
|
This question gave us information about the most popular target operating
|
||||||
|
systems, as well as some of the more obscure ones. We have asked this question
|
||||||
|
to find out the platforms on which Nim applications run on most frequently.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/target_os.png">
|
||||||
|
<img src="../assets/news/images/survey/target_os.png" alt="Target operating systems" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
This question allowed multiple choices, so each percentage is out of the total
|
||||||
|
number of respondents for this question. For example, 80.7% of the
|
||||||
|
respondents selected "Linux" but only 26.6% selected OS X.
|
||||||
|
|
||||||
|
This makes Linux by far the most popular target for Nim applications.
|
||||||
|
Some "Other" targets included: BSD (OpenBSD, FreeBSD), iOS, Android, and
|
||||||
|
JavaScript.
|
||||||
|
It's great to see Nim being used on such a wide variety of platforms.
|
||||||
|
|
||||||
|
What operating system(s) do you develop Nim projects on?
|
||||||
|
________________________________________________________
|
||||||
|
|
||||||
|
With this question, we wanted to know what operating systems are used for
|
||||||
|
development.
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/dev_os.png">
|
||||||
|
<img src="../assets/news/images/survey/dev_os.png" alt="Development operating systems" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
This question also allowed multiple choices and ended up with very similar
|
||||||
|
results.
|
||||||
|
|
||||||
|
You can see that Linux is also the most popular developmental
|
||||||
|
platform for Nim. But it's more popular as a target platform.
|
||||||
|
|
||||||
|
Which version(s) of Nim do you use for your applications?
|
||||||
|
_________________________________________________________
|
||||||
|
|
||||||
|
.. raw::html
|
||||||
|
|
||||||
|
<a href="../assets/news/images/survey/nim_versions.png">
|
||||||
|
<img src="../assets/news/images/survey/nim_versions.png" alt="Version use" style="width:100%"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
At the time of this survey, version 0.14.2 was the latest stable release.
|
||||||
|
It's no wonder that it is the most commonly used release of Nim. It's good to
|
||||||
|
see that the older versions are not used as often. The high use of ``Git HEAD (devel)``
|
||||||
|
(nightly builds) isn't surprising, Nim is still evolving rapidly and our
|
||||||
|
release schedule is not regular or frequent.
|
||||||
|
|
||||||
|
Once we go past the 1.0 release, we expect to see much less use of the unstable
|
||||||
|
``devel`` branch.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -10,6 +10,8 @@ Some text here.
|
||||||
Changes affecting backwards compatibility
|
Changes affecting backwards compatibility
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
|
- The ``json`` module uses an ``OrderedTable`` rather than a ``Table``
|
||||||
|
for JSON objects.
|
||||||
- De-deprecated ``re.nim`` because we have too much code using it
|
- De-deprecated ``re.nim`` because we have too much code using it
|
||||||
and it got the basic API right.
|
and it got the basic API right.
|
||||||
|
|
||||||
|
|
|
||||||