mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-13 06:43:52 +00:00
linearScanEnd pragma; string case statement optimization
This commit is contained in:
10
build.bat
10
build.bat
@@ -123,6 +123,10 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/procfind.c -o build/1_1/procfind.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/procfind.c -o build/1_1/procfind.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/pragmas.c -o build/1_1/pragmas.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/pragmas.c -o build/1_1/pragmas.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/semtypinst.c -o build/1_1/semtypinst.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/semtypinst.c -o build/1_1/semtypinst.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/sigmatch.c -o build/1_1/sigmatch.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/sigmatch.c -o build/1_1/sigmatch.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/suggest.c -o build/1_1/suggest.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/suggest.c -o build/1_1/suggest.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/docgen.c -o build/1_1/docgen.o
|
||||
@@ -139,8 +143,6 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/cgmeth.c -o build/1_1/cgmeth.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/cgmeth.c -o build/1_1/cgmeth.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/ecmasgen.c -o build/1_1/ecmasgen.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/ecmasgen.c -o build/1_1/ecmasgen.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/interact.c -o build/1_1/interact.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/interact.c -o build/1_1/interact.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/passaux.c -o build/1_1/passaux.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/passaux.c -o build/1_1/passaux.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/depends.c -o build/1_1/depends.o
|
||||
@@ -150,8 +152,8 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/transf.c -o build/1_1/transf.o
|
||||
ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o
|
||||
%CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o
|
||||
|
||||
ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
|
||||
%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
|
||||
ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/semtypinst.o build/1_1/sigmatch.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
|
||||
%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/semtypinst.o build/1_1/sigmatch.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o
|
||||
|
||||
ECHO SUCCESS
|
||||
|
||||
|
||||
@@ -2646,6 +2646,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.
|
||||
|
||||
|
||||
compilation option pragmas
|
||||
|
||||
@@ -293,10 +293,26 @@ However it is not efficient to do:
|
||||
.. code-block:: Nimrod
|
||||
var s = varA # assignment has to copy the whole string into a new buffer!
|
||||
|
||||
..
|
||||
String case statements are optimized too. A hashing scheme is used for them
|
||||
if several different string constants are used. This is likely to be more
|
||||
efficient than any hand-coded scheme.
|
||||
The compiler optimizes string case statements: A hashing scheme is used for them
|
||||
if several different string constants are used. So code like this is reasonably
|
||||
efficient:
|
||||
|
||||
.. code-block:: Nimrod
|
||||
case normalize(k.key)
|
||||
of "name": c.name = v
|
||||
of "displayname": c.displayName = v
|
||||
of "version": c.version = v
|
||||
of "os": c.oses = split(v, {';'})
|
||||
of "cpu": c.cpus = split(v, {';'})
|
||||
of "authors": c.authors = split(v, {';'})
|
||||
of "description": c.description = v
|
||||
of "app":
|
||||
case normalize(v)
|
||||
of "console": c.app = appConsole
|
||||
of "gui": c.app = appGUI
|
||||
else: quit(errorStr(p, "expected: console or gui"))
|
||||
of "license": c.license = UnixToNativePath(k.value)
|
||||
else: quit(errorStr(p, "unknown variable: " & k.key))
|
||||
|
||||
|
||||
..
|
||||
|
||||
@@ -88,8 +88,6 @@ if [ $# -eq 1 ] ; then
|
||||
chmod 644 $docdir/abstypes.txt
|
||||
cp doc/advopt.txt $docdir/advopt.txt || exit 1
|
||||
chmod 644 $docdir/advopt.txt
|
||||
cp doc/altsyn.txt $docdir/altsyn.txt || exit 1
|
||||
chmod 644 $docdir/altsyn.txt
|
||||
cp doc/apis.txt $docdir/apis.txt || exit 1
|
||||
chmod 644 $docdir/apis.txt
|
||||
cp doc/astspec.txt $docdir/astspec.txt || exit 1
|
||||
@@ -330,6 +328,8 @@ if [ $# -eq 1 ] ; then
|
||||
chmod 644 $libdir/core/marshal.nim
|
||||
cp lib/core/threads.nim $libdir/core/threads.nim || exit 1
|
||||
chmod 644 $libdir/core/threads.nim
|
||||
cp lib/pure/algorithm.nim $libdir/pure/algorithm.nim || exit 1
|
||||
chmod 644 $libdir/pure/algorithm.nim
|
||||
cp lib/pure/base64.nim $libdir/pure/base64.nim || exit 1
|
||||
chmod 644 $libdir/pure/base64.nim
|
||||
cp lib/pure/browsers.nim $libdir/pure/browsers.nim || exit 1
|
||||
@@ -344,6 +344,8 @@ if [ $# -eq 1 ] ; then
|
||||
chmod 644 $libdir/pure/cookies.nim
|
||||
cp lib/pure/dynlib.nim $libdir/pure/dynlib.nim || exit 1
|
||||
chmod 644 $libdir/pure/dynlib.nim
|
||||
cp lib/pure/gentabs.nim $libdir/pure/gentabs.nim || exit 1
|
||||
chmod 644 $libdir/pure/gentabs.nim
|
||||
cp lib/pure/hashes.nim $libdir/pure/hashes.nim || exit 1
|
||||
chmod 644 $libdir/pure/hashes.nim
|
||||
cp lib/pure/htmlparser.nim $libdir/pure/htmlparser.nim || exit 1
|
||||
|
||||
@@ -406,14 +406,16 @@ proc ParseInt*(s: string): int {.noSideEffect, procvar,
|
||||
## Parses a decimal integer value contained in `s`. If `s` is not
|
||||
## a valid integer, `EInvalidValue` is raised.
|
||||
var L = parseutils.parseInt(s, result, 0)
|
||||
if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(EInvalidValue, "invalid integer: " & s)
|
||||
|
||||
proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuParseBiggestInt".} =
|
||||
## Parses a decimal integer value contained in `s`. If `s` is not
|
||||
## a valid integer, `EInvalidValue` is raised.
|
||||
var L = parseutils.parseBiggestInt(s, result, 0)
|
||||
if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(EInvalidValue, "invalid integer: " & s)
|
||||
|
||||
proc ParseFloat*(s: string): float {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuParseFloat".} =
|
||||
@@ -421,7 +423,8 @@ proc ParseFloat*(s: string): float {.noSideEffect, procvar,
|
||||
## a valid floating point number, `EInvalidValue` is raised. ``NAN``,
|
||||
## ``INF``, ``-INF`` are also supported (case insensitive comparison).
|
||||
var L = parseutils.parseFloat(s, result, 0)
|
||||
if L != s.len: raise newException(EInvalidValue, "invalid float: " & s)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(EInvalidValue, "invalid float: " & s)
|
||||
|
||||
proc ParseHexInt*(s: string): int {.noSideEffect, procvar,
|
||||
rtl, extern: "nsuParseHexInt".} =
|
||||
|
||||
@@ -1198,12 +1198,12 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
|
||||
|
||||
# ----------------- GC interface ---------------------------------------------
|
||||
|
||||
proc GC_disable*() {.rtl.}
|
||||
proc GC_disable*() {.rtl, inl.}
|
||||
## disables the GC. If called n-times, n calls to `GC_enable` are needed to
|
||||
## reactivate the GC. Note that in most circumstances one should only disable
|
||||
## the mark and sweep phase with `GC_disableMarkAndSweep`.
|
||||
|
||||
proc GC_enable*() {.rtl.}
|
||||
proc GC_enable*() {.rtl, inl.}
|
||||
## enables the GC again.
|
||||
|
||||
proc GC_fullCollect*() {.rtl.}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
#when defined(debugGC):
|
||||
# {.define: logAssign.}
|
||||
proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.}
|
||||
proc genericAssignAux(dest, src: Pointer, mt: PNimType)
|
||||
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
|
||||
var
|
||||
d = cast[TAddress](dest)
|
||||
@@ -17,8 +15,8 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
|
||||
case n.kind
|
||||
of nkNone: assert(false)
|
||||
of nkSlot:
|
||||
genericAssign(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
|
||||
n.typ)
|
||||
genericAssignAux(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
|
||||
n.typ)
|
||||
of nkList:
|
||||
for i in 0..n.len-1:
|
||||
genericAssignAux(dest, src, n.sons[i])
|
||||
@@ -28,7 +26,7 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
|
||||
var m = selectBranch(src, n)
|
||||
if m != nil: genericAssignAux(dest, src, m)
|
||||
|
||||
proc genericAssign(dest, src: Pointer, mt: PNimType) =
|
||||
proc genericAssignAux(dest, src: Pointer, mt: PNimType) =
|
||||
var
|
||||
d = cast[TAddress](dest)
|
||||
s = cast[TAddress](src)
|
||||
@@ -47,7 +45,7 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
|
||||
newObj(mt, seq.len * mt.base.size + GenericSeqSize))
|
||||
var dst = cast[taddress](cast[ppointer](dest)^)
|
||||
for i in 0..seq.len-1:
|
||||
genericAssign(
|
||||
genericAssignAux(
|
||||
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
|
||||
cast[pointer](cast[taddress](s2) +% i *% mt.base.size +%
|
||||
GenericSeqSize),
|
||||
@@ -60,8 +58,8 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
|
||||
genericAssignAux(dest, src, mt.node)
|
||||
of tyArray, tyArrayConstr:
|
||||
for i in 0..(mt.size div mt.base.size)-1:
|
||||
genericAssign(cast[pointer](d +% i*% mt.base.size),
|
||||
cast[pointer](s +% i*% mt.base.size), mt.base)
|
||||
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!
|
||||
@@ -75,6 +73,11 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
|
||||
else:
|
||||
copyMem(dest, src, mt.size) # copy raw bits
|
||||
|
||||
proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
|
||||
GC_disable()
|
||||
genericAssignAux(dest, src, mt)
|
||||
GC_enable()
|
||||
|
||||
proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
|
||||
var src = src # ugly, but I like to stress the parser sometimes :-)
|
||||
genericAssign(dest, addr(src), mt)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# Nimrod's Runtime Library
|
||||
# (c) Copyright 2010 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
|
||||
@@ -269,7 +269,8 @@ type
|
||||
tfNoSideEffect, # procedure type does not allow side effects
|
||||
tfFinal, # is the object final?
|
||||
tfAcyclic, # type is acyclic (for GC optimization)
|
||||
tfEnumHasWholes # enum cannot be mapped into a range
|
||||
tfEnumHasWholes, # enum cannot be mapped into a range
|
||||
tfShallow # type can be shallow copied on assignment
|
||||
|
||||
TTypeFlags* = set[TTypeFlag]
|
||||
|
||||
|
||||
@@ -215,6 +215,13 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
|
||||
else:
|
||||
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
|
||||
of 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)])
|
||||
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",
|
||||
@@ -223,12 +230,6 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
appcg(p, cpsStmts,
|
||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
|
||||
[rdLoc(dest), rdLoc(src)])
|
||||
of 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)])
|
||||
else:
|
||||
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
|
||||
of tyOpenArray:
|
||||
# open arrays are always on the stack - really? What if a sequence is
|
||||
# passed to an open array?
|
||||
|
||||
195
rod/ccgstmts.nim
195
rod/ccgstmts.nim
@@ -10,6 +10,10 @@
|
||||
const
|
||||
RangeExpandLimit = 256 # do not generate ranges
|
||||
# over 'RangeExpandLimit' elements
|
||||
stringCaseThreshold = 8
|
||||
# above X strings a hash-switch for strings is generated
|
||||
# this version sets it too high to avoid hashing, because this has not
|
||||
# been tested for a long time
|
||||
|
||||
proc genLineDir(p: BProc, t: PNode) =
|
||||
var line = toLinenumber(t.info) # BUGFIX
|
||||
@@ -229,13 +233,6 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
else:
|
||||
appcg(p, cpsStmts, "#reraiseException();" & tnl)
|
||||
|
||||
const
|
||||
stringCaseThreshold = 100000
|
||||
# above X strings a hash-switch for strings is generated
|
||||
# this version sets it too high to avoid hashing, because this has not
|
||||
# been tested for a long time
|
||||
# XXX test and enable this optimization!
|
||||
|
||||
proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||
rangeFormat, eqFormat: TFormatStr, labl: TLabel) =
|
||||
var
|
||||
@@ -251,90 +248,68 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||
initLocExpr(p, b.sons[i], x)
|
||||
appcg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
|
||||
|
||||
proc genCaseSecondPass(p: BProc, t: PNode, labId: int) =
|
||||
proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel =
|
||||
var Lend = getLabel(p)
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
for i in 1..until:
|
||||
appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(labId + i)])
|
||||
if t.sons[i].kind == nkOfBranch: # else statement
|
||||
if t.sons[i].kind == nkOfBranch:
|
||||
var length = sonsLen(t.sons[i])
|
||||
genStmts(p, t.sons[i].sons[length - 1])
|
||||
appf(p.s[cpsStmts], "goto $1;$n", [Lend])
|
||||
else:
|
||||
genStmts(p, t.sons[i].sons[0])
|
||||
fixLabel(p, Lend)
|
||||
result = Lend
|
||||
|
||||
proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) =
|
||||
proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr,
|
||||
until: int, a: TLoc): TLabel =
|
||||
# generate a C-if statement for a Nimrod case statement
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[0], a) # fist pass: generate ifs+goto:
|
||||
var labId = p.labels
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
for i in 1..until:
|
||||
inc(p.labels)
|
||||
if t.sons[i].kind == nkOfBranch: # else statement
|
||||
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
|
||||
con("LA", toRope(p.labels)))
|
||||
else:
|
||||
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)])
|
||||
genCaseSecondPass(p, t, labId)
|
||||
if until < t.len-1:
|
||||
inc(p.labels)
|
||||
var gotoTarget = p.labels
|
||||
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(gotoTarget)])
|
||||
result = genCaseSecondPass(p, t, labId, until)
|
||||
appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(gotoTarget)])
|
||||
else:
|
||||
result = genCaseSecondPass(p, t, labId, until)
|
||||
|
||||
proc hashString(s: string): biggestInt =
|
||||
var
|
||||
a: int32
|
||||
b: int64
|
||||
if CPU[targetCPU].bit == 64:
|
||||
# we have to use the same bitwidth
|
||||
# as the target CPU
|
||||
b = 0
|
||||
for i in countup(0, len(s) - 1):
|
||||
b = b +% Ord(s[i])
|
||||
b = b +% `shl`(b, 10)
|
||||
b = b xor `shr`(b, 6)
|
||||
b = b +% `shl`(b, 3)
|
||||
b = b xor `shr`(b, 11)
|
||||
b = b +% `shl`(b, 15)
|
||||
result = b
|
||||
else:
|
||||
a = 0
|
||||
for i in countup(0, len(s) - 1):
|
||||
a = a +% int32(Ord(s[i]))
|
||||
a = a +% `shl`(a, int32(10))
|
||||
a = a xor `shr`(a, int32(6))
|
||||
a = a +% `shl`(a, int32(3))
|
||||
a = a xor `shr`(a, int32(11))
|
||||
a = a +% `shl`(a, int32(15))
|
||||
result = a
|
||||
|
||||
type
|
||||
TRopeSeq = seq[PRope]
|
||||
proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[0], a)
|
||||
var Lend = genIfForCaseUntil(p, t, rangeFormat, eqFormat, sonsLen(t)-1, a)
|
||||
fixLabel(p, Lend)
|
||||
|
||||
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
branches: var TRopeSeq) =
|
||||
var
|
||||
length, j: int
|
||||
x: TLoc
|
||||
length = sonsLen(b)
|
||||
branches: var openArray[PRope]) =
|
||||
var x: TLoc
|
||||
var length = sonsLen(b)
|
||||
for i in countup(0, length - 2):
|
||||
assert(b.sons[i].kind != nkRange)
|
||||
initLocExpr(p, b.sons[i], x)
|
||||
assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
|
||||
j = int(hashString(b.sons[i].strVal) and high(branches))
|
||||
var j = int(hashString(b.sons[i].strVal) and high(branches))
|
||||
appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
|
||||
[rdLoc(e), rdLoc(x), labl])
|
||||
|
||||
proc genStringCase(p: BProc, t: PNode) =
|
||||
var
|
||||
strings, bitMask, labId: int
|
||||
a: TLoc
|
||||
branches: TRopeSeq
|
||||
# count how many constant strings there are in the case:
|
||||
strings = 0
|
||||
var strings = 0
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
|
||||
if strings > stringCaseThreshold:
|
||||
bitMask = math.nextPowerOfTwo(strings) - 1
|
||||
var bitMask = math.nextPowerOfTwo(strings) - 1
|
||||
var branches: seq[PRope]
|
||||
newSeq(branches, bitMask + 1)
|
||||
var a: TLoc
|
||||
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
|
||||
labId = p.labels
|
||||
var labId = p.labels
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
inc(p.labels)
|
||||
if t.sons[i].kind == nkOfBranch:
|
||||
@@ -353,67 +328,72 @@ proc genStringCase(p: BProc, t: PNode) =
|
||||
if t.sons[sonsLen(t) - 1].kind != nkOfBranch:
|
||||
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)])
|
||||
# third pass: generate statements
|
||||
genCaseSecondPass(p, t, labId)
|
||||
var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1)
|
||||
fixLabel(p, Lend)
|
||||
else:
|
||||
genCaseGeneric(p, t, "", "if (#eqStrings($1, $2)) goto $3;$n")
|
||||
|
||||
proc branchHasTooBigRange(b: PNode): bool =
|
||||
for i in countup(0, sonsLen(b) - 2):
|
||||
for i in countup(0, sonsLen(b)-2):
|
||||
# last son is block
|
||||
if (b.sons[i].Kind == nkRange) and
|
||||
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc genOrdinalCase(p: BProc, t: PNode) =
|
||||
# We analyse if we have a too big switch range. If this is the case,
|
||||
# we generate an ordinary if statement and rely on the C compiler
|
||||
# to produce good code.
|
||||
var
|
||||
canGenerateSwitch, hasDefault: bool
|
||||
length: int
|
||||
a: TLoc
|
||||
v: PNode
|
||||
canGenerateSwitch = true
|
||||
if not (hasSwitchRange in CC[ccompiler].props):
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
if (t.sons[i].kind == nkOfBranch) and branchHasTooBigRange(t.sons[i]):
|
||||
canGenerateSwitch = false
|
||||
break
|
||||
if canGenerateSwitch:
|
||||
initLocExpr(p, t.sons[0], a)
|
||||
proc IfSwitchSplitPoint(p: BProc, n: PNode): int =
|
||||
for i in 1..n.len-1:
|
||||
var branch = n[i]
|
||||
var stmtBlock = lastSon(branch)
|
||||
if stmtBlock.stmtsContainPragma(wLinearScanEnd):
|
||||
result = i
|
||||
elif hasSwitchRange notin CC[ccompiler].props:
|
||||
if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
|
||||
result = i
|
||||
|
||||
proc genOrdinalCase(p: BProc, n: PNode) =
|
||||
# analyse 'case' statement:
|
||||
var splitPoint = IfSwitchSplitPoint(p, n)
|
||||
|
||||
# generate if part (might be empty):
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
var Lend = if splitPoint > 0: genIfForCaseUntil(p, n,
|
||||
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
|
||||
eqFormat = "if ($1 == $2) goto $3;$n",
|
||||
splitPoint, a) else: nil
|
||||
|
||||
# generate switch part (might be empty):
|
||||
if splitPoint+1 < n.len:
|
||||
appf(p.s[cpsStmts], "switch ($1) {$n", [rdCharLoc(a)])
|
||||
hasDefault = false
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
if t.sons[i].kind == nkOfBranch:
|
||||
length = sonsLen(t.sons[i])
|
||||
for j in countup(0, length - 2):
|
||||
if t.sons[i].sons[j].kind == nkRange:
|
||||
# a range
|
||||
var hasDefault = false
|
||||
for i in splitPoint+1 .. < n.len:
|
||||
var branch = n[i]
|
||||
if branch.kind == nkOfBranch:
|
||||
var length = branch.len
|
||||
for j in 0 .. length-2:
|
||||
if branch[j].kind == nkRange:
|
||||
if hasSwitchRange in CC[ccompiler].props:
|
||||
appf(p.s[cpsStmts], "case $1 ... $2:$n", [
|
||||
genLiteral(p, t.sons[i].sons[j].sons[0]),
|
||||
genLiteral(p, t.sons[i].sons[j].sons[1])])
|
||||
genLiteral(p, branch[j][0]),
|
||||
genLiteral(p, branch[j][1])])
|
||||
else:
|
||||
v = copyNode(t.sons[i].sons[j].sons[0])
|
||||
while (v.intVal <= t.sons[i].sons[j].sons[1].intVal):
|
||||
var v = copyNode(branch[j][0])
|
||||
while v.intVal <= branch[j][1].intVal:
|
||||
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, v)])
|
||||
Inc(v.intVal)
|
||||
else:
|
||||
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, t.sons[i].sons[j])])
|
||||
genStmts(p, t.sons[i].sons[length - 1])
|
||||
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, branch[j])])
|
||||
genStmts(p, branch[length-1])
|
||||
else:
|
||||
# else part of case statement:
|
||||
app(p.s[cpsStmts], "default:" & tnl)
|
||||
genStmts(p, t.sons[i].sons[0])
|
||||
genStmts(p, branch[0])
|
||||
hasDefault = true
|
||||
app(p.s[cpsStmts], "break;" & tnl)
|
||||
if (hasAssume in CC[ccompiler].props) and not hasDefault:
|
||||
app(p.s[cpsStmts], "default: __assume(0);" & tnl)
|
||||
app(p.s[cpsStmts], '}' & tnl)
|
||||
else:
|
||||
genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
|
||||
"if ($1 == $2) goto $3;$n")
|
||||
if Lend != nil: fixLabel(p, Lend)
|
||||
|
||||
proc genCaseStmt(p: BProc, t: PNode) =
|
||||
genLineDir(p, t)
|
||||
@@ -424,7 +404,6 @@ proc genCaseStmt(p: BProc, t: PNode) =
|
||||
genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
|
||||
"if ($1 == $2) goto $3;$n")
|
||||
else:
|
||||
# ordinal type: generate a switch statement
|
||||
genOrdinalCase(p, t)
|
||||
|
||||
proc hasGeneralExceptSection(t: PNode): bool =
|
||||
@@ -629,19 +608,17 @@ proc genBreakPoint(p: BProc, t: PNode) =
|
||||
proc genPragma(p: BProc, n: PNode) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
||||
if key.kind == nkIdent:
|
||||
case whichKeyword(key.ident)
|
||||
of wEmit:
|
||||
genEmit(p, it)
|
||||
of wBreakpoint:
|
||||
genBreakPoint(p, it)
|
||||
of wDeadCodeElim:
|
||||
if not (optDeadCodeElim in gGlobalOptions):
|
||||
# we need to keep track of ``deadCodeElim`` pragma
|
||||
if (sfDeadCodeElim in p.module.module.flags):
|
||||
addPendingModule(p.module)
|
||||
else: nil
|
||||
case whichPragma(it)
|
||||
of wEmit:
|
||||
genEmit(p, it)
|
||||
of wBreakpoint:
|
||||
genBreakPoint(p, it)
|
||||
of wDeadCodeElim:
|
||||
if not (optDeadCodeElim in gGlobalOptions):
|
||||
# we need to keep track of ``deadCodeElim`` pragma
|
||||
if (sfDeadCodeElim in p.module.module.flags):
|
||||
addPendingModule(p.module)
|
||||
else: nil
|
||||
|
||||
proc genAsgn(p: BProc, e: PNode) =
|
||||
var a: TLoc
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2009 Andreas Rumpf
|
||||
# (c) Copyright 2011 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
@@ -10,21 +10,58 @@
|
||||
# This module declares some helpers for the C code generator.
|
||||
|
||||
import
|
||||
ast, astalgo, ropes, lists, nhashes, strutils, types, msgs
|
||||
ast, astalgo, ropes, lists, nhashes, strutils, types, msgs, wordrecg,
|
||||
platform
|
||||
|
||||
proc toCChar*(c: Char): string
|
||||
proc makeCString*(s: string): PRope
|
||||
proc makeLLVMString*(s: string): PRope
|
||||
proc TableGetType*(tab: TIdTable, key: PType): PObject
|
||||
proc GetUniqueType*(key: PType): PType
|
||||
# implementation
|
||||
proc whichPragma*(n: PNode): TSpecialWord =
|
||||
var key = if n.kind == nkExprColonExpr: n.sons[0] else: n
|
||||
if key.kind == nkIdent: result = whichKeyword(key.ident)
|
||||
|
||||
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||
case n.kind
|
||||
of nkStmtList:
|
||||
for i in 0 .. < n.len:
|
||||
result = getPragmaStmt(n[i], w)
|
||||
if result != nil: break
|
||||
of nkPragma:
|
||||
for i in 0 .. < n.len:
|
||||
if whichPragma(n[i]) == w: return n[i]
|
||||
else: nil
|
||||
|
||||
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
|
||||
result = getPragmaStmt(n, w) != nil
|
||||
|
||||
proc hashString*(s: string): biggestInt =
|
||||
# has to be the same algorithm as system.hashString!
|
||||
if CPU[targetCPU].bit == 64:
|
||||
# we have to use the same bitwidth
|
||||
# as the target CPU
|
||||
var b = 0'i64
|
||||
for i in countup(0, len(s) - 1):
|
||||
b = b +% Ord(s[i])
|
||||
b = b +% `shl`(b, 10)
|
||||
b = b xor `shr`(b, 6)
|
||||
b = b +% `shl`(b, 3)
|
||||
b = b xor `shr`(b, 11)
|
||||
b = b +% `shl`(b, 15)
|
||||
result = b
|
||||
else:
|
||||
var a = 0'i32
|
||||
for i in countup(0, len(s) - 1):
|
||||
a = a +% Ord(s[i]).int32
|
||||
a = a +% `shl`(a, 10'i32)
|
||||
a = a xor `shr`(a, 6'i32)
|
||||
a = a +% `shl`(a, 3'i32)
|
||||
a = a xor `shr`(a, 11'i32)
|
||||
a = a +% `shl`(a, 15'i32)
|
||||
result = a
|
||||
|
||||
var gTypeTable: array[TTypeKind, TIdTable]
|
||||
|
||||
proc initTypeTables() =
|
||||
for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
|
||||
|
||||
proc GetUniqueType(key: PType): PType =
|
||||
proc GetUniqueType*(key: PType): PType =
|
||||
var
|
||||
t: PType
|
||||
k: TTypeKind
|
||||
@@ -32,33 +69,7 @@ proc GetUniqueType(key: PType): PType =
|
||||
result = key
|
||||
if key == nil: return
|
||||
k = key.kind
|
||||
case k #
|
||||
# case key.Kind of
|
||||
# tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
||||
# tyInt..tyFloat128, tyProc, tyAnyEnum: begin end;
|
||||
# tyNone, tyForward:
|
||||
# InternalError('GetUniqueType: ' + typeToString(key));
|
||||
# tyGenericParam, tyGeneric, tyAbstract, tySequence,
|
||||
# tyOpenArray, tySet, tyVar, tyRef, tyPtr, tyArrayConstr,
|
||||
# tyArray, tyTuple, tyRange: begin
|
||||
# // we have to do a slow linear search because types may need
|
||||
# // to be compared by their structure:
|
||||
# if IdTableHasObjectAsKey(gTypeTable, key) then exit;
|
||||
# for h := 0 to high(gTypeTable.data) do begin
|
||||
# t := PType(gTypeTable.data[h].key);
|
||||
# if (t <> nil) and sameType(t, key) then begin result := t; exit end
|
||||
# end;
|
||||
# IdTablePut(gTypeTable, key, key);
|
||||
# end;
|
||||
# tyObject, tyEnum: begin
|
||||
# result := PType(IdTableGet(gTypeTable, key));
|
||||
# if result = nil then begin
|
||||
# IdTablePut(gTypeTable, key, key);
|
||||
# result := key;
|
||||
# end
|
||||
# end;
|
||||
# tyGenericInst, tyAbstract: result := GetUniqueType(lastSon(key));
|
||||
# end;
|
||||
case k
|
||||
of tyObject, tyEnum:
|
||||
result = PType(IdTableGet(gTypeTable[k], key))
|
||||
if result == nil:
|
||||
@@ -78,7 +89,7 @@ proc GetUniqueType(key: PType): PType =
|
||||
return t
|
||||
IdTablePut(gTypeTable[k], key, key)
|
||||
|
||||
proc TableGetType(tab: TIdTable, key: PType): PObject =
|
||||
proc TableGetType*(tab: TIdTable, key: PType): PObject =
|
||||
var t: PType
|
||||
# returns nil if we need to declare this type
|
||||
result = IdTableGet(tab, key)
|
||||
@@ -91,13 +102,13 @@ proc TableGetType(tab: TIdTable, key: PType): PObject =
|
||||
if sameType(t, key):
|
||||
return tab.data[h].val
|
||||
|
||||
proc toCChar(c: Char): string =
|
||||
proc toCChar*(c: Char): string =
|
||||
case c
|
||||
of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
|
||||
of '\'', '\"', '\\': result = '\\' & c
|
||||
else: result = $(c)
|
||||
|
||||
proc makeCString(s: string): PRope =
|
||||
proc makeCString*(s: string): PRope =
|
||||
# BUGFIX: We have to split long strings into many ropes. Otherwise
|
||||
# this could trigger an InternalError(). See the ropes module for
|
||||
# further information.
|
||||
@@ -117,9 +128,8 @@ proc makeCString(s: string): PRope =
|
||||
add(res, '\"')
|
||||
app(result, toRope(res))
|
||||
|
||||
proc makeLLVMString(s: string): PRope =
|
||||
const
|
||||
MaxLineLength = 64
|
||||
proc makeLLVMString*(s: string): PRope =
|
||||
const MaxLineLength = 64
|
||||
var res: string
|
||||
result = nil
|
||||
res = "c\""
|
||||
@@ -135,4 +145,4 @@ proc makeLLVMString(s: string): PRope =
|
||||
add(res, "\\00\"")
|
||||
app(result, toRope(res))
|
||||
|
||||
InitTypeTables()
|
||||
InitTypeTables()
|
||||
|
||||
19
rod/cgen.nim
19
rod/cgen.nim
@@ -308,14 +308,19 @@ proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) =
|
||||
proc zeroTemp(p: BProc, loc: TLoc) =
|
||||
if skipTypes(loc.t, abstractVarRange).Kind notin
|
||||
{tyArray, tyArrayConstr, tySet, tyTuple, tyObject}:
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.t, onStack)
|
||||
nilLoc.r = toRope("NIM_NIL")
|
||||
# puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
|
||||
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
|
||||
appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
|
||||
when false:
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.t, onStack)
|
||||
nilLoc.r = toRope("NIM_NIL")
|
||||
# puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
|
||||
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
|
||||
else:
|
||||
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
||||
[addrLoc(loc), genTypeInfo(p.module, loc.t)])
|
||||
appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n",
|
||||
[addrLoc(loc), rdLoc(loc)])
|
||||
when false:
|
||||
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
||||
[addrLoc(loc), genTypeInfo(p.module, loc.t)])
|
||||
|
||||
proc initVariable(p: BProc, v: PSym) =
|
||||
var b = containsGarbageCollectedRef(v.typ)
|
||||
|
||||
36
rod/main.nim
36
rod/main.nim
@@ -193,23 +193,23 @@ proc MainCommand(cmd, filename: string) =
|
||||
setID(100)
|
||||
passes.gIncludeFile = syntaxes.parseFile
|
||||
passes.gImportModule = importModule
|
||||
case whichKeyword(cmd)
|
||||
of wCompile, wCompileToC, wC, wCC:
|
||||
case cmd.normalize
|
||||
of "c", "cc", "compile", "compiletoc":
|
||||
# compile means compileToC currently
|
||||
gCmd = cmdCompileToC
|
||||
wantFile(filename)
|
||||
CommandCompileToC(filename)
|
||||
of wCompileToCpp:
|
||||
of "compiletocpp":
|
||||
extccomp.cExt = ".cpp"
|
||||
gCmd = cmdCompileToCpp
|
||||
wantFile(filename)
|
||||
CommandCompileToC(filename)
|
||||
of wCompileToOC, wOC:
|
||||
of "oc", "compiletooc":
|
||||
extccomp.cExt = ".m"
|
||||
gCmd = cmdCompileToOC
|
||||
wantFile(filename)
|
||||
CommandCompileToC(filename)
|
||||
of wRun:
|
||||
of "run":
|
||||
gCmd = cmdRun
|
||||
wantFile(filename)
|
||||
when hasTinyCBackend:
|
||||
@@ -217,61 +217,61 @@ proc MainCommand(cmd, filename: string) =
|
||||
CommandCompileToC(filename)
|
||||
else:
|
||||
rawMessage(errInvalidCommandX, cmd)
|
||||
of wCompileToEcmaScript, wJs:
|
||||
of "js", "compiletoecmascript":
|
||||
gCmd = cmdCompileToEcmaScript
|
||||
wantFile(filename)
|
||||
CommandCompileToEcmaScript(filename)
|
||||
of wCompileToLLVM:
|
||||
of "compiletollvm":
|
||||
gCmd = cmdCompileToLLVM
|
||||
wantFile(filename)
|
||||
when has_LLVM_Backend:
|
||||
CommandCompileToLLVM(filename)
|
||||
else:
|
||||
rawMessage(errInvalidCommandX, cmd)
|
||||
of wPretty:
|
||||
of "pretty":
|
||||
gCmd = cmdPretty
|
||||
wantFile(filename) #CommandExportSymbols(filename);
|
||||
CommandPretty(filename)
|
||||
of wDoc:
|
||||
of "doc":
|
||||
gCmd = cmdDoc
|
||||
LoadSpecialConfig(DocConfig)
|
||||
wantFile(filename)
|
||||
CommandDoc(filename)
|
||||
of wRst2html:
|
||||
of "rst2html":
|
||||
gCmd = cmdRst2html
|
||||
LoadSpecialConfig(DocConfig)
|
||||
wantFile(filename)
|
||||
CommandRst2Html(filename)
|
||||
of wRst2tex:
|
||||
of "rst2tex":
|
||||
gCmd = cmdRst2tex
|
||||
LoadSpecialConfig(DocTexConfig)
|
||||
wantFile(filename)
|
||||
CommandRst2TeX(filename)
|
||||
of wGenDepend:
|
||||
of "gendepend":
|
||||
gCmd = cmdGenDepend
|
||||
wantFile(filename)
|
||||
CommandGenDepend(filename)
|
||||
of wDump:
|
||||
of "dump":
|
||||
gCmd = cmdDump
|
||||
condsyms.ListSymbols()
|
||||
for it in iterSearchPath(): MsgWriteln(it)
|
||||
of wCheck:
|
||||
of "check":
|
||||
gCmd = cmdCheck
|
||||
wantFile(filename)
|
||||
CommandCheck(filename)
|
||||
of wParse:
|
||||
of "parse":
|
||||
gCmd = cmdParse
|
||||
wantFile(filename)
|
||||
discard parseFile(addFileExt(filename, nimExt))
|
||||
of wScan:
|
||||
of "scan":
|
||||
gCmd = cmdScan
|
||||
wantFile(filename)
|
||||
CommandScan(filename)
|
||||
MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
|
||||
of wI:
|
||||
of "i":
|
||||
gCmd = cmdInteractive
|
||||
CommandInteractive()
|
||||
of wIdeTools:
|
||||
of "idetools":
|
||||
gCmd = cmdIdeTools
|
||||
wantFile(filename)
|
||||
CommandSuggest(filename)
|
||||
|
||||
@@ -34,12 +34,12 @@ const
|
||||
wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal,
|
||||
wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint,
|
||||
wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks,
|
||||
wInfChecks, wNanChecks, wPragma, wEmit}
|
||||
wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd}
|
||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure,
|
||||
wDeprecated, wExtern}
|
||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern}
|
||||
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow}
|
||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern}
|
||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern}
|
||||
@@ -357,6 +357,19 @@ proc PragmaEmit(c: PContext, n: PNode) =
|
||||
proc noVal(n: PNode) =
|
||||
if n.kind == nkExprColonExpr: invalidPragma(n)
|
||||
|
||||
proc PragmaUnroll(c: PContext, n: PNode) =
|
||||
if c.p.nestedLoopCounter <= 0:
|
||||
invalidPragma(n)
|
||||
elif n.kind == nkExprColonExpr:
|
||||
var unrollFactor = expectIntLit(c, n)
|
||||
if unrollFactor <% 32:
|
||||
n.sons[1] = newIntNode(nkIntLit, unrollFactor)
|
||||
else:
|
||||
invalidPragma(n)
|
||||
|
||||
proc PragmaLinearScanEnd(c: PContext, n: PNode) =
|
||||
noVal(n)
|
||||
|
||||
proc processPragma(c: PContext, n: PNode, i: int) =
|
||||
var it = n.sons[i]
|
||||
if it.kind != nkExprColonExpr: invalidPragma(n)
|
||||
@@ -475,6 +488,10 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
incl(sym.typ.flags, tfAcyclic)
|
||||
of wShallow:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
incl(sym.typ.flags, tfShallow)
|
||||
of wTypeCheck:
|
||||
noVal(it)
|
||||
incl(sym.flags, sfTypeCheck)
|
||||
@@ -509,6 +526,8 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
sym.typ.callConv = wordToCallConv(k)
|
||||
of wEmit: PragmaEmit(c, it)
|
||||
of wUnroll: PragmaUnroll(c, it)
|
||||
of wLinearScanEnd: PragmaLinearScanEnd(c, it)
|
||||
else: invalidPragma(it)
|
||||
else: invalidPragma(it)
|
||||
else: processNote(c, it)
|
||||
|
||||
14
rod/rst.nim
14
rod/rst.nim
@@ -188,7 +188,7 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
|
||||
of '\x0D', '\x0A':
|
||||
getIndent(L, tok)
|
||||
of '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
|
||||
'/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{',
|
||||
'/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{',
|
||||
'|', '}', '~':
|
||||
getAdornment(L, tok)
|
||||
if len(tok.symbol) <= 3: tok.kind = tkPunct
|
||||
@@ -257,16 +257,16 @@ type
|
||||
value*: PRstNode
|
||||
|
||||
TSharedState{.final.} = object
|
||||
uLevel*, oLevel*: int # counters for the section levels
|
||||
subs*: seq[TSubstitution] # substitutions
|
||||
refs*: seq[TSubstitution] # references
|
||||
uLevel*, oLevel*: int # counters for the section levels
|
||||
subs*: seq[TSubstitution] # substitutions
|
||||
refs*: seq[TSubstitution] # references
|
||||
underlineToLevel*: TLevelMap # Saves for each possible title adornment
|
||||
# character its level in the
|
||||
# current document.
|
||||
# This is for single underline adornments.
|
||||
overlineToLevel*: TLevelMap # Saves for each possible title adornment
|
||||
# character its level in the current document.
|
||||
# This is for over-underline adornments.
|
||||
overlineToLevel*: TLevelMap # Saves for each possible title adornment
|
||||
# character its level in the current document.
|
||||
# This is for over-underline adornments.
|
||||
|
||||
PSharedState = ref TSharedState
|
||||
TRstParser = object of TObject
|
||||
|
||||
@@ -410,10 +410,13 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
|
||||
proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
|
||||
flags: TExprFlags): PNode =
|
||||
if not (efWantIterator in flags):
|
||||
result = semDirectCall(c, n, {skProc, skMethod, skConverter})
|
||||
else:
|
||||
result = semDirectCall(c, n, {skIterator})
|
||||
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)
|
||||
result = semDirectCall(c, n, symflags)
|
||||
if result != nil:
|
||||
if result.sons[0].kind != nkSym:
|
||||
InternalError("semDirectCallAnalyseEffects")
|
||||
@@ -1037,7 +1040,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of paNone: result = nil
|
||||
of paTuplePositions: result = semTuplePositionsConstr(c, n)
|
||||
of paTupleFields: result = semTupleFieldsConstr(c, n)
|
||||
of paSingle: result = semExpr(c, n.sons[0])
|
||||
of paSingle: result = semExpr(c, n.sons[0], flags)
|
||||
of nkCurly: result = semSetConstr(c, n)
|
||||
of nkBracket: result = semArrayConstr(c, n)
|
||||
of nkLambda: result = semLambda(c, n)
|
||||
|
||||
@@ -574,7 +574,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
case n.kind
|
||||
of nkEmpty: nil
|
||||
of nkTypeOfExpr:
|
||||
result = semExprWithType(c, n, {efAllowType}).typ
|
||||
checkSonsLen(n, 1)
|
||||
result = semExprWithType(c, n.sons[0], {efAllowType}).typ
|
||||
of nkPar:
|
||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||
else: GlobalError(n.info, errTypeExpected)
|
||||
|
||||
@@ -340,10 +340,6 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
||||
#result = newTransNode(n.sons[0])
|
||||
#result[1] = transform(c, m.sons[0])
|
||||
|
||||
#if skipTypes(n.sons[0].typ, abstractVar).kind == tyOpenArray:
|
||||
# debug(result.pnode)
|
||||
# liMessage(n.info, warnUser,
|
||||
# "nkPassAsOpenArray introduced here " & renderTree(n))
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
else:
|
||||
|
||||
@@ -53,12 +53,8 @@ type
|
||||
wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH,
|
||||
wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced, wSkipcfg, wSkipProjCfg,
|
||||
wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar,
|
||||
wAcyclic, wIndex,
|
||||
wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM,
|
||||
wCompileToOC,
|
||||
wPretty,
|
||||
wDoc, wGenDepend, wDump, wCheck, wParse, wScan, wJs, wOC,
|
||||
wRst2html, wRst2tex, wI,
|
||||
wAcyclic, wShallow, wUnroll, wLinearScanEnd,
|
||||
wIndex,
|
||||
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wThreads,
|
||||
wRecursivePath,
|
||||
wStdout,
|
||||
@@ -105,33 +101,25 @@ const
|
||||
"cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v",
|
||||
"help", "h", "symbolfiles", "fieldchecks", "x", "version", "advanced",
|
||||
"skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints",
|
||||
"nomain", "subschar", "acyclic", "index",
|
||||
"compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm",
|
||||
"compiletooc",
|
||||
"pretty", "doc", "gendepend", "dump", "check", "parse", "scan",
|
||||
"js", "oc", "rst2html", "rst2tex", "i",
|
||||
"nomain", "subschar", "acyclic", "shallow", "unroll", "linearscanend",
|
||||
"index",
|
||||
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
|
||||
"threads", "recursivepath",
|
||||
"stdout",
|
||||
"idetools", "suggest", "track", "def", "context"]
|
||||
|
||||
proc whichKeyword*(id: PIdent): TSpecialWord
|
||||
proc whichKeyword*(id: String): TSpecialWord
|
||||
proc findStr*(a: openarray[string], s: string): int
|
||||
# implementation
|
||||
|
||||
proc findStr(a: openarray[string], s: string): int =
|
||||
proc findStr*(a: openarray[string], s: string): int =
|
||||
for i in countup(low(a), high(a)):
|
||||
if cmpIgnoreStyle(a[i], s) == 0:
|
||||
return i
|
||||
result = - 1
|
||||
|
||||
proc whichKeyword(id: String): TSpecialWord =
|
||||
result = whichKeyword(getIdent(id))
|
||||
|
||||
proc whichKeyword(id: PIdent): TSpecialWord =
|
||||
proc whichKeyword*(id: PIdent): TSpecialWord =
|
||||
if id.id < 0: result = wInvalid
|
||||
else: result = TSpecialWord(id.id)
|
||||
|
||||
proc whichKeyword*(id: String): TSpecialWord =
|
||||
result = whichKeyword(getIdent(id))
|
||||
|
||||
proc initSpecials() =
|
||||
# initialize the keywords:
|
||||
|
||||
11
tests/accept/compile/tfib.nim
Normal file
11
tests/accept/compile/tfib.nim
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
iterator fibonacci(): int =
|
||||
var a = 0
|
||||
var b = 1
|
||||
while true:
|
||||
yield a
|
||||
var c = b
|
||||
b = a
|
||||
a = a + c
|
||||
|
||||
|
||||
185
tests/accept/run/tsort.nim
Normal file
185
tests/accept/run/tsort.nim
Normal file
@@ -0,0 +1,185 @@
|
||||
|
||||
# design criteria:
|
||||
# Generic code is expenisve wrt code size!
|
||||
# So the implementation should be small.
|
||||
# The sort should be stable.
|
||||
#
|
||||
|
||||
proc sort[T](arr: var openArray[T], lo, hi: natural) =
|
||||
var k = 0
|
||||
if lo < hi:
|
||||
var mid = (lo + hi) div 2
|
||||
sort(arr, lo, mid)
|
||||
inc(mid)
|
||||
sort(arr, mid, hi)
|
||||
while lo < mid and mid <= hi:
|
||||
if arr[lo] < arr[mid]:
|
||||
inc(lo)
|
||||
else:
|
||||
when swapIsExpensive(T):
|
||||
var help = arr[mid]
|
||||
for k in countdown(mid, succ(lo)):
|
||||
arr[k] = arr[pred(k)]
|
||||
arr[lo] = help
|
||||
else:
|
||||
for k in countdown(mid, succ(lo)):
|
||||
swap(arr[k], arr[pred(k)])
|
||||
inc(lo)
|
||||
inc(mid)
|
||||
|
||||
type
|
||||
TSortOrder* = enum
|
||||
Descending = -1,
|
||||
Ascending = 0
|
||||
|
||||
proc flip(x: int, order: TSortOrder): int {.inline.} =
|
||||
result = x xor ord(order) - ord(order)
|
||||
|
||||
# We use a fixed size stack. This size is larger
|
||||
# than can be overflowed on a 64-bit machine
|
||||
const
|
||||
stackSize = 66
|
||||
minRunSize = 7
|
||||
|
||||
type
|
||||
TRun = tuple[index, length: int]
|
||||
TSortState[T] {.pure, final.} = object
|
||||
storage: seq[T]
|
||||
runs: array[0..stackSize-1, TRun]
|
||||
stackHeight: int # The index of the first unwritten element of the stack.
|
||||
partitionedUpTo, length: int
|
||||
|
||||
# We keep track of how far we've partitioned up
|
||||
# to so we know where to start the next partition.
|
||||
# The idea is that everything < partionedUpTo
|
||||
# is on the stack, everything >= partionedUpTo
|
||||
# is not yet on the stack. When partitionedUpTo == length
|
||||
# we'll have put everything on the stack.
|
||||
|
||||
proc reverse[T](a: var openArray[T], first, last: int) =
|
||||
for j in first .. < first+length div 2: swap(a[j], a[length-j-1])
|
||||
|
||||
proc insertionSort[T]( int xs[], int length) =
|
||||
for i in 1.. < length:
|
||||
# The array before i is sorted. Now insert xs[i] into it
|
||||
var x = xs[i]
|
||||
var j = i-1
|
||||
# Move j down until it's either at the beginning or on
|
||||
# something <= x, and everything to the right of it has
|
||||
# been moved up one.
|
||||
while j >= 0 and xs[j] > x:
|
||||
xs[j+1] = xs[j]
|
||||
dec j
|
||||
xs[j+1] = x
|
||||
|
||||
proc boostRunLength(s: TSortState, run: var TRun) =
|
||||
# Need to make sure we don't overshoot the end of the array
|
||||
var length = min(s.length - run.index, minRunSize)
|
||||
insertionSort(run.index, length)
|
||||
run.length = length
|
||||
|
||||
proc nextPartition[T](a: var openarray[T], s: var TSortState): bool =
|
||||
if s.partitionedUpTo >= s.length: return false
|
||||
var startIndex = s.partitionedUpTo
|
||||
# Find an increasing run starting from startIndex
|
||||
var nextStartIndex = startIndex + 1
|
||||
|
||||
if nextStartIndex < s.length:
|
||||
if a[nextStartIndex] < a[startIndex]:
|
||||
# We have a decreasing sequence starting here.
|
||||
while nextStartIndex < s.length:
|
||||
if a[nextStartIndex] < a[nextStartIndex-1]: inc(nextStartIndex)
|
||||
else: break
|
||||
# Now reverse it in place.
|
||||
reverse(a, startIndex, nextStartIndex)
|
||||
else:
|
||||
# We have an increasing sequence starting here.
|
||||
while nextStartIndex < s.length:
|
||||
if a[nextStartIndex] >= a[nextStartIndex-1]: inc(nextStartIndex)
|
||||
else: break
|
||||
|
||||
# So now [startIndex, nextStartIndex) is an increasing run.
|
||||
# Push it onto the stack.
|
||||
var runToAdd: TRun = (startIndex, nextStartIndex - startIndex)
|
||||
if runToAdd.length < minRunSize:
|
||||
boostRunLength(s, runToAdd)
|
||||
s.partitionedUpTo = startIndex + runToAdd.length
|
||||
|
||||
s.runs[s.stackHeight] = runToAdd
|
||||
inc s.stackHeight
|
||||
result = true
|
||||
|
||||
proc shouldCollapse(s: TSortState): bool =
|
||||
if s.stackHeight > 2:
|
||||
var h = s.stackHeight-1
|
||||
var headLength = s.runs[h].length
|
||||
var nextLength = s.runs[h-1].length
|
||||
result = 2 * headLength > nextLength
|
||||
|
||||
proc merge(int target[], int p1[], int l1, int p2[], int l2, int storage[]) =
|
||||
# Merge the sorted arrays p1, p2 of length l1, l2 into a single
|
||||
# sorted array starting at target. target may overlap with either
|
||||
# of p1 or p2 but must have enough space to store the array.
|
||||
# Use the storage argument for temporary storage. It must have room for
|
||||
# l1 + l2 ints.
|
||||
int *merge_to = storage
|
||||
|
||||
# Current index into each of the two arrays we're writing
|
||||
# from.
|
||||
int i1, i2;
|
||||
i1 = i2 = 0;
|
||||
|
||||
# The address to which we write the next element in the merge
|
||||
int *next_merge_element = merge_to;
|
||||
|
||||
# Iterate over the two arrays, writing the least element at the
|
||||
# current position to merge_to. When the two are equal we prefer
|
||||
# the left one, because if we're merging left, right we want to
|
||||
# ensure stability.
|
||||
# Of course this doesn't matter for integers, but it's the thought
|
||||
# that counts.
|
||||
while i1 < l1 and i2 < l2:
|
||||
if p1[i1] <= p2[i2]:
|
||||
*next_merge_element = p1[i1];
|
||||
i1++
|
||||
else:
|
||||
*next_merge_element = p2[i2];
|
||||
i2++
|
||||
next_merge_element++
|
||||
|
||||
# If we stopped short before the end of one of the arrays
|
||||
# we now copy the rest over.
|
||||
memcpy(next_merge_element, p1 + i1, sizeof(int) * (l1 - i1));
|
||||
memcpy(next_merge_element, p2 + i2, sizeof(int) * (l2 - i2));
|
||||
|
||||
# We've now merged into our additional working space. Time
|
||||
# to copy to the target.
|
||||
memcpy(target, merge_to, sizeof(int) * (l1 + l2));
|
||||
|
||||
|
||||
proc mergeCollapse(a: s: var TSortState) =
|
||||
var X = s.runs[s.stackHeight-2]
|
||||
var Y = s.runs[s.stackHeight-1]
|
||||
|
||||
merge(X.index, X.index, X.length, Y.index, Y.length, s.storage)
|
||||
|
||||
dec s.stackHeight
|
||||
inc X.length, Y.length
|
||||
s.runs[s.stackHeight-1] = X
|
||||
|
||||
proc sort[T](arr: var openArray[T], first, last: natural,
|
||||
cmp: proc (x,y: T): int, order = TSortOrder.ascending) =
|
||||
var s: TSortState
|
||||
newSeq(s.storage, arr.len)
|
||||
s.stackHeight = 0
|
||||
s.partitionedUpTo = 0
|
||||
s.length = arr.len
|
||||
|
||||
while nextPartition(s):
|
||||
while shouldCollapse(s): mergeCollapse(s)
|
||||
while s.stackHeight > 1: mergeCollapse(s)
|
||||
|
||||
proc sort[T](arr: var openArray[T], cmp: proc (x, y: T): int = cmp,
|
||||
order = TSortOrder.ascending) =
|
||||
sort(arr, 0, high(arr), order)
|
||||
|
||||
12
tests/accept/run/ttoseq.nim
Normal file
12
tests/accept/run/ttoseq.nim
Normal file
@@ -0,0 +1,12 @@
|
||||
discard """
|
||||
output: "23456"
|
||||
"""
|
||||
|
||||
template toSeq*(iter: expr): expr =
|
||||
var result: seq[type(iter)] = @[]
|
||||
for x in iter: add(result, x)
|
||||
result
|
||||
|
||||
for x, y in items(toSeq(countup(2, 6))).withIndex:
|
||||
stdout.write(x)
|
||||
|
||||
1
todo.txt
1
todo.txt
@@ -1,5 +1,4 @@
|
||||
- 'nimrod def': does not always work
|
||||
- BUG: gcleak.nim
|
||||
|
||||
- thread support: threadvar on Windows seems broken;
|
||||
add --deadlock_prevention:on|off switch
|
||||
|
||||
@@ -20,7 +20,8 @@ Bugfixes
|
||||
- Bugfix: Multiple yield statements in iterators did not cause local vars to be
|
||||
copied.
|
||||
- Bugfix: The compiler does not emit very inaccurate floating point literals
|
||||
anymore.
|
||||
anymore.
|
||||
- Lots of other bugfixes: Too many to list them all.
|
||||
|
||||
|
||||
Changes affecting backwards compatibility
|
||||
@@ -65,6 +66,9 @@ Additions
|
||||
- Added ``math.floor``.
|
||||
- The *interactive mode* (REPL) has been improved and documented for the
|
||||
first time.
|
||||
- Added the ``linearScanEnd`` and ``unroll`` pragmas.
|
||||
- The compiler now might use a hashing for string case statements depending
|
||||
on the number of string literals in the case statement.
|
||||
|
||||
|
||||
2010-10-20 Version 0.8.10 released
|
||||
|
||||
Reference in New Issue
Block a user