linearScanEnd pragma; string case statement optimization
This commit is contained in:
parent
6850fb73c1
commit
8d734244b1
26 changed files with 537 additions and 252 deletions
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
|
%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
|
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
|
%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
|
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
|
%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
|
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
|
%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
|
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
|
%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
|
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
|
%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
|
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
|
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
|
%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
|
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/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/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
|
ECHO SUCCESS
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2648,6 +2648,53 @@ The `hint`:idx: pragma is used to make the compiler output a hint message with
|
||||||
the given content. Compilation continues after the hint.
|
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
|
compilation option pragmas
|
||||||
--------------------------
|
--------------------------
|
||||||
The listed pragmas here can be used to override the code generation options
|
The listed pragmas here can be used to override the code generation options
|
||||||
|
|
|
||||||
|
|
@ -293,10 +293,26 @@ However it is not efficient to do:
|
||||||
.. code-block:: Nimrod
|
.. code-block:: Nimrod
|
||||||
var s = varA # assignment has to copy the whole string into a new buffer!
|
var s = varA # assignment has to copy the whole string into a new buffer!
|
||||||
|
|
||||||
..
|
The compiler optimizes string case statements: A hashing scheme is used for them
|
||||||
String case statements are optimized too. A hashing scheme is used for them
|
if several different string constants are used. So code like this is reasonably
|
||||||
if several different string constants are used. This is likely to be more
|
efficient:
|
||||||
efficient than any hand-coded scheme.
|
|
||||||
|
.. 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
|
chmod 644 $docdir/abstypes.txt
|
||||||
cp doc/advopt.txt $docdir/advopt.txt || exit 1
|
cp doc/advopt.txt $docdir/advopt.txt || exit 1
|
||||||
chmod 644 $docdir/advopt.txt
|
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
|
cp doc/apis.txt $docdir/apis.txt || exit 1
|
||||||
chmod 644 $docdir/apis.txt
|
chmod 644 $docdir/apis.txt
|
||||||
cp doc/astspec.txt $docdir/astspec.txt || exit 1
|
cp doc/astspec.txt $docdir/astspec.txt || exit 1
|
||||||
|
|
@ -330,6 +328,8 @@ if [ $# -eq 1 ] ; then
|
||||||
chmod 644 $libdir/core/marshal.nim
|
chmod 644 $libdir/core/marshal.nim
|
||||||
cp lib/core/threads.nim $libdir/core/threads.nim || exit 1
|
cp lib/core/threads.nim $libdir/core/threads.nim || exit 1
|
||||||
chmod 644 $libdir/core/threads.nim
|
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
|
cp lib/pure/base64.nim $libdir/pure/base64.nim || exit 1
|
||||||
chmod 644 $libdir/pure/base64.nim
|
chmod 644 $libdir/pure/base64.nim
|
||||||
cp lib/pure/browsers.nim $libdir/pure/browsers.nim || exit 1
|
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
|
chmod 644 $libdir/pure/cookies.nim
|
||||||
cp lib/pure/dynlib.nim $libdir/pure/dynlib.nim || exit 1
|
cp lib/pure/dynlib.nim $libdir/pure/dynlib.nim || exit 1
|
||||||
chmod 644 $libdir/pure/dynlib.nim
|
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
|
cp lib/pure/hashes.nim $libdir/pure/hashes.nim || exit 1
|
||||||
chmod 644 $libdir/pure/hashes.nim
|
chmod 644 $libdir/pure/hashes.nim
|
||||||
cp lib/pure/htmlparser.nim $libdir/pure/htmlparser.nim || exit 1
|
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
|
## Parses a decimal integer value contained in `s`. If `s` is not
|
||||||
## a valid integer, `EInvalidValue` is raised.
|
## a valid integer, `EInvalidValue` is raised.
|
||||||
var L = parseutils.parseInt(s, result, 0)
|
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,
|
proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuParseBiggestInt".} =
|
rtl, extern: "nsuParseBiggestInt".} =
|
||||||
## Parses a decimal integer value contained in `s`. If `s` is not
|
## Parses a decimal integer value contained in `s`. If `s` is not
|
||||||
## a valid integer, `EInvalidValue` is raised.
|
## a valid integer, `EInvalidValue` is raised.
|
||||||
var L = parseutils.parseBiggestInt(s, result, 0)
|
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,
|
proc ParseFloat*(s: string): float {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuParseFloat".} =
|
rtl, extern: "nsuParseFloat".} =
|
||||||
|
|
@ -421,7 +423,8 @@ proc ParseFloat*(s: string): float {.noSideEffect, procvar,
|
||||||
## a valid floating point number, `EInvalidValue` is raised. ``NAN``,
|
## a valid floating point number, `EInvalidValue` is raised. ``NAN``,
|
||||||
## ``INF``, ``-INF`` are also supported (case insensitive comparison).
|
## ``INF``, ``-INF`` are also supported (case insensitive comparison).
|
||||||
var L = parseutils.parseFloat(s, result, 0)
|
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,
|
proc ParseHexInt*(s: string): int {.noSideEffect, procvar,
|
||||||
rtl, extern: "nsuParseHexInt".} =
|
rtl, extern: "nsuParseHexInt".} =
|
||||||
|
|
|
||||||
|
|
@ -1198,12 +1198,12 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
|
||||||
|
|
||||||
# ----------------- GC interface ---------------------------------------------
|
# ----------------- 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
|
## 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
|
## reactivate the GC. Note that in most circumstances one should only disable
|
||||||
## the mark and sweep phase with `GC_disableMarkAndSweep`.
|
## the mark and sweep phase with `GC_disableMarkAndSweep`.
|
||||||
|
|
||||||
proc GC_enable*() {.rtl.}
|
proc GC_enable*() {.rtl, inl.}
|
||||||
## enables the GC again.
|
## enables the GC again.
|
||||||
|
|
||||||
proc GC_fullCollect*() {.rtl.}
|
proc GC_fullCollect*() {.rtl.}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,7 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
#when defined(debugGC):
|
proc genericAssignAux(dest, src: Pointer, mt: PNimType)
|
||||||
# {.define: logAssign.}
|
|
||||||
proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.}
|
|
||||||
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
|
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
|
||||||
var
|
var
|
||||||
d = cast[TAddress](dest)
|
d = cast[TAddress](dest)
|
||||||
|
|
@ -17,8 +15,8 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkNone: assert(false)
|
of nkNone: assert(false)
|
||||||
of nkSlot:
|
of nkSlot:
|
||||||
genericAssign(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
|
genericAssignAux(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
|
||||||
n.typ)
|
n.typ)
|
||||||
of nkList:
|
of nkList:
|
||||||
for i in 0..n.len-1:
|
for i in 0..n.len-1:
|
||||||
genericAssignAux(dest, src, n.sons[i])
|
genericAssignAux(dest, src, n.sons[i])
|
||||||
|
|
@ -28,7 +26,7 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
|
||||||
var m = selectBranch(src, n)
|
var m = selectBranch(src, n)
|
||||||
if m != nil: genericAssignAux(dest, src, m)
|
if m != nil: genericAssignAux(dest, src, m)
|
||||||
|
|
||||||
proc genericAssign(dest, src: Pointer, mt: PNimType) =
|
proc genericAssignAux(dest, src: Pointer, mt: PNimType) =
|
||||||
var
|
var
|
||||||
d = cast[TAddress](dest)
|
d = cast[TAddress](dest)
|
||||||
s = cast[TAddress](src)
|
s = cast[TAddress](src)
|
||||||
|
|
@ -47,7 +45,7 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
|
||||||
newObj(mt, seq.len * mt.base.size + GenericSeqSize))
|
newObj(mt, seq.len * mt.base.size + GenericSeqSize))
|
||||||
var dst = cast[taddress](cast[ppointer](dest)^)
|
var dst = cast[taddress](cast[ppointer](dest)^)
|
||||||
for i in 0..seq.len-1:
|
for i in 0..seq.len-1:
|
||||||
genericAssign(
|
genericAssignAux(
|
||||||
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
|
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
|
||||||
cast[pointer](cast[taddress](s2) +% i *% mt.base.size +%
|
cast[pointer](cast[taddress](s2) +% i *% mt.base.size +%
|
||||||
GenericSeqSize),
|
GenericSeqSize),
|
||||||
|
|
@ -60,8 +58,8 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
|
||||||
genericAssignAux(dest, src, mt.node)
|
genericAssignAux(dest, src, mt.node)
|
||||||
of tyArray, tyArrayConstr:
|
of tyArray, tyArrayConstr:
|
||||||
for i in 0..(mt.size div mt.base.size)-1:
|
for i in 0..(mt.size div mt.base.size)-1:
|
||||||
genericAssign(cast[pointer](d +% i*% mt.base.size),
|
genericAssignAux(cast[pointer](d +% i*% mt.base.size),
|
||||||
cast[pointer](s +% i*% mt.base.size), mt.base)
|
cast[pointer](s +% i*% mt.base.size), mt.base)
|
||||||
of tyString: # a leaf
|
of tyString: # a leaf
|
||||||
var s2 = cast[ppointer](s)^
|
var s2 = cast[ppointer](s)^
|
||||||
if s2 != nil: # nil strings are possible!
|
if s2 != nil: # nil strings are possible!
|
||||||
|
|
@ -75,6 +73,11 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
|
||||||
else:
|
else:
|
||||||
copyMem(dest, src, mt.size) # copy raw bits
|
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.} =
|
proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
|
||||||
var src = src # ugly, but I like to stress the parser sometimes :-)
|
var src = src # ugly, but I like to stress the parser sometimes :-)
|
||||||
genericAssign(dest, addr(src), mt)
|
genericAssign(dest, addr(src), mt)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nimrod's Runtime Library
|
# Nimrod's Runtime Library
|
||||||
# (c) Copyright 2010 Andreas Rumpf
|
# (c) Copyright 2011 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Nimrod's Runtime Library
|
# Nimrod's Runtime Library
|
||||||
# (c) Copyright 2010 Andreas Rumpf
|
# (c) Copyright 2011 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,8 @@ type
|
||||||
tfNoSideEffect, # procedure type does not allow side effects
|
tfNoSideEffect, # procedure type does not allow side effects
|
||||||
tfFinal, # is the object final?
|
tfFinal, # is the object final?
|
||||||
tfAcyclic, # type is acyclic (for GC optimization)
|
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]
|
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)])
|
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
|
||||||
else:
|
else:
|
||||||
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
|
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:
|
of tyArray, tyArrayConstr:
|
||||||
if needsComplexAssignment(dest.t):
|
if needsComplexAssignment(dest.t):
|
||||||
appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
|
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,
|
appcg(p, cpsStmts,
|
||||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
|
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
|
||||||
[rdLoc(dest), rdLoc(src)])
|
[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:
|
of tyOpenArray:
|
||||||
# open arrays are always on the stack - really? What if a sequence is
|
# open arrays are always on the stack - really? What if a sequence is
|
||||||
# passed to an open array?
|
# passed to an open array?
|
||||||
|
|
|
||||||
193
rod/ccgstmts.nim
193
rod/ccgstmts.nim
|
|
@ -10,6 +10,10 @@
|
||||||
const
|
const
|
||||||
RangeExpandLimit = 256 # do not generate ranges
|
RangeExpandLimit = 256 # do not generate ranges
|
||||||
# over 'RangeExpandLimit' elements
|
# 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) =
|
proc genLineDir(p: BProc, t: PNode) =
|
||||||
var line = toLinenumber(t.info) # BUGFIX
|
var line = toLinenumber(t.info) # BUGFIX
|
||||||
|
|
@ -229,13 +233,6 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||||
else:
|
else:
|
||||||
appcg(p, cpsStmts, "#reraiseException();" & tnl)
|
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,
|
proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||||
rangeFormat, eqFormat: TFormatStr, labl: TLabel) =
|
rangeFormat, eqFormat: TFormatStr, labl: TLabel) =
|
||||||
var
|
var
|
||||||
|
|
@ -251,90 +248,68 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||||
initLocExpr(p, b.sons[i], x)
|
initLocExpr(p, b.sons[i], x)
|
||||||
appcg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
|
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)
|
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)])
|
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])
|
var length = sonsLen(t.sons[i])
|
||||||
genStmts(p, t.sons[i].sons[length - 1])
|
genStmts(p, t.sons[i].sons[length - 1])
|
||||||
appf(p.s[cpsStmts], "goto $1;$n", [Lend])
|
appf(p.s[cpsStmts], "goto $1;$n", [Lend])
|
||||||
else:
|
else:
|
||||||
genStmts(p, t.sons[i].sons[0])
|
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
|
# 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
|
var labId = p.labels
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in 1..until:
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
if t.sons[i].kind == nkOfBranch: # else statement
|
if t.sons[i].kind == nkOfBranch: # else statement
|
||||||
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
|
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
|
||||||
con("LA", toRope(p.labels)))
|
con("LA", toRope(p.labels)))
|
||||||
else:
|
else:
|
||||||
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)])
|
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)])
|
||||||
genCaseSecondPass(p, t, labId)
|
if until < t.len-1:
|
||||||
|
inc(p.labels)
|
||||||
proc hashString(s: string): biggestInt =
|
var gotoTarget = p.labels
|
||||||
var
|
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(gotoTarget)])
|
||||||
a: int32
|
result = genCaseSecondPass(p, t, labId, until)
|
||||||
b: int64
|
appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(gotoTarget)])
|
||||||
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:
|
else:
|
||||||
a = 0
|
result = genCaseSecondPass(p, t, labId, until)
|
||||||
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
|
proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) =
|
||||||
TRopeSeq = seq[PRope]
|
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,
|
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||||
branches: var TRopeSeq) =
|
branches: var openArray[PRope]) =
|
||||||
var
|
var x: TLoc
|
||||||
length, j: int
|
var length = sonsLen(b)
|
||||||
x: TLoc
|
|
||||||
length = sonsLen(b)
|
|
||||||
for i in countup(0, length - 2):
|
for i in countup(0, length - 2):
|
||||||
assert(b.sons[i].kind != nkRange)
|
assert(b.sons[i].kind != nkRange)
|
||||||
initLocExpr(p, b.sons[i], x)
|
initLocExpr(p, b.sons[i], x)
|
||||||
assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
|
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",
|
appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
|
||||||
[rdLoc(e), rdLoc(x), labl])
|
[rdLoc(e), rdLoc(x), labl])
|
||||||
|
|
||||||
proc genStringCase(p: BProc, t: PNode) =
|
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:
|
# count how many constant strings there are in the case:
|
||||||
strings = 0
|
var strings = 0
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
|
if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
|
||||||
if strings > stringCaseThreshold:
|
if strings > stringCaseThreshold:
|
||||||
bitMask = math.nextPowerOfTwo(strings) - 1
|
var bitMask = math.nextPowerOfTwo(strings) - 1
|
||||||
|
var branches: seq[PRope]
|
||||||
newSeq(branches, bitMask + 1)
|
newSeq(branches, bitMask + 1)
|
||||||
|
var a: TLoc
|
||||||
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
|
initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
|
||||||
labId = p.labels
|
var labId = p.labels
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
if t.sons[i].kind == nkOfBranch:
|
if t.sons[i].kind == nkOfBranch:
|
||||||
|
|
@ -353,67 +328,72 @@ proc genStringCase(p: BProc, t: PNode) =
|
||||||
if t.sons[sonsLen(t) - 1].kind != nkOfBranch:
|
if t.sons[sonsLen(t) - 1].kind != nkOfBranch:
|
||||||
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)])
|
appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)])
|
||||||
# third pass: generate statements
|
# third pass: generate statements
|
||||||
genCaseSecondPass(p, t, labId)
|
var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1)
|
||||||
|
fixLabel(p, Lend)
|
||||||
else:
|
else:
|
||||||
genCaseGeneric(p, t, "", "if (#eqStrings($1, $2)) goto $3;$n")
|
genCaseGeneric(p, t, "", "if (#eqStrings($1, $2)) goto $3;$n")
|
||||||
|
|
||||||
proc branchHasTooBigRange(b: PNode): bool =
|
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
|
# last son is block
|
||||||
if (b.sons[i].Kind == nkRange) and
|
if (b.sons[i].Kind == nkRange) and
|
||||||
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
|
b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
|
||||||
return true
|
return true
|
||||||
result = false
|
|
||||||
|
|
||||||
proc genOrdinalCase(p: BProc, t: PNode) =
|
proc IfSwitchSplitPoint(p: BProc, n: PNode): int =
|
||||||
# We analyse if we have a too big switch range. If this is the case,
|
for i in 1..n.len-1:
|
||||||
# we generate an ordinary if statement and rely on the C compiler
|
var branch = n[i]
|
||||||
# to produce good code.
|
var stmtBlock = lastSon(branch)
|
||||||
var
|
if stmtBlock.stmtsContainPragma(wLinearScanEnd):
|
||||||
canGenerateSwitch, hasDefault: bool
|
result = i
|
||||||
length: int
|
elif hasSwitchRange notin CC[ccompiler].props:
|
||||||
a: TLoc
|
if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
|
||||||
v: PNode
|
result = i
|
||||||
canGenerateSwitch = true
|
|
||||||
if not (hasSwitchRange in CC[ccompiler].props):
|
proc genOrdinalCase(p: BProc, n: PNode) =
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
# analyse 'case' statement:
|
||||||
if (t.sons[i].kind == nkOfBranch) and branchHasTooBigRange(t.sons[i]):
|
var splitPoint = IfSwitchSplitPoint(p, n)
|
||||||
canGenerateSwitch = false
|
|
||||||
break
|
# generate if part (might be empty):
|
||||||
if canGenerateSwitch:
|
var a: TLoc
|
||||||
initLocExpr(p, t.sons[0], a)
|
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)])
|
appf(p.s[cpsStmts], "switch ($1) {$n", [rdCharLoc(a)])
|
||||||
hasDefault = false
|
var hasDefault = false
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in splitPoint+1 .. < n.len:
|
||||||
if t.sons[i].kind == nkOfBranch:
|
var branch = n[i]
|
||||||
length = sonsLen(t.sons[i])
|
if branch.kind == nkOfBranch:
|
||||||
for j in countup(0, length - 2):
|
var length = branch.len
|
||||||
if t.sons[i].sons[j].kind == nkRange:
|
for j in 0 .. length-2:
|
||||||
# a range
|
if branch[j].kind == nkRange:
|
||||||
if hasSwitchRange in CC[ccompiler].props:
|
if hasSwitchRange in CC[ccompiler].props:
|
||||||
appf(p.s[cpsStmts], "case $1 ... $2:$n", [
|
appf(p.s[cpsStmts], "case $1 ... $2:$n", [
|
||||||
genLiteral(p, t.sons[i].sons[j].sons[0]),
|
genLiteral(p, branch[j][0]),
|
||||||
genLiteral(p, t.sons[i].sons[j].sons[1])])
|
genLiteral(p, branch[j][1])])
|
||||||
else:
|
else:
|
||||||
v = copyNode(t.sons[i].sons[j].sons[0])
|
var v = copyNode(branch[j][0])
|
||||||
while (v.intVal <= t.sons[i].sons[j].sons[1].intVal):
|
while v.intVal <= branch[j][1].intVal:
|
||||||
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, v)])
|
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, v)])
|
||||||
Inc(v.intVal)
|
Inc(v.intVal)
|
||||||
else:
|
else:
|
||||||
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, t.sons[i].sons[j])])
|
appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, branch[j])])
|
||||||
genStmts(p, t.sons[i].sons[length - 1])
|
genStmts(p, branch[length-1])
|
||||||
else:
|
else:
|
||||||
# else part of case statement:
|
# else part of case statement:
|
||||||
app(p.s[cpsStmts], "default:" & tnl)
|
app(p.s[cpsStmts], "default:" & tnl)
|
||||||
genStmts(p, t.sons[i].sons[0])
|
genStmts(p, branch[0])
|
||||||
hasDefault = true
|
hasDefault = true
|
||||||
app(p.s[cpsStmts], "break;" & tnl)
|
app(p.s[cpsStmts], "break;" & tnl)
|
||||||
if (hasAssume in CC[ccompiler].props) and not hasDefault:
|
if (hasAssume in CC[ccompiler].props) and not hasDefault:
|
||||||
app(p.s[cpsStmts], "default: __assume(0);" & tnl)
|
app(p.s[cpsStmts], "default: __assume(0);" & tnl)
|
||||||
app(p.s[cpsStmts], '}' & tnl)
|
app(p.s[cpsStmts], '}' & tnl)
|
||||||
else:
|
if Lend != nil: fixLabel(p, Lend)
|
||||||
genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
|
|
||||||
"if ($1 == $2) goto $3;$n")
|
|
||||||
|
|
||||||
proc genCaseStmt(p: BProc, t: PNode) =
|
proc genCaseStmt(p: BProc, t: PNode) =
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
|
|
@ -424,7 +404,6 @@ proc genCaseStmt(p: BProc, t: PNode) =
|
||||||
genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
|
genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
|
||||||
"if ($1 == $2) goto $3;$n")
|
"if ($1 == $2) goto $3;$n")
|
||||||
else:
|
else:
|
||||||
# ordinal type: generate a switch statement
|
|
||||||
genOrdinalCase(p, t)
|
genOrdinalCase(p, t)
|
||||||
|
|
||||||
proc hasGeneralExceptSection(t: PNode): bool =
|
proc hasGeneralExceptSection(t: PNode): bool =
|
||||||
|
|
@ -629,19 +608,17 @@ proc genBreakPoint(p: BProc, t: PNode) =
|
||||||
proc genPragma(p: BProc, n: PNode) =
|
proc genPragma(p: BProc, n: PNode) =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
|
case whichPragma(it)
|
||||||
if key.kind == nkIdent:
|
of wEmit:
|
||||||
case whichKeyword(key.ident)
|
genEmit(p, it)
|
||||||
of wEmit:
|
of wBreakpoint:
|
||||||
genEmit(p, it)
|
genBreakPoint(p, it)
|
||||||
of wBreakpoint:
|
of wDeadCodeElim:
|
||||||
genBreakPoint(p, it)
|
if not (optDeadCodeElim in gGlobalOptions):
|
||||||
of wDeadCodeElim:
|
# we need to keep track of ``deadCodeElim`` pragma
|
||||||
if not (optDeadCodeElim in gGlobalOptions):
|
if (sfDeadCodeElim in p.module.module.flags):
|
||||||
# we need to keep track of ``deadCodeElim`` pragma
|
addPendingModule(p.module)
|
||||||
if (sfDeadCodeElim in p.module.module.flags):
|
else: nil
|
||||||
addPendingModule(p.module)
|
|
||||||
else: nil
|
|
||||||
|
|
||||||
proc genAsgn(p: BProc, e: PNode) =
|
proc genAsgn(p: BProc, e: PNode) =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nimrod Compiler
|
||||||
# (c) Copyright 2009 Andreas Rumpf
|
# (c) Copyright 2011 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
|
|
@ -10,21 +10,58 @@
|
||||||
# This module declares some helpers for the C code generator.
|
# This module declares some helpers for the C code generator.
|
||||||
|
|
||||||
import
|
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 whichPragma*(n: PNode): TSpecialWord =
|
||||||
proc makeCString*(s: string): PRope
|
var key = if n.kind == nkExprColonExpr: n.sons[0] else: n
|
||||||
proc makeLLVMString*(s: string): PRope
|
if key.kind == nkIdent: result = whichKeyword(key.ident)
|
||||||
proc TableGetType*(tab: TIdTable, key: PType): PObject
|
|
||||||
proc GetUniqueType*(key: PType): PType
|
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
|
||||||
# implementation
|
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]
|
var gTypeTable: array[TTypeKind, TIdTable]
|
||||||
|
|
||||||
proc initTypeTables() =
|
proc initTypeTables() =
|
||||||
for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
|
for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
|
||||||
|
|
||||||
proc GetUniqueType(key: PType): PType =
|
proc GetUniqueType*(key: PType): PType =
|
||||||
var
|
var
|
||||||
t: PType
|
t: PType
|
||||||
k: TTypeKind
|
k: TTypeKind
|
||||||
|
|
@ -32,33 +69,7 @@ proc GetUniqueType(key: PType): PType =
|
||||||
result = key
|
result = key
|
||||||
if key == nil: return
|
if key == nil: return
|
||||||
k = key.kind
|
k = key.kind
|
||||||
case k #
|
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;
|
|
||||||
of tyObject, tyEnum:
|
of tyObject, tyEnum:
|
||||||
result = PType(IdTableGet(gTypeTable[k], key))
|
result = PType(IdTableGet(gTypeTable[k], key))
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
|
@ -78,7 +89,7 @@ proc GetUniqueType(key: PType): PType =
|
||||||
return t
|
return t
|
||||||
IdTablePut(gTypeTable[k], key, key)
|
IdTablePut(gTypeTable[k], key, key)
|
||||||
|
|
||||||
proc TableGetType(tab: TIdTable, key: PType): PObject =
|
proc TableGetType*(tab: TIdTable, key: PType): PObject =
|
||||||
var t: PType
|
var t: PType
|
||||||
# returns nil if we need to declare this type
|
# returns nil if we need to declare this type
|
||||||
result = IdTableGet(tab, key)
|
result = IdTableGet(tab, key)
|
||||||
|
|
@ -91,13 +102,13 @@ proc TableGetType(tab: TIdTable, key: PType): PObject =
|
||||||
if sameType(t, key):
|
if sameType(t, key):
|
||||||
return tab.data[h].val
|
return tab.data[h].val
|
||||||
|
|
||||||
proc toCChar(c: Char): string =
|
proc toCChar*(c: Char): string =
|
||||||
case c
|
case c
|
||||||
of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
|
of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
|
||||||
of '\'', '\"', '\\': result = '\\' & c
|
of '\'', '\"', '\\': result = '\\' & c
|
||||||
else: 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
|
# BUGFIX: We have to split long strings into many ropes. Otherwise
|
||||||
# this could trigger an InternalError(). See the ropes module for
|
# this could trigger an InternalError(). See the ropes module for
|
||||||
# further information.
|
# further information.
|
||||||
|
|
@ -117,9 +128,8 @@ proc makeCString(s: string): PRope =
|
||||||
add(res, '\"')
|
add(res, '\"')
|
||||||
app(result, toRope(res))
|
app(result, toRope(res))
|
||||||
|
|
||||||
proc makeLLVMString(s: string): PRope =
|
proc makeLLVMString*(s: string): PRope =
|
||||||
const
|
const MaxLineLength = 64
|
||||||
MaxLineLength = 64
|
|
||||||
var res: string
|
var res: string
|
||||||
result = nil
|
result = nil
|
||||||
res = "c\""
|
res = "c\""
|
||||||
|
|
|
||||||
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) =
|
proc zeroTemp(p: BProc, loc: TLoc) =
|
||||||
if skipTypes(loc.t, abstractVarRange).Kind notin
|
if skipTypes(loc.t, abstractVarRange).Kind notin
|
||||||
{tyArray, tyArrayConstr, tySet, tyTuple, tyObject}:
|
{tyArray, tyArrayConstr, tySet, tyTuple, tyObject}:
|
||||||
var nilLoc: TLoc
|
appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
|
||||||
initLoc(nilLoc, locTemp, loc.t, onStack)
|
when false:
|
||||||
nilLoc.r = toRope("NIM_NIL")
|
var nilLoc: TLoc
|
||||||
# puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
|
initLoc(nilLoc, locTemp, loc.t, onStack)
|
||||||
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
|
nilLoc.r = toRope("NIM_NIL")
|
||||||
|
# puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
|
||||||
|
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
|
||||||
else:
|
else:
|
||||||
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n",
|
||||||
[addrLoc(loc), genTypeInfo(p.module, loc.t)])
|
[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) =
|
proc initVariable(p: BProc, v: PSym) =
|
||||||
var b = containsGarbageCollectedRef(v.typ)
|
var b = containsGarbageCollectedRef(v.typ)
|
||||||
|
|
|
||||||
36
rod/main.nim
36
rod/main.nim
|
|
@ -193,23 +193,23 @@ proc MainCommand(cmd, filename: string) =
|
||||||
setID(100)
|
setID(100)
|
||||||
passes.gIncludeFile = syntaxes.parseFile
|
passes.gIncludeFile = syntaxes.parseFile
|
||||||
passes.gImportModule = importModule
|
passes.gImportModule = importModule
|
||||||
case whichKeyword(cmd)
|
case cmd.normalize
|
||||||
of wCompile, wCompileToC, wC, wCC:
|
of "c", "cc", "compile", "compiletoc":
|
||||||
# compile means compileToC currently
|
# compile means compileToC currently
|
||||||
gCmd = cmdCompileToC
|
gCmd = cmdCompileToC
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandCompileToC(filename)
|
CommandCompileToC(filename)
|
||||||
of wCompileToCpp:
|
of "compiletocpp":
|
||||||
extccomp.cExt = ".cpp"
|
extccomp.cExt = ".cpp"
|
||||||
gCmd = cmdCompileToCpp
|
gCmd = cmdCompileToCpp
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandCompileToC(filename)
|
CommandCompileToC(filename)
|
||||||
of wCompileToOC, wOC:
|
of "oc", "compiletooc":
|
||||||
extccomp.cExt = ".m"
|
extccomp.cExt = ".m"
|
||||||
gCmd = cmdCompileToOC
|
gCmd = cmdCompileToOC
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandCompileToC(filename)
|
CommandCompileToC(filename)
|
||||||
of wRun:
|
of "run":
|
||||||
gCmd = cmdRun
|
gCmd = cmdRun
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
when hasTinyCBackend:
|
when hasTinyCBackend:
|
||||||
|
|
@ -217,61 +217,61 @@ proc MainCommand(cmd, filename: string) =
|
||||||
CommandCompileToC(filename)
|
CommandCompileToC(filename)
|
||||||
else:
|
else:
|
||||||
rawMessage(errInvalidCommandX, cmd)
|
rawMessage(errInvalidCommandX, cmd)
|
||||||
of wCompileToEcmaScript, wJs:
|
of "js", "compiletoecmascript":
|
||||||
gCmd = cmdCompileToEcmaScript
|
gCmd = cmdCompileToEcmaScript
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandCompileToEcmaScript(filename)
|
CommandCompileToEcmaScript(filename)
|
||||||
of wCompileToLLVM:
|
of "compiletollvm":
|
||||||
gCmd = cmdCompileToLLVM
|
gCmd = cmdCompileToLLVM
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
when has_LLVM_Backend:
|
when has_LLVM_Backend:
|
||||||
CommandCompileToLLVM(filename)
|
CommandCompileToLLVM(filename)
|
||||||
else:
|
else:
|
||||||
rawMessage(errInvalidCommandX, cmd)
|
rawMessage(errInvalidCommandX, cmd)
|
||||||
of wPretty:
|
of "pretty":
|
||||||
gCmd = cmdPretty
|
gCmd = cmdPretty
|
||||||
wantFile(filename) #CommandExportSymbols(filename);
|
wantFile(filename) #CommandExportSymbols(filename);
|
||||||
CommandPretty(filename)
|
CommandPretty(filename)
|
||||||
of wDoc:
|
of "doc":
|
||||||
gCmd = cmdDoc
|
gCmd = cmdDoc
|
||||||
LoadSpecialConfig(DocConfig)
|
LoadSpecialConfig(DocConfig)
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandDoc(filename)
|
CommandDoc(filename)
|
||||||
of wRst2html:
|
of "rst2html":
|
||||||
gCmd = cmdRst2html
|
gCmd = cmdRst2html
|
||||||
LoadSpecialConfig(DocConfig)
|
LoadSpecialConfig(DocConfig)
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandRst2Html(filename)
|
CommandRst2Html(filename)
|
||||||
of wRst2tex:
|
of "rst2tex":
|
||||||
gCmd = cmdRst2tex
|
gCmd = cmdRst2tex
|
||||||
LoadSpecialConfig(DocTexConfig)
|
LoadSpecialConfig(DocTexConfig)
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandRst2TeX(filename)
|
CommandRst2TeX(filename)
|
||||||
of wGenDepend:
|
of "gendepend":
|
||||||
gCmd = cmdGenDepend
|
gCmd = cmdGenDepend
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandGenDepend(filename)
|
CommandGenDepend(filename)
|
||||||
of wDump:
|
of "dump":
|
||||||
gCmd = cmdDump
|
gCmd = cmdDump
|
||||||
condsyms.ListSymbols()
|
condsyms.ListSymbols()
|
||||||
for it in iterSearchPath(): MsgWriteln(it)
|
for it in iterSearchPath(): MsgWriteln(it)
|
||||||
of wCheck:
|
of "check":
|
||||||
gCmd = cmdCheck
|
gCmd = cmdCheck
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandCheck(filename)
|
CommandCheck(filename)
|
||||||
of wParse:
|
of "parse":
|
||||||
gCmd = cmdParse
|
gCmd = cmdParse
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
discard parseFile(addFileExt(filename, nimExt))
|
discard parseFile(addFileExt(filename, nimExt))
|
||||||
of wScan:
|
of "scan":
|
||||||
gCmd = cmdScan
|
gCmd = cmdScan
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandScan(filename)
|
CommandScan(filename)
|
||||||
MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
|
MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
|
||||||
of wI:
|
of "i":
|
||||||
gCmd = cmdInteractive
|
gCmd = cmdInteractive
|
||||||
CommandInteractive()
|
CommandInteractive()
|
||||||
of wIdeTools:
|
of "idetools":
|
||||||
gCmd = cmdIdeTools
|
gCmd = cmdIdeTools
|
||||||
wantFile(filename)
|
wantFile(filename)
|
||||||
CommandSuggest(filename)
|
CommandSuggest(filename)
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,12 @@ const
|
||||||
wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal,
|
wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal,
|
||||||
wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint,
|
wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint,
|
||||||
wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks,
|
wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks,
|
||||||
wInfChecks, wNanChecks, wPragma, wEmit}
|
wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd}
|
||||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||||
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure,
|
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure,
|
||||||
wDeprecated, wExtern}
|
wDeprecated, wExtern}
|
||||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
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}
|
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern}
|
||||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||||
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern}
|
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern}
|
||||||
|
|
@ -357,6 +357,19 @@ proc PragmaEmit(c: PContext, n: PNode) =
|
||||||
proc noVal(n: PNode) =
|
proc noVal(n: PNode) =
|
||||||
if n.kind == nkExprColonExpr: invalidPragma(n)
|
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) =
|
proc processPragma(c: PContext, n: PNode, i: int) =
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
if it.kind != nkExprColonExpr: invalidPragma(n)
|
if it.kind != nkExprColonExpr: invalidPragma(n)
|
||||||
|
|
@ -475,6 +488,10 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
noVal(it)
|
noVal(it)
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
incl(sym.typ.flags, tfAcyclic)
|
incl(sym.typ.flags, tfAcyclic)
|
||||||
|
of wShallow:
|
||||||
|
noVal(it)
|
||||||
|
if sym.typ == nil: invalidPragma(it)
|
||||||
|
incl(sym.typ.flags, tfShallow)
|
||||||
of wTypeCheck:
|
of wTypeCheck:
|
||||||
noVal(it)
|
noVal(it)
|
||||||
incl(sym.flags, sfTypeCheck)
|
incl(sym.flags, sfTypeCheck)
|
||||||
|
|
@ -509,6 +526,8 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
if sym.typ == nil: invalidPragma(it)
|
if sym.typ == nil: invalidPragma(it)
|
||||||
sym.typ.callConv = wordToCallConv(k)
|
sym.typ.callConv = wordToCallConv(k)
|
||||||
of wEmit: PragmaEmit(c, it)
|
of wEmit: PragmaEmit(c, it)
|
||||||
|
of wUnroll: PragmaUnroll(c, it)
|
||||||
|
of wLinearScanEnd: PragmaLinearScanEnd(c, it)
|
||||||
else: invalidPragma(it)
|
else: invalidPragma(it)
|
||||||
else: invalidPragma(it)
|
else: invalidPragma(it)
|
||||||
else: processNote(c, it)
|
else: processNote(c, it)
|
||||||
|
|
|
||||||
12
rod/rst.nim
12
rod/rst.nim
|
|
@ -257,16 +257,16 @@ type
|
||||||
value*: PRstNode
|
value*: PRstNode
|
||||||
|
|
||||||
TSharedState{.final.} = object
|
TSharedState{.final.} = object
|
||||||
uLevel*, oLevel*: int # counters for the section levels
|
uLevel*, oLevel*: int # counters for the section levels
|
||||||
subs*: seq[TSubstitution] # substitutions
|
subs*: seq[TSubstitution] # substitutions
|
||||||
refs*: seq[TSubstitution] # references
|
refs*: seq[TSubstitution] # references
|
||||||
underlineToLevel*: TLevelMap # Saves for each possible title adornment
|
underlineToLevel*: TLevelMap # Saves for each possible title adornment
|
||||||
# character its level in the
|
# character its level in the
|
||||||
# current document.
|
# current document.
|
||||||
# This is for single underline adornments.
|
# This is for single underline adornments.
|
||||||
overlineToLevel*: TLevelMap # Saves for each possible title adornment
|
overlineToLevel*: TLevelMap # Saves for each possible title adornment
|
||||||
# character its level in the current document.
|
# character its level in the current document.
|
||||||
# This is for over-underline adornments.
|
# This is for over-underline adornments.
|
||||||
|
|
||||||
PSharedState = ref TSharedState
|
PSharedState = ref TSharedState
|
||||||
TRstParser = object of TObject
|
TRstParser = object of TObject
|
||||||
|
|
|
||||||
|
|
@ -410,10 +410,13 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||||
|
|
||||||
proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
|
proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
|
||||||
flags: TExprFlags): PNode =
|
flags: TExprFlags): PNode =
|
||||||
if not (efWantIterator in flags):
|
var symflags = {skProc, skMethod, skConverter}
|
||||||
result = semDirectCall(c, n, {skProc, skMethod, skConverter})
|
if efWantIterator in flags:
|
||||||
else:
|
symflags = {skIterator}
|
||||||
result = semDirectCall(c, n, {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 != nil:
|
||||||
if result.sons[0].kind != nkSym:
|
if result.sons[0].kind != nkSym:
|
||||||
InternalError("semDirectCallAnalyseEffects")
|
InternalError("semDirectCallAnalyseEffects")
|
||||||
|
|
@ -1037,7 +1040,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
of paNone: result = nil
|
of paNone: result = nil
|
||||||
of paTuplePositions: result = semTuplePositionsConstr(c, n)
|
of paTuplePositions: result = semTuplePositionsConstr(c, n)
|
||||||
of paTupleFields: result = semTupleFieldsConstr(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 nkCurly: result = semSetConstr(c, n)
|
||||||
of nkBracket: result = semArrayConstr(c, n)
|
of nkBracket: result = semArrayConstr(c, n)
|
||||||
of nkLambda: result = semLambda(c, n)
|
of nkLambda: result = semLambda(c, n)
|
||||||
|
|
|
||||||
|
|
@ -574,7 +574,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkEmpty: nil
|
of nkEmpty: nil
|
||||||
of nkTypeOfExpr:
|
of nkTypeOfExpr:
|
||||||
result = semExprWithType(c, n, {efAllowType}).typ
|
checkSonsLen(n, 1)
|
||||||
|
result = semExprWithType(c, n.sons[0], {efAllowType}).typ
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||||
else: GlobalError(n.info, errTypeExpected)
|
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 = newTransNode(n.sons[0])
|
||||||
#result[1] = transform(c, m.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:
|
else:
|
||||||
result = transformSons(c, n)
|
result = transformSons(c, n)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -53,12 +53,8 @@ type
|
||||||
wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH,
|
wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH,
|
||||||
wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced, wSkipcfg, wSkipProjCfg,
|
wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced, wSkipcfg, wSkipProjCfg,
|
||||||
wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar,
|
wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar,
|
||||||
wAcyclic, wIndex,
|
wAcyclic, wShallow, wUnroll, wLinearScanEnd,
|
||||||
wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM,
|
wIndex,
|
||||||
wCompileToOC,
|
|
||||||
wPretty,
|
|
||||||
wDoc, wGenDepend, wDump, wCheck, wParse, wScan, wJs, wOC,
|
|
||||||
wRst2html, wRst2tex, wI,
|
|
||||||
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wThreads,
|
wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wThreads,
|
||||||
wRecursivePath,
|
wRecursivePath,
|
||||||
wStdout,
|
wStdout,
|
||||||
|
|
@ -105,34 +101,26 @@ const
|
||||||
"cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v",
|
"cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v",
|
||||||
"help", "h", "symbolfiles", "fieldchecks", "x", "version", "advanced",
|
"help", "h", "symbolfiles", "fieldchecks", "x", "version", "advanced",
|
||||||
"skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints",
|
"skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints",
|
||||||
"nomain", "subschar", "acyclic", "index",
|
"nomain", "subschar", "acyclic", "shallow", "unroll", "linearscanend",
|
||||||
"compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm",
|
"index",
|
||||||
"compiletooc",
|
|
||||||
"pretty", "doc", "gendepend", "dump", "check", "parse", "scan",
|
|
||||||
"js", "oc", "rst2html", "rst2tex", "i",
|
|
||||||
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
|
"write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
|
||||||
"threads", "recursivepath",
|
"threads", "recursivepath",
|
||||||
"stdout",
|
"stdout",
|
||||||
"idetools", "suggest", "track", "def", "context"]
|
"idetools", "suggest", "track", "def", "context"]
|
||||||
|
|
||||||
proc whichKeyword*(id: PIdent): TSpecialWord
|
proc findStr*(a: openarray[string], s: string): int =
|
||||||
proc whichKeyword*(id: String): TSpecialWord
|
|
||||||
proc findStr*(a: openarray[string], s: string): int
|
|
||||||
# implementation
|
|
||||||
|
|
||||||
proc findStr(a: openarray[string], s: string): int =
|
|
||||||
for i in countup(low(a), high(a)):
|
for i in countup(low(a), high(a)):
|
||||||
if cmpIgnoreStyle(a[i], s) == 0:
|
if cmpIgnoreStyle(a[i], s) == 0:
|
||||||
return i
|
return i
|
||||||
result = - 1
|
result = - 1
|
||||||
|
|
||||||
proc whichKeyword(id: String): TSpecialWord =
|
proc whichKeyword*(id: PIdent): TSpecialWord =
|
||||||
result = whichKeyword(getIdent(id))
|
|
||||||
|
|
||||||
proc whichKeyword(id: PIdent): TSpecialWord =
|
|
||||||
if id.id < 0: result = wInvalid
|
if id.id < 0: result = wInvalid
|
||||||
else: result = TSpecialWord(id.id)
|
else: result = TSpecialWord(id.id)
|
||||||
|
|
||||||
|
proc whichKeyword*(id: String): TSpecialWord =
|
||||||
|
result = whichKeyword(getIdent(id))
|
||||||
|
|
||||||
proc initSpecials() =
|
proc initSpecials() =
|
||||||
# initialize the keywords:
|
# initialize the keywords:
|
||||||
for s in countup(succ(low(specialWords)), high(specialWords)):
|
for s in countup(succ(low(specialWords)), high(specialWords)):
|
||||||
|
|
|
||||||
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
|
- 'nimrod def': does not always work
|
||||||
- BUG: gcleak.nim
|
|
||||||
|
|
||||||
- thread support: threadvar on Windows seems broken;
|
- thread support: threadvar on Windows seems broken;
|
||||||
add --deadlock_prevention:on|off switch
|
add --deadlock_prevention:on|off switch
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ Bugfixes
|
||||||
copied.
|
copied.
|
||||||
- Bugfix: The compiler does not emit very inaccurate floating point literals
|
- 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
|
Changes affecting backwards compatibility
|
||||||
|
|
@ -65,6 +66,9 @@ Additions
|
||||||
- Added ``math.floor``.
|
- Added ``math.floor``.
|
||||||
- The *interactive mode* (REPL) has been improved and documented for the
|
- The *interactive mode* (REPL) has been improved and documented for the
|
||||||
first time.
|
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
|
2010-10-20 Version 0.8.10 released
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue