bugfixes; field discriminant checks; linearScanEnd, unroll, shallow pragmas

This commit is contained in:
Araq
2011-03-23 01:09:52 +01:00
parent 8d734244b1
commit 5b789f2da8
45 changed files with 2342 additions and 243 deletions

View File

@@ -81,7 +81,7 @@ gcc.options.debug = "-g"
@end
@else:
@if not release:
gcc.options.always = "-w -O1"
gcc.options.always = "-w"
@else:
gcc.options.always = "-w"
@end

View File

@@ -2614,6 +2614,26 @@ The `final`:idx: pragma can be used for an object type to specify that it
cannot be inherited from.
shallow pragma
--------------
The `shallow`:idx: pragma affects the semantics of a type: The compiler is
allowed to make a shallow copy. This can cause serious semantic issues and
break memory safety! However, it can speed up assignments considerably,
because the semantics of Nimrod require deep copying of sequences and strings.
This can be expensive, especially if sequences are used to build a tree
structure:
.. code-block:: nimrod
type
TNodeKind = enum nkLeaf, nkInner
TNode {.final, shallow.} = object
case kind: TNodeKind
of nkLeaf:
strVal: string
of nkInner:
children: seq[TNode]
Pure pragma
-----------
The `pure`:idx: pragma serves two completely different purposes:
@@ -2646,53 +2666,53 @@ hint pragma
-----------
The `hint`:idx: pragma is used to make the compiler output a hint message with
the given content. Compilation continues after the hint.
linearScanEnd pragma
--------------------
The `linearScanEnd`:idx: pragma can be used to tell the compiler how to
compile a Nimrod `case`:idx: statement. Syntactially it has to be used as a
statement:
.. code-block:: nimrod
case myInt
of 0:
echo "most common case"
of 1:
{.linearScanEnd.}
echo "second most common case"
of 2: echo "unlikely: use branch table"
else: echo "unlikely too: use branch table for ", myInt
In the example, the case branches ``0`` and ``1`` are much more common than
the other cases. Therefore the generated assembler code should test for these
values first, so that the CPU's branch predictor has a good chance to succeed
(avoiding an expensive CPU pipeline stall). The other cases might be put into a
jump table for O(1) overhead, but at the cost of a (very likely) pipeline
stall.
The ``linearScanEnd`` pragma should be put into the last branch that should be
tested against via linear scanning. If put into the last branch of the
whole ``case`` statement, the whole ``case`` statement uses linear scanning.
unroll pragma
-------------
The `unroll`:idx: pragma can be used to tell the compiler that it should unroll
a `for`:idx: or `while`:idx: loop for runtime efficiency:
.. code-block:: nimrod
proc searchChar(s: string, c: char): int =
for i in 0 .. s.high:
{.unroll: 4.}
if s[i] == c: return i
result = -1
In the above example, the search loop is unrolled by a factor 4. The unroll
factor can be left out too; the compiler then chooses an appropriate unroll
factor.
**Note**: Currently the compiler recognizes but ignores this pragma.
linearScanEnd pragma
--------------------
The `linearScanEnd`:idx: pragma can be used to tell the compiler how to
compile a Nimrod `case`:idx: statement. Syntactially it has to be used as a
statement:
.. code-block:: nimrod
case myInt
of 0:
echo "most common case"
of 1:
{.linearScanEnd.}
echo "second most common case"
of 2: echo "unlikely: use branch table"
else: echo "unlikely too: use branch table for ", myInt
In the example, the case branches ``0`` and ``1`` are much more common than
the other cases. Therefore the generated assembler code should test for these
values first, so that the CPU's branch predictor has a good chance to succeed
(avoiding an expensive CPU pipeline stall). The other cases might be put into a
jump table for O(1) overhead, but at the cost of a (very likely) pipeline
stall.
The ``linearScanEnd`` pragma should be put into the last branch that should be
tested against via linear scanning. If put into the last branch of the
whole ``case`` statement, the whole ``case`` statement uses linear scanning.
unroll pragma
-------------
The `unroll`:idx: pragma can be used to tell the compiler that it should unroll
a `for`:idx: or `while`:idx: loop for runtime efficiency:
.. code-block:: nimrod
proc searchChar(s: string, c: char): int =
for i in 0 .. s.high:
{.unroll: 4.}
if s[i] == c: return i
result = -1
In the above example, the search loop is unrolled by a factor 4. The unroll
factor can be left out too; the compiler then chooses an appropriate unroll
factor.
**Note**: Currently the compiler recognizes but ignores this pragma.
compilation option pragmas

View File

@@ -131,28 +131,29 @@ proc findStartNimrod: string =
proc safeRemove(filename: string) =
if existsFile(filename): removeFile(filename)
proc bootIteration(args: string): bool =
var nimrod1 = "rod" / "nimrod1".exe
safeRemove(nimrod1)
moveFile(dest=nimrod1, source="rod" / "nimrod".exe)
exec "rod" / "nimrod1 cc $# $# rod/nimrod.nim" % [bootOptions, args]
# Nimrod does not produce an executable again if nothing changed. That's ok:
result = sameFileContent("rod" / "nimrod".exe, nimrod1)
var dest = "bin" / "nimrod".exe
safeRemove(dest)
copyFile(dest=dest, source="rod" / "nimrod".exe)
inclFilePermissions(dest, {fpUserExec})
safeRemove(nimrod1)
if result: echo "executables are equal: SUCCESS!"
proc thVersion(i: int): string =
result = ("rod" / "nimrod" & $i).exe
proc copyExe(source, dest: string) =
safeRemove(dest)
copyFile(dest=dest, source=source)
inclFilePermissions(dest, {fpUserExec})
proc boot(args: string) =
echo "iteration: 1"
exec findStartNimrod() & " cc $# $# rod" / "nimrod.nim" % [bootOptions, args]
echo "iteration: 2"
if not bootIteration(args):
echo "executables are not equal: compile once again..."
if not bootIteration(args):
echo "[Warning] executables are still not equal"
var output = "rod" / "nimrod".exe
var finalDest = "bin" / "nimrod".exe
copyExe(findStartNimrod(), 0.thVersion)
for i in 0..2:
echo "iteration: ", i+1
exec i.thVersion & " cc $# $# rod" / "nimrod.nim" % [bootOptions, args]
if sameFileContent(output, i.thVersion):
copyExe(output, finalDest)
echo "executables are equal: SUCCESS!"
return
copyExe(output, (i+1).thVersion)
copyExe(output, finalDest)
echo "[Warning] executables are still not equal"
# -------------- clean --------------------------------------------------------

0
lib/impure/rdstdin.nim Normal file → Executable file
View File

0
lib/pure/algorithm.nim Normal file → Executable file
View File

192
lib/pure/gentabs.nim Executable file
View File

@@ -0,0 +1,192 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## The ``gentabs`` module implements an efficient hash table that is a
## key-value mapping. The keys are required to be strings, but the values
## may be any Nimrod or user defined type. This module supports matching
## of keys in case-sensitive, case-insensitive and style-insensitive modes.
import
os, hashes, strutils
type
TGenTableMode* = enum ## describes the table's key matching mode
modeCaseSensitive, ## case sensitive matching of keys
modeCaseInsensitive, ## case insensitive matching of keys
modeStyleInsensitive ## style sensitive matching of keys
TGenKeyValuePair[T] = tuple[key: string, val: T]
TGenKeyValuePairSeq[T] = seq[TGenKeyValuePair[T]]
TGenTable*[T] = object of TObject
counter: int
data: TGenKeyValuePairSeq[T]
mode: TGenTableMode
PGenTable*[T] = ref TGenTable[T] ## use this type to declare hash tables
const
growthFactor = 2
startSize = 64
proc len*[T](tbl: PGenTable[T]): int {.inline.} =
## returns the number of keys in `tbl`.
result = tbl.counter
iterator pairs*[T](tbl: PGenTable[T]): tuple[key: string, value: T] =
## iterates over any (key, value) pair in the table `tbl`.
for h in 0..high(tbl.data):
if not isNil(tbl.data[h].key):
yield (tbl.data[h].key, tbl.data[h].val)
proc myhash[T](tbl: PGenTable[T], key: string): THash =
case tbl.mode
of modeCaseSensitive: result = hashes.hash(key)
of modeCaseInsensitive: result = hashes.hashIgnoreCase(key)
of modeStyleInsensitive: result = hashes.hashIgnoreStyle(key)
proc myCmp[T](tbl: PGenTable[T], a, b: string): bool =
case tbl.mode
of modeCaseSensitive: result = cmp(a, b) == 0
of modeCaseInsensitive: result = cmpIgnoreCase(a, b) == 0
of modeStyleInsensitive: result = cmpIgnoreStyle(a, b) == 0
proc mustRehash(length, counter: int): bool =
assert(length > counter)
result = (length * 2 < counter * 3) or (length - counter < 4)
proc newGenTable*[T](mode: TGenTableMode): PGenTable[T] =
## creates a new generic hash table that is empty.
new(result)
result.mode = mode
result.counter = 0
newSeq(result.data, startSize)
proc nextTry(h, maxHash: THash): THash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc RawGet[T](tbl: PGenTable[T], key: string): int =
var h: THash
h = myhash(tbl, key) and high(tbl.data) # start with real hash value
while not isNil(tbl.data[h].key):
if mycmp(tbl, tbl.data[h].key, key):
return h
h = nextTry(h, high(tbl.data))
result = - 1
proc RawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
key: string, val: T) =
var h: THash
h = myhash(tbl, key) and high(data)
while not isNil(data[h].key):
h = nextTry(h, high(data))
data[h].key = key
data[h].val = val
proc Enlarge[T](tbl: PGenTable[T]) =
var n: TGenKeyValuePairSeq[T]
newSeq(n, len(tbl.data) * growthFactor)
for i in countup(0, high(tbl.data)):
if not isNil(tbl.data[i].key):
RawInsert[T](tbl, n, tbl.data[i].key, tbl.data[i].val)
swap(tbl.data, n)
proc hasKey*[T](tbl: PGenTable[T], key: string): bool =
## returns true iff `key` is in the table `tbl`.
result = rawGet(tbl, key) >= 0
proc `[]`*[T](tbl: PGenTable[T], key: string): T =
## retrieves the value at ``tbl[key]``. If `key` is not in `tbl`,
## "" is returned and no exception is raised. One can check
## with ``hasKey`` whether the key exists.
var index: int
index = RawGet(tbl, key)
if index >= 0: result = tbl.data[index].val
#else: result = "" ### Not sure what to do here
proc `[]=`*[T](tbl: PGenTable[T], key: string, val: T) =
## puts a (key, value)-pair into `tbl`.
var index = RawGet(tbl, key)
if index >= 0:
tbl.data[index].val = val
else:
if mustRehash(len(tbl.data), tbl.counter): Enlarge(tbl)
RawInsert(tbl, tbl.data, key, val)
inc(tbl.counter)
when isMainModule:
#
# Verify tables of integer values (string keys)
#
var x = newGenTable[int](modeCaseInsensitive)
x["one"] = 1
x["two"] = 2
x["three"] = 3
x["four"] = 4
x["five"] = 5
assert(len(x) == 5) # length procedure works
assert(x["one"] == 1) # case-sensitive lookup works
assert(x["ONE"] == 1) # case-insensitive should work for this table
assert(x["one"]+x["two"] == 3) # make sure we're getting back ints
assert(x.hasKey("one")) # hasKey should return 'true' for a key
# of "one"...
assert(not x.hasKey("NOPE")) # ...but key "NOPE" is not in the table.
for k,v in pairs(x): # make sure the 'pairs' iterator works
assert(x[k]==v)
echo()
#
# Verify a table of user-defined types
#
type
TMyType = tuple[first, second: string] # a pair of strings
var y = newGenTable[TMyType](modeCaseInsensitive) # hash table where each
# value is TMyType tuple
#var junk: TMyType = ("OK", "Here")
y["Hello"] = ("Hello", "World")
y["Goodbye"] = ("Goodbye", "Everyone")
#y["Hello"] = TMyType( ("Hello", "World") )
#y["Goodbye"] = TMyType( ("Goodbye", "Everyone") )
assert( y["Hello"].first == "Hello" )
assert( y["Hello"].second == "World" )
#
# Verify table of tables
#
var z: PGenTable[ PGenTable[int] ] # hash table where each value is
# a hash table of ints
z = newGenTable[PGenTable[int]](modeCaseInsensitive)
z["first"] = newGenTable[int](modeCaseInsensitive)
z["first"]["one"] = 1
z["first"]["two"] = 2
z["first"]["three"] = 3
z["second"] = newGenTable[int](modeCaseInsensitive)
z["second"]["red"] = 10
z["second"]["blue"] = 20
assert(len(z) == 2) # length of outer table
assert(len(z["first"]) == 3) # length of "first" table
assert(len(z["second"]) == 2) # length of "second" table
assert( z["first"]["one"] == 1) # retrieve from first inner table
assert( z["second"]["red"] == 10) # retrieve from second inner table
for k,v in pairs(z):
echo( "$# ($#) ->" % [k,$len(v)] )
#for k2,v2 in pairs(v):
# echo( " $# <-> $#" % [k2,$v2] )
echo()

View File

@@ -708,7 +708,7 @@ else:
# environ is needed, the _NSGetEnviron() routine, defined in
# <crt_externs.h>, can be used to retrieve the address of environ
# at runtime.
proc NSGetEnviron(): cstringArray {.
proc NSGetEnviron(): ptr cstringArray {.
importc: "_NSGetEnviron", header: "<crt_externs.h>".}
else:
var gEnv {.importc: "environ".}: cstringArray
@@ -717,7 +717,7 @@ else:
# retrieves the variables of char** env of C's main proc
if not envComputed:
when defined(macosx):
var gEnv = NSGetEnviron()
var gEnv = NSGetEnviron()^
var i = 0
while True:
if gEnv[i] == nil: break

View File

@@ -75,7 +75,7 @@ type
col: int ## column the symbol has been declared/used in
flags: set[TNonTerminalFlag] ## the nonterminal's flags
rule: TNode ## the rule that the symbol refers to
TNode {.final.} = object
TNode {.final, shallow.} = object
case kind: TPegKind
of pkEmpty..pkWhitespace: nil
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string
@@ -128,10 +128,12 @@ proc add(d: var TPeg, s: TPeg) {.inline.} = add(d.sons, s)
proc addChoice(dest: var TPeg, elem: TPeg) =
var L = dest.len-1
if L >= 0 and dest.sons[L].kind == pkCharChoice:
# caution! Do not introduce false aliasing here!
case elem.kind
of pkCharChoice:
dest.sons[L].charChoice^ = dest.sons[L].charChoice^ + elem.charChoice^
of pkChar: incl(dest.sons[L].charChoice^, elem.ch)
dest.sons[L] = charSet(dest.sons[L].charChoice^ + elem.charChoice^)
of pkChar:
dest.sons[L] = charSet(dest.sons[L].charChoice^ + {elem.ch})
else: add(dest, elem)
else: add(dest, elem)
@@ -155,9 +157,12 @@ proc `/`*(a: openArray[TPeg]): TPeg {.
proc addSequence(dest: var TPeg, elem: TPeg) =
var L = dest.len-1
if L >= 0 and dest.sons[L].kind == pkTerminal:
# caution! Do not introduce false aliasing here!
case elem.kind
of pkTerminal: add(dest.sons[L].term, elem.term)
of pkChar: add(dest.sons[L].term, elem.ch)
of pkTerminal:
dest.sons[L] = term(dest.sons[L].term & elem.term)
of pkChar:
dest.sons[L] = term(dest.sons[L].term & elem.ch)
else: add(dest, elem)
else: add(dest, elem)

View File

@@ -1,14 +1,14 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
proc genericAssignAux(dest, src: Pointer, mt: PNimType)
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
proc genericAssignAux(dest, src: Pointer, mt: PNimType, shallow: bool)
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode, shallow: bool) =
var
d = cast[TAddress](dest)
s = cast[TAddress](src)
@@ -16,66 +16,69 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
of nkNone: assert(false)
of nkSlot:
genericAssignAux(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
n.typ)
n.typ, shallow)
of nkList:
for i in 0..n.len-1:
genericAssignAux(dest, src, n.sons[i])
genericAssignAux(dest, src, n.sons[i], shallow)
of nkCase:
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
n.typ.size)
var m = selectBranch(src, n)
if m != nil: genericAssignAux(dest, src, m)
if m != nil: genericAssignAux(dest, src, m, shallow)
proc genericAssignAux(dest, src: Pointer, mt: PNimType) =
proc genericAssignAux(dest, src: Pointer, mt: PNimType, shallow: bool) =
var
d = cast[TAddress](dest)
s = cast[TAddress](src)
assert(mt != nil)
case mt.Kind
of tyString:
var x = cast[ppointer](dest)
var s2 = cast[ppointer](s)^
if s2 == nil or shallow:
unsureAsgnRef(x, s2)
else:
unsureAsgnRef(x, copyString(cast[NimString](s2)))
of tySequence:
var s2 = cast[ppointer](src)^
var seq = cast[PGenericSeq](s2)
if s2 == nil: # this can happen! nil sequences are allowed
var x = cast[ppointer](dest)
x^ = nil
var seq = cast[PGenericSeq](s2)
var x = cast[ppointer](dest)
if s2 == nil or shallow:
# this can happen! nil sequences are allowed
unsureAsgnRef(x, s2)
return
assert(dest != nil)
unsureAsgnRef(cast[ppointer](dest),
newObj(mt, seq.len * mt.base.size + GenericSeqSize))
unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize))
var dst = cast[taddress](cast[ppointer](dest)^)
for i in 0..seq.len-1:
genericAssignAux(
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
cast[pointer](cast[taddress](s2) +% i *% mt.base.size +%
GenericSeqSize),
mt.Base)
mt.Base, shallow)
var dstseq = cast[PGenericSeq](dst)
dstseq.len = seq.len
dstseq.space = seq.len
of tyObject, tyTuple, tyPureObject:
# we don't need to copy m_type field for tyObject, as they are equal anyway
genericAssignAux(dest, src, mt.node)
genericAssignAux(dest, src, mt.node, shallow)
of tyArray, tyArrayConstr:
for i in 0..(mt.size div mt.base.size)-1:
genericAssignAux(cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base)
of tyString: # a leaf
var s2 = cast[ppointer](s)^
if s2 != nil: # nil strings are possible!
unsureAsgnRef(cast[ppointer](dest), copyString(cast[NimString](s2)))
else:
var x = cast[ppointer](dest)
x^ = nil
return
of tyRef: # BUGFIX: a long time this has been forgotten!
cast[pointer](s +% i*% mt.base.size), mt.base, shallow)
of tyRef:
unsureAsgnRef(cast[ppointer](dest), cast[ppointer](s)^)
else:
copyMem(dest, src, mt.size) # copy raw bits
proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
GC_disable()
genericAssignAux(dest, src, mt)
genericAssignAux(dest, src, mt, false)
GC_enable()
proc genericShallowAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
GC_disable()
genericAssignAux(dest, src, mt, true)
GC_enable()
proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
@@ -152,3 +155,19 @@ proc genericReset(dest: Pointer, mt: PNimType) =
else:
zeroMem(dest, mt.size) # set raw bits to zero
proc selectBranch(discVal, L: int,
a: ptr array [0..0x7fff, ptr TNimNode]): ptr TNimNode =
result = a[L] # a[L] contains the ``else`` part (but may be nil)
if discVal <% L:
var x = a[discVal]
if x != nil: result = x
proc FieldDiscriminantCheck(oldDiscVal, newDiscVal: int,
a: ptr array [0..0x7fff, ptr TNimNode],
L: int) {.compilerProc.} =
var oldBranch = selectBranch(oldDiscVal, L, a)
var newBranch = selectBranch(newDiscVal, L, a)
if newBranch != oldBranch and oldDiscVal != 0:
raise newException(EInvalidField,
"assignment to discriminant changes object branch")

0
lib/wrappers/readline/history.nim Normal file → Executable file
View File

0
lib/wrappers/readline/readline.nim Normal file → Executable file
View File

0
lib/wrappers/readline/rltypedefs.nim Normal file → Executable file
View File

0
lib/wrappers/readline/tweaked/history.h Normal file → Executable file
View File

0
lib/wrappers/readline/tweaked/readline.h Normal file → Executable file
View File

0
lib/wrappers/readline/tweaked/rltypedefs.h Normal file → Executable file
View File

0
lib/wrappers/readline/tweaked/tilde.h Normal file → Executable file
View File

View File

@@ -184,6 +184,26 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
appcg(p.module, p.s[cpsStmts], "#unsureAsgnRef((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)])
proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# Consider:
# type TMyFastString {.shallow.} = string
# Due to the implementation of pragmas this would end up to set the
# tfShallow flag for the built-in string type too! So we check only
# here for this flag, where it is reasonably safe to do so
# (for objects, etc.):
if needToCopy notin flags or
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
if (dest.s == OnStack) or not (optRefcGC in gGlobalOptions):
appcg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
[addrLoc(dest), addrLoc(src), rdLoc(dest)])
else:
appcg(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
else:
appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# This function replaces all other methods for generating
# the assignment operation in C.
@@ -192,13 +212,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
of tyRef:
genRefAssign(p, dest, src, flags)
of tySequence:
if not (needToCopy in flags):
if needToCopy notin flags:
genRefAssign(p, dest, src, flags)
else:
appcg(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
[addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)])
of tyString:
if not (needToCopy in flags):
if needToCopy notin flags:
genRefAssign(p, dest, src, flags)
else:
if (dest.s == OnStack) or not (optRefcGC in gGlobalOptions):
@@ -209,23 +229,15 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
else:
appcg(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
[addrLoc(dest), rdLoc(src)])
of tyTuple:
if needsComplexAssignment(dest.t):
appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
else:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyObject:
of tyTuple, tyObject:
# XXX: check for subtyping?
if needsComplexAssignment(dest.t):
appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
genGenericAsgn(p, dest, src, flags)
else:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyArray, tyArrayConstr:
if needsComplexAssignment(dest.t):
appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
genGenericAsgn(p, dest, src, flags)
else:
appcg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
@@ -363,10 +375,11 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const
opr: array[mUnaryMinusI..mAbsI64, string] = ["((NI$2)-($1))", # UnaryMinusI
"-($1)", # UnaryMinusI64
"(NI$2)abs($1)", # AbsI
"($1 > 0? ($1) : -($1))"] # AbsI64
opr: array[mUnaryMinusI..mAbsI64, string] = [
mUnaryMinusI: "((NI$2)-($1))",
mUnaryMinusI64: "-($1)",
mAbsI: "(NI$2)abs($1)",
mAbsI64: "($1 > 0? ($1) : -($1))"]
var
a: TLoc
t: PType
@@ -760,47 +773,68 @@ proc genEcho(p: BProc, n: PNode) =
appcg(p, cpsStmts, "#rawEchoNL();$n")
proc genCall(p: BProc, t: PNode, d: var TLoc) =
var
param: PSym
invalidRetType: bool
typ: PType
pl: PRope # parameter list
op, list, a: TLoc
length: int
var op, a: TLoc
# this is a hotspot in the compiler
initLocExpr(p, t.sons[0], op)
pl = con(op.r, "(") #typ := getUniqueType(t.sons[0].typ);
typ = t.sons[0].typ # getUniqueType() is too expensive here!
var pl = con(op.r, "(")
var typ = t.sons[0].typ # getUniqueType() is too expensive here!
assert(typ.kind == tyProc)
invalidRetType = isInvalidReturnType(typ.sons[0])
length = sonsLen(t)
var invalidRetType = isInvalidReturnType(typ.sons[0])
var length = sonsLen(t)
for i in countup(1, length - 1):
initLocExpr(p, t.sons[i], a) # generate expression for param
assert(sonsLen(typ) == sonsLen(typ.n))
if (i < sonsLen(typ)):
assert(typ.n.sons[i].kind == nkSym)
param = typ.n.sons[i].sym
var param = typ.n.sons[i].sym
if ccgIntroducedPtr(param): app(pl, addrLoc(a))
else: app(pl, rdLoc(a))
else:
app(pl, rdLoc(a))
if (i < length - 1) or (invalidRetType and (typ.sons[0] != nil)):
app(pl, ", ")
if (typ.sons[0] != nil) and invalidRetType:
# XXX (detected by pegs module 64bit): p(result, result) is not
# correct here. Thus we always allocate a temporary:
if d.k == locNone: getTemp(p, typ.sons[0], d)
app(pl, addrLoc(d))
app(pl, ")")
if (typ.sons[0] != nil) and not invalidRetType:
if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d:
initLoc(list, locCall, nil, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
if i < length - 1: app(pl, ", ")
if typ.sons[0] != nil:
if invalidRetType:
if length > 1: app(pl, ", ")
# beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it:
if d.k == locNone: getTemp(p, typ.sons[0], d)
app(pl, addrLoc(d))
app(pl, ")")
app(p.s[cpsStmts], pl)
app(p.s[cpsStmts], ';' & tnl)
else:
var tmp: TLoc
getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp))
app(pl, ")")
app(p.s[cpsStmts], pl)
app(p.s[cpsStmts], ';' & tnl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
app(pl, ")")
if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, nil, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
app(pl, ")")
app(p.s[cpsStmts], pl)
app(p.s[cpsStmts], ';' & tnl)
when false:
app(pl, ")")
if (typ.sons[0] != nil) and not invalidRetType:
if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d:
initLoc(list, locCall, nil, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
app(p.s[cpsStmts], pl)
app(p.s[cpsStmts], ';' & tnl)
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
# <Nimrod code>

View File

@@ -162,6 +162,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
a: TLoc
Labl: TLabel
length: int
inc(p.withinLoop)
genLineDir(p, t)
assert(sonsLen(t) == 2)
inc(p.labels)
@@ -179,6 +180,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
if p.blocks[length].id > 0: appf(p.s[cpsStmts], "} $1: ;$n", [Labl])
else: app(p.s[cpsStmts], '}' & tnl)
setlen(p.blocks, len(p.blocks) - 1)
dec(p.withinLoop)
proc genBlock(p: BProc, t: PNode, d: var TLoc) =
inc(p.labels)
@@ -619,21 +621,52 @@ proc genPragma(p: BProc, n: PNode) =
if (sfDeadCodeElim in p.module.module.flags):
addPendingModule(p.module)
else: nil
proc genAsgn(p: BProc, e: PNode) =
var a: TLoc
genLineDir(p, e) # BUGFIX
InitLocExpr(p, e.sons[0], a)
assert(a.t != nil)
expr(p, e.sons[1], a)
proc genFastAsgn(p: BProc, e: PNode) =
var a: TLoc
genLineDir(p, e) # BUGFIX
proc FieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
if optFieldCheck in p.options:
var le = asgn.sons[0]
if le.kind == nkCheckedFieldExpr:
var field = le.sons[0].sons[1].sym
result = sfDiscriminant in field.flags
elif le.kind == nkDotExpr:
var field = le.sons[1].sym
result = sfDiscriminant in field.flags
proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
field: PSym) =
var t = skipTypes(objtype, abstractVar)
assert t.kind == tyObject
discard genTypeInfo(p.module, t)
var L = lengthOrd(field.typ)
if not IntSetContainsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1",
discriminatorTableDecl(p.module, t, field))
appcg(p, cpsStmts,
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
intLiteral(L+1)])
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var a, tmp: TLoc
var dotExpr = e.sons[0]
var d: PSym
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.sons[0]
InitLocExpr(p, e.sons[0], a)
incl(a.flags, lfNoDeepCopy)
assert(a.t != nil)
expr(p, e.sons[1], a)
getTemp(p, a.t, tmp)
expr(p, e.sons[1], tmp)
genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, dotExpr.sons[1].sym)
genAssignment(p, a, tmp, {})
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
genLineDir(p, e)
if not FieldDiscriminantCheckNeeded(p, e):
var a: TLoc
InitLocExpr(p, e.sons[0], a)
if fastAsgn: incl(a.flags, lfNoDeepCopy)
assert(a.t != nil)
expr(p, e.sons[1], a)
else:
asgnFieldDiscriminant(p, e)
proc genStmts(p: BProc, t: PNode) =
var
@@ -657,8 +690,8 @@ proc genStmts(p: BProc, t: PNode) =
nkCallStrLit:
genLineDir(p, t)
initLocExpr(p, t, a)
of nkAsgn: genAsgn(p, t)
of nkFastAsgn: genFastAsgn(p, t)
of nkAsgn: genAsgn(p, t, fastAsgn=false)
of nkFastAsgn: genAsgn(p, t, fastAsgn=true)
of nkDiscardStmt:
genLineDir(p, t)
initLocExpr(p, t.sons[0], a)
@@ -684,7 +717,7 @@ proc genStmts(p: BProc, t: PNode) =
(sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
(prc.kind == skMethod):
# we have not only the header:
if (t.sons[codePos].kind != nkEmpty) or (lfDynamicLib in prc.loc.flags):
if t.sons[codePos].kind != nkEmpty or lfDynamicLib in prc.loc.flags:
genProc(p.module, prc)
else: internalError(t.info, "genStmts(" & $t.kind & ')')

View File

@@ -7,9 +7,6 @@
# distribution, for details about the copyright.
#
#var
# newDummyVar: int # just to check the symbol file mechanism
# ------------------------- Name Mangling --------------------------------
proc mangle(name: string): string =
@@ -566,46 +563,51 @@ proc genTypeInfoAux(m: BModule, typ: PType, name: PRope) =
base = toRope("0")
genTypeInfoAuxBase(m, typ, name, base)
proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
if objType.sym == nil:
InternalError(d.info, "anonymous obj with discriminator")
result = ropef("NimDT_$1_$2", [
toRope(objType.sym.name.s), toRope(d.name.s)])
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): PRope =
discard cgsym(m, "TNimNode")
var tmp = discriminatorTableName(m, objtype, d)
result = ropef("TNimNode* $1[$2];$n", [tmp, toRope(lengthOrd(d.typ)+1)])
proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
var
tmp, tmp2: PRope
length, x, y: int
field: PSym
b: PNode
case n.kind
of nkRecList:
length = sonsLen(n)
if length == 1:
var L = sonsLen(n)
if L == 1:
genObjectFields(m, typ, n.sons[0], expr)
elif length > 0:
tmp = getTempName()
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
[tmp, toRope(length)])
for i in countup(0, length - 1):
tmp2 = getNimNode(m)
elif L > 0:
var tmp = getTempName()
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, toRope(L)])
for i in countup(0, L-1):
var tmp2 = getNimNode(m)
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(i), tmp2])
genObjectFields(m, typ, n.sons[i], tmp2)
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
[expr, toRope(length), tmp])
else:
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
[expr, toRope(length)])
[expr, toRope(L), tmp])
else:
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, toRope(L)])
of nkRecCase:
length = sonsLen(n)
assert(n.sons[0].kind == nkSym)
field = n.sons[0].sym
tmp = getTempName()
var field = n.sons[0].sym
var tmp = discriminatorTableName(m, typ, field)
var L = lengthOrd(field.typ)
assert L > 0
appf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
"$1.len = $7;$n", [expr, getTypeDesc(m, typ), field.loc.r,
genTypeInfo(m, field.typ), makeCString(field.name.s),
tmp, toRope(lengthOrd(field.typ))])
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
[tmp, toRope(lengthOrd(field.typ) + 1)])
for i in countup(1, length - 1):
b = n.sons[i] # branch
tmp2 = getNimNode(m)
genTypeInfo(m, field.typ),
makeCString(field.name.s),
tmp, toRope(L)])
appf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, toRope(L+1)])
for i in countup(1, sonsLen(n)-1):
var b = n.sons[i] # branch
var tmp2 = getNimNode(m)
genObjectFields(m, typ, lastSon(b), tmp2)
case b.kind
of nkOfBranch:
@@ -613,8 +615,8 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
internalError(b.info, "genObjectFields; nkOfBranch broken")
for j in countup(0, sonsLen(b) - 2):
if b.sons[j].kind == nkRange:
x = int(getOrdValue(b.sons[j].sons[0]))
y = int(getOrdValue(b.sons[j].sons[1]))
var x = int(getOrdValue(b.sons[j].sons[0]))
var y = int(getOrdValue(b.sons[j].sons[1]))
while x <= y:
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, toRope(x), tmp2])
inc(x)
@@ -623,10 +625,10 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
[tmp, toRope(getOrdValue(b.sons[j])), tmp2])
of nkElse:
appf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
[tmp, toRope(lengthOrd(field.typ)), tmp2])
[tmp, toRope(L), tmp2])
else: internalError(n.info, "genObjectFields(nkRecCase)")
of nkSym:
field = n.sym
var field = n.sym
appf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n", [expr, getTypeDesc(m, typ),
@@ -634,10 +636,9 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
else: internalError(n.info, "genObjectFields")
proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
var tmp: PRope
if typ.kind == tyObject: genTypeInfoAux(m, typ, name)
else: genTypeInfoAuxBase(m, typ, name, toRope("0"))
tmp = getNimNode(m)
var tmp = getNimNode(m)
genObjectFields(m, typ, typ.n, tmp)
appf(m.s[cfsTypeInit3], "$1->node = &$2;$n", [name, tmp])
@@ -742,21 +743,15 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
[result, toRope(typeToString(t))])
if dataGenerated: return
case t.kind
of tyEmpty:
result = toRope("0")
of tyEmpty: result = toRope("0")
of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyFloat128,
tyVar:
genTypeInfoAuxBase(gNimDat, t, result, toRope("0"))
of tyRef, tyPtr, tySequence, tyRange:
genTypeInfoAux(gNimDat, t, result)
of tyArrayConstr, tyArray:
genArrayInfo(gNimDat, t, result)
of tySet:
genSetInfo(gNimDat, t, result)
of tyEnum:
genEnumInfo(gNimDat, t, result)
of tyObject:
genObjectInfo(gNimDat, t, result)
of tyRef, tyPtr, tySequence, tyRange: genTypeInfoAux(gNimDat, t, result)
of tyArrayConstr, tyArray: genArrayInfo(gNimDat, t, result)
of tySet: genSetInfo(gNimDat, t, result)
of tyEnum: genEnumInfo(gNimDat, t, result)
of tyObject: genObjectInfo(gNimDat, t, result)
of tyTuple:
if t.n != nil: genObjectInfo(gNimDat, t, result)
else: genTupleInfo(gNimDat, t, result)

View File

@@ -77,6 +77,7 @@ type
sendClosure: PType # closure record type that we pass
receiveClosure: PType # closure record type that we get
module: BModule # used to prevent excessive parameter passing
withinLoop: int # > 0 if we are within a loop
TTypeSeq = seq[PType]
TCGen = object of TPassContext # represents a C source file
@@ -131,8 +132,7 @@ proc addPendingModule(m: BModule) =
proc findPendingModule(m: BModule, s: PSym): BModule =
var ms = getModule(s)
if ms.id == m.module.id:
return m
if ms.id == m.module.id: return m
for i in countup(0, high(gPendingModules)):
result = gPendingModules[i]
if result.module.id == ms.id: return
@@ -231,6 +231,9 @@ proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
args: openarray[PRope]) =
app(c, ropecg(m, frmt, args))
proc appcg(m: BModule, s: TCFileSection, frmt: TFormatStr,
args: openarray[PRope]) =
app(m.s[s], ropecg(m, frmt, args))
proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: openarray[PRope]) =
@@ -248,7 +251,7 @@ proc rdLoc(a: TLoc): PRope =
proc addrLoc(a: TLoc): PRope =
result = a.r
if not (lfIndirect in a.flags): result = con("&", result)
if lfIndirect notin a.flags: result = con("&", result)
proc rdCharLoc(a: TLoc): PRope =
# read a location that may need a char-cast:
@@ -285,7 +288,7 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) =
if skipTypes(loc.t, abstractVarRange).Kind notin
{tyArray, tyArrayConstr, tySet, tyTuple, tyObject}:
if containsGcref:
if containsGcref and p.WithInLoop > 0:
appf(p.s[cpsInit], "$1 = 0;$n", [rdLoc(loc)])
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, onStack)
@@ -295,7 +298,7 @@ proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) =
else:
appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
else:
if containsGcref:
if containsGcref and p.WithInLoop > 0:
appf(p.s[cpsInit], "memset((void*)$1, 0, sizeof($2));$n",
[addrLoc(loc), rdLoc(loc)])
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",

View File

@@ -200,12 +200,12 @@ proc ProcessSpecificNote(arg: string, state: TSpecialWord, pass: TCmdlinePass,
var id = "" # arg = "X]:on|off"
var i = 0
var n = hintMin
while (i < len(arg) + 0) and (arg[i] != ']'):
while i < len(arg) and (arg[i] != ']'):
add(id, arg[i])
inc(i)
if (i < len(arg) + 0) and (arg[i] == ']'): inc(i)
if i < len(arg) and (arg[i] == ']'): inc(i)
else: InvalidCmdLineOption(pass, arg, info)
if (i < len(arg) + 0) and (arg[i] in {':', '='}): inc(i)
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
else: InvalidCmdLineOption(pass, arg, info)
if state == wHint:
var x = findStr(msgs.HintsToStr, id)

View File

@@ -432,7 +432,7 @@ proc matchesHyperlink(h: PRstNode, filename: string): bool =
result = matchesHyperlink(h.sons[0], filename)
elif h.kind == rnHyperlink:
var s = addNodes(h.sons[1])
if startsWith(s, filename) and (s[len(filename) + 0] == '#'): result = true
if startsWith(s, filename) and (s[len(filename)] == '#'): result = true
else: result = false
else:
result = false

0
rod/semcall.nim Normal file → Executable file
View File

View File

@@ -412,10 +412,8 @@ proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
flags: TExprFlags): PNode =
var symflags = {skProc, skMethod, skConverter}
if efWantIterator in flags:
symflags = {skIterator}
elif efAllowType in flags:
# for ``type countup(1,3)``, see ``tests/ttoseq``.
symflags.incl(skIterator)
symflags = {skIterator}
result = semDirectCall(c, n, symflags)
if result != nil:
if result.sons[0].kind != nkSym:
@@ -571,7 +569,6 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
check: var PNode): PSym =
# transform in a node that contains the runtime check for the
# field, if it is in a case-part...
var s, it, inExpr, notExpr: PNode
result = nil
case r.kind
of nkRecList:
@@ -583,9 +580,9 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
if (r.sons[0].kind != nkSym): IllFormedAst(r)
result = lookupInRecordAndBuildCheck(c, n, r.sons[0], field, check)
if result != nil: return
s = newNodeI(nkCurly, r.info)
var s = newNodeI(nkCurly, r.info)
for i in countup(1, sonsLen(r) - 1):
it = r.sons[i]
var it = r.sons[i]
case it.kind
of nkOfBranch:
result = lookupInRecordAndBuildCheck(c, n, lastSon(it), field, check)
@@ -597,7 +594,7 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
addSon(check, ast.emptyNode) # make space for access node
s = newNodeI(nkCurly, n.info)
for j in countup(0, sonsLen(it) - 2): addSon(s, copyTree(it.sons[j]))
inExpr = newNodeI(nkCall, n.info)
var inExpr = newNodeI(nkCall, n.info)
addSon(inExpr, newIdentNode(getIdent("in"), n.info))
addSon(inExpr, copyTree(r.sons[0]))
addSon(inExpr, s) #writeln(output, renderTree(inExpr));
@@ -609,11 +606,11 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
if check == nil:
check = newNodeI(nkCheckedFieldExpr, n.info)
addSon(check, ast.emptyNode) # make space for access node
inExpr = newNodeI(nkCall, n.info)
var inExpr = newNodeI(nkCall, n.info)
addSon(inExpr, newIdentNode(getIdent("in"), n.info))
addSon(inExpr, copyTree(r.sons[0]))
addSon(inExpr, s)
notExpr = newNodeI(nkCall, n.info)
var notExpr = newNodeI(nkCall, n.info)
addSon(notExpr, newIdentNode(getIdent("not"), n.info))
addSon(notExpr, inExpr)
addSon(check, semExpr(c, notExpr))

View File

@@ -152,7 +152,7 @@ proc transformToExpr(n: PNode): PNode =
if realStmt >= 0: result = transformToExpr(n.sons[realStmt])
else: n.kind = nkStmtListExpr
of nkBlockStmt:
n.kind = nkBlockExpr
n.kind = nkBlockExpr
#nkIfStmt: n.kind := nkIfExpr; // this is not correct!
else:
nil

View File

@@ -574,8 +574,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
case n.kind
of nkEmpty: nil
of nkTypeOfExpr:
# for ``type countup(1,3)``, see ``tests/ttoseq``.
# XXX We should find a better solution.
checkSonsLen(n, 1)
result = semExprWithType(c, n.sons[0], {efAllowType}).typ
result = semExprWithType(c, n.sons[0], {efWantIterator}).typ
of nkPar:
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
else: GlobalError(n.info, errTypeExpected)

0
rod/semtypinst.nim Normal file → Executable file
View File

0
rod/suggest.nim Normal file → Executable file
View File

0
tests/accept/compile/tfib.nim Normal file → Executable file
View File

View File

@@ -0,0 +1,24 @@
import strutils
var x = 343
case stdin.readline.parseInt
of 0:
echo "most common case"
of 1:
{.linearScanEnd.}
echo "second most common case"
of 2: echo "unlikely: use branch table"
else:
echo "unlikely too: use branch table"
case x
of 23: echo "23"
of 343: echo "343"
of 21: echo "21"
else:
{.linearScanEnd.}
echo "default"

0
tests/accept/compile/tmacro1.nim Normal file → Executable file
View File

0
tests/accept/compile/tsortdev.nim Normal file → Executable file
View File

View File

@@ -0,0 +1,6 @@
converter p(i: int): bool = return i != 0
if 0:
echo "foo"

0
tests/accept/run/tmacro2.nim Normal file → Executable file
View File

0
tests/accept/run/tmacro3.nim Normal file → Executable file
View File

0
tests/accept/run/tmacros1.nim Normal file → Executable file
View File

1769
tests/accept/run/tpegs.nim Executable file

File diff suppressed because it is too large Load Diff

0
tests/accept/run/tsort.nim Normal file → Executable file
View File

0
tests/accept/run/ttoseq.nim Normal file → Executable file
View File

5
tests/gc/gcleak.nim Normal file → Executable file
View File

@@ -5,7 +5,10 @@ type
proc MakeObj(): TTestObj =
result.x = "Hello"
while true:
for i in 1 .. 100_000_000:
var obj = MakeObj()
if getOccupiedMem() > 300_000: quit("still a leak!")
# echo GC_getstatistics()
echo "no leak: ", getOccupiedMem()

9
tests/gc/gcleak2.nim Normal file → Executable file
View File

@@ -7,14 +7,13 @@ proc MakeObj(): TTestObj =
result.x = "Hello"
result.s = @[1,2,3]
#while true:
# var obj = MakeObj()
# echo GC_getstatistics()
proc inProc() =
while true:
for i in 1 .. 100_000_000:
var obj: TTestObj
obj = MakeObj()
if getOccupiedMem() > 300_000: quit("still a leak!")
inProc()
echo "no leak: ", getOccupiedMem()

0
tests/reject/ttypenoval.nim Normal file → Executable file
View File

View File

@@ -22,11 +22,13 @@ High priority (version 0.9.0)
Bugs
----
- proc (x: int) is passable to proc (x: var int) !?
- detected by pegs module 64bit: p(result, result) should use a temporary!
- the parser allows empty object case branches
- Exception matching needs to take subclasses into account
- pegs: the anchor '^' does not work because many procs use a linear search
and matchLen()
- BUG: generic assign still buggy
- Optimization: If we use a temporary for the result anyway the code gen
should make use of this fact to generate better code...
To implement
@@ -51,18 +53,13 @@ Low priority
- find a way to reintroduce the cleanup() pass for C code generation: this
is hard because of partial evaluation --> symbol files will fix this as
a side effect
- implement better error handling: errornous top level statements are ignored
and not part of the symbal table --> for REPL
--> this needs deletion operation for symbol table!
- floating point checks for EcmaScript
- enhance `` notation for identifier concatenation: `concat` a `these`
- prefer proc in current module over other procs with same overloading result?
- real types for template results
- generalized case statement (requires better transf)
- normalize for the DOM
- tlastmod returns wrong results on BSD (Linux, MacOS X: works)
- nested tuple unpacking
- fast assignment optimization for TPeg
- nested tuple unpacking; no auto-unpacking in 'for' loops!
- better error messages for used keywords as identifiers
- case statement branches should support constant sets

0
tools/nimgrep.cfg Normal file → Executable file
View File

View File

@@ -66,7 +66,7 @@ Additions
- Added ``math.floor``.
- The *interactive mode* (REPL) has been improved and documented for the
first time.
- Added the ``linearScanEnd`` and ``unroll`` pragmas.
- Added the ``linearScanEnd``, ``unroll``, ``shallow`` pragmas.
- The compiler now might use a hashing for string case statements depending
on the number of string literals in the case statement.