Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq 2012-06-19 22:38:48 +02:00
commit e0092cfae6
54 changed files with 1980 additions and 1251 deletions

View file

@ -143,8 +143,12 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\aliases.c -o build\1_1\aliases.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\aliases.c -o build\1_1\aliases.o %CC% %COMP_FLAGS% -Ibuild -c build\1_1\aliases.c -o build\1_1\aliases.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
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\docgen.c -o build\1_1\docgen.o %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\rstast.c -o build\1_1\rstast.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstast.c -o build\1_1\rstast.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rst.c -o build\1_1\rst.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rst.c -o build\1_1\rst.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rst.c -o build\1_1\rst.o %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rst.c -o build\1_1\rst.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstgen.c -o build\1_1\rstgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\rstgen.c -o build\1_1\rstgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\highlite.c -o build\1_1\highlite.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\highlite.c -o build\1_1\highlite.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_1\highlite.c -o build\1_1\highlite.o %CC% %COMP_FLAGS% -Ibuild -c build\1_1\highlite.c -o build\1_1\highlite.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgen.c -o build\1_1\cgen.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_1\cgen.c -o build\1_1\cgen.o
@ -164,8 +168,8 @@ 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\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\strtabs.o build\1_1\hashes.o build\1_1\tables.o build\1_1\math.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\intsets.o build\1_1\idgen.o build\1_1\astalgo.o build\1_1\rodutils.o build\1_1\extccomp.o build\1_1\osproc.o build\1_1\streams.o build\1_1\wordrecg.o build\1_1\lexer.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\parser.o build\1_1\pbraces.o build\1_1\filters.o build\1_1\renderer.o build\1_1\filter_tmpl.o build\1_1\rodread.o build\1_1\memfiles.o build\1_1\rodwrite.o build\1_1\passes.o build\1_1\types.o build\1_1\trees.o build\1_1\magicsys.o build\1_1\nimsets.o build\1_1\bitsets.o build\1_1\semthreads.o build\1_1\importer.o build\1_1\lookups.o build\1_1\semdata.o build\1_1\treetab.o build\1_1\evals.o build\1_1\semfold.o build\1_1\transf.o build\1_1\cgmeth.o build\1_1\sem.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\aliases.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\cgendata.o build\1_1\ccgmerge.o build\1_1\ecmasgen.o build\1_1\passaux.o build\1_1\depends.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\strtabs.o build\1_1\hashes.o build\1_1\tables.o build\1_1\math.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\intsets.o build\1_1\idgen.o build\1_1\astalgo.o build\1_1\rodutils.o build\1_1\extccomp.o build\1_1\osproc.o build\1_1\streams.o build\1_1\wordrecg.o build\1_1\lexer.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\parser.o build\1_1\pbraces.o build\1_1\filters.o build\1_1\renderer.o build\1_1\filter_tmpl.o build\1_1\rodread.o build\1_1\memfiles.o build\1_1\rodwrite.o build\1_1\passes.o build\1_1\types.o build\1_1\trees.o build\1_1\magicsys.o build\1_1\nimsets.o build\1_1\bitsets.o build\1_1\semthreads.o build\1_1\importer.o build\1_1\lookups.o build\1_1\semdata.o build\1_1\treetab.o build\1_1\evals.o build\1_1\semfold.o build\1_1\transf.o build\1_1\cgmeth.o build\1_1\sem.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\aliases.o build\1_1\docgen.o build\1_1\rstast.o build\1_1\rst.o build\1_1\rstgen.o build\1_1\highlite.o build\1_1\cgen.o build\1_1\ccgutils.o build\1_1\cgendata.o build\1_1\ccgmerge.o build\1_1\ecmasgen.o build\1_1\passaux.o build\1_1\depends.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\strtabs.o build\1_1\hashes.o build\1_1\tables.o build\1_1\math.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\intsets.o build\1_1\idgen.o build\1_1\astalgo.o build\1_1\rodutils.o build\1_1\extccomp.o build\1_1\osproc.o build\1_1\streams.o build\1_1\wordrecg.o build\1_1\lexer.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\parser.o build\1_1\pbraces.o build\1_1\filters.o build\1_1\renderer.o build\1_1\filter_tmpl.o build\1_1\rodread.o build\1_1\memfiles.o build\1_1\rodwrite.o build\1_1\passes.o build\1_1\types.o build\1_1\trees.o build\1_1\magicsys.o build\1_1\nimsets.o build\1_1\bitsets.o build\1_1\semthreads.o build\1_1\importer.o build\1_1\lookups.o build\1_1\semdata.o build\1_1\treetab.o build\1_1\evals.o build\1_1\semfold.o build\1_1\transf.o build\1_1\cgmeth.o build\1_1\sem.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\aliases.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\cgendata.o build\1_1\ccgmerge.o build\1_1\ecmasgen.o build\1_1\passaux.o build\1_1\depends.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\strtabs.o build\1_1\hashes.o build\1_1\tables.o build\1_1\math.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\intsets.o build\1_1\idgen.o build\1_1\astalgo.o build\1_1\rodutils.o build\1_1\extccomp.o build\1_1\osproc.o build\1_1\streams.o build\1_1\wordrecg.o build\1_1\lexer.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\parser.o build\1_1\pbraces.o build\1_1\filters.o build\1_1\renderer.o build\1_1\filter_tmpl.o build\1_1\rodread.o build\1_1\memfiles.o build\1_1\rodwrite.o build\1_1\passes.o build\1_1\types.o build\1_1\trees.o build\1_1\magicsys.o build\1_1\nimsets.o build\1_1\bitsets.o build\1_1\semthreads.o build\1_1\importer.o build\1_1\lookups.o build\1_1\semdata.o build\1_1\treetab.o build\1_1\evals.o build\1_1\semfold.o build\1_1\transf.o build\1_1\cgmeth.o build\1_1\sem.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\aliases.o build\1_1\docgen.o build\1_1\rstast.o build\1_1\rst.o build\1_1\rstgen.o build\1_1\highlite.o build\1_1\cgen.o build\1_1\ccgutils.o build\1_1\cgendata.o build\1_1\ccgmerge.o build\1_1\ecmasgen.o build\1_1\passaux.o build\1_1\depends.o build\1_1\parseopt.o
ECHO SUCCESS ECHO SUCCESS

View file

@ -143,8 +143,12 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\aliases.c -o build\1_2\aliases.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\aliases.c -o build\1_2\aliases.o %CC% %COMP_FLAGS% -Ibuild -c build\1_2\aliases.c -o build\1_2\aliases.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen.c -o build\1_2\docgen.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen.c -o build\1_2\docgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen.c -o build\1_2\docgen.o %CC% %COMP_FLAGS% -Ibuild -c build\1_2\docgen.c -o build\1_2\docgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstast.c -o build\1_2\rstast.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstast.c -o build\1_2\rstast.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rst.c -o build\1_2\rst.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rst.c -o build\1_2\rst.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rst.c -o build\1_2\rst.o %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rst.c -o build\1_2\rst.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstgen.c -o build\1_2\rstgen.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\rstgen.c -o build\1_2\rstgen.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\highlite.c -o build\1_2\highlite.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\highlite.c -o build\1_2\highlite.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\highlite.c -o build\1_2\highlite.o %CC% %COMP_FLAGS% -Ibuild -c build\1_2\highlite.c -o build\1_2\highlite.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgen.c -o build\1_2\cgen.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\cgen.c -o build\1_2\cgen.o
@ -164,8 +168,8 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\depends.c -o build\1_2\depends.o
ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseopt.c -o build\1_2\parseopt.o ECHO %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseopt.c -o build\1_2\parseopt.o
%CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseopt.c -o build\1_2\parseopt.o %CC% %COMP_FLAGS% -Ibuild -c build\1_2\parseopt.c -o build\1_2\parseopt.o
ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_2\nim__dat.o build\1_2\system.o build\1_2\nimrod.o build\1_2\times.o build\1_2\strutils.o build\1_2\parseutils.o build\1_2\winlean.o build\1_2\commands.o build\1_2\os.o build\1_2\msgs.o build\1_2\options.o build\1_2\lists.o build\1_2\strtabs.o build\1_2\hashes.o build\1_2\tables.o build\1_2\math.o build\1_2\nversion.o build\1_2\condsyms.o build\1_2\ast.o build\1_2\crc.o build\1_2\ropes.o build\1_2\platform.o build\1_2\idents.o build\1_2\intsets.o build\1_2\idgen.o build\1_2\astalgo.o build\1_2\rodutils.o build\1_2\extccomp.o build\1_2\osproc.o build\1_2\streams.o build\1_2\wordrecg.o build\1_2\lexer.o build\1_2\lexbase.o build\1_2\llstream.o build\1_2\nimconf.o build\1_2\main.o build\1_2\syntaxes.o build\1_2\parser.o build\1_2\pbraces.o build\1_2\filters.o build\1_2\renderer.o build\1_2\filter_tmpl.o build\1_2\rodread.o build\1_2\memfiles.o build\1_2\rodwrite.o build\1_2\passes.o build\1_2\types.o build\1_2\trees.o build\1_2\magicsys.o build\1_2\nimsets.o build\1_2\bitsets.o build\1_2\semthreads.o build\1_2\importer.o build\1_2\lookups.o build\1_2\semdata.o build\1_2\treetab.o build\1_2\evals.o build\1_2\semfold.o build\1_2\transf.o build\1_2\cgmeth.o build\1_2\sem.o build\1_2\procfind.o build\1_2\pragmas.o build\1_2\semtypinst.o build\1_2\sigmatch.o build\1_2\suggest.o build\1_2\aliases.o build\1_2\docgen.o build\1_2\rst.o build\1_2\highlite.o build\1_2\cgen.o build\1_2\ccgutils.o build\1_2\cgendata.o build\1_2\ccgmerge.o build\1_2\ecmasgen.o build\1_2\passaux.o build\1_2\depends.o build\1_2\parseopt.o ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_2\nim__dat.o build\1_2\system.o build\1_2\nimrod.o build\1_2\times.o build\1_2\strutils.o build\1_2\parseutils.o build\1_2\winlean.o build\1_2\commands.o build\1_2\os.o build\1_2\msgs.o build\1_2\options.o build\1_2\lists.o build\1_2\strtabs.o build\1_2\hashes.o build\1_2\tables.o build\1_2\math.o build\1_2\nversion.o build\1_2\condsyms.o build\1_2\ast.o build\1_2\crc.o build\1_2\ropes.o build\1_2\platform.o build\1_2\idents.o build\1_2\intsets.o build\1_2\idgen.o build\1_2\astalgo.o build\1_2\rodutils.o build\1_2\extccomp.o build\1_2\osproc.o build\1_2\streams.o build\1_2\wordrecg.o build\1_2\lexer.o build\1_2\lexbase.o build\1_2\llstream.o build\1_2\nimconf.o build\1_2\main.o build\1_2\syntaxes.o build\1_2\parser.o build\1_2\pbraces.o build\1_2\filters.o build\1_2\renderer.o build\1_2\filter_tmpl.o build\1_2\rodread.o build\1_2\memfiles.o build\1_2\rodwrite.o build\1_2\passes.o build\1_2\types.o build\1_2\trees.o build\1_2\magicsys.o build\1_2\nimsets.o build\1_2\bitsets.o build\1_2\semthreads.o build\1_2\importer.o build\1_2\lookups.o build\1_2\semdata.o build\1_2\treetab.o build\1_2\evals.o build\1_2\semfold.o build\1_2\transf.o build\1_2\cgmeth.o build\1_2\sem.o build\1_2\procfind.o build\1_2\pragmas.o build\1_2\semtypinst.o build\1_2\sigmatch.o build\1_2\suggest.o build\1_2\aliases.o build\1_2\docgen.o build\1_2\rstast.o build\1_2\rst.o build\1_2\rstgen.o build\1_2\highlite.o build\1_2\cgen.o build\1_2\ccgutils.o build\1_2\cgendata.o build\1_2\ccgmerge.o build\1_2\ecmasgen.o build\1_2\passaux.o build\1_2\depends.o build\1_2\parseopt.o
%LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_2\nim__dat.o build\1_2\system.o build\1_2\nimrod.o build\1_2\times.o build\1_2\strutils.o build\1_2\parseutils.o build\1_2\winlean.o build\1_2\commands.o build\1_2\os.o build\1_2\msgs.o build\1_2\options.o build\1_2\lists.o build\1_2\strtabs.o build\1_2\hashes.o build\1_2\tables.o build\1_2\math.o build\1_2\nversion.o build\1_2\condsyms.o build\1_2\ast.o build\1_2\crc.o build\1_2\ropes.o build\1_2\platform.o build\1_2\idents.o build\1_2\intsets.o build\1_2\idgen.o build\1_2\astalgo.o build\1_2\rodutils.o build\1_2\extccomp.o build\1_2\osproc.o build\1_2\streams.o build\1_2\wordrecg.o build\1_2\lexer.o build\1_2\lexbase.o build\1_2\llstream.o build\1_2\nimconf.o build\1_2\main.o build\1_2\syntaxes.o build\1_2\parser.o build\1_2\pbraces.o build\1_2\filters.o build\1_2\renderer.o build\1_2\filter_tmpl.o build\1_2\rodread.o build\1_2\memfiles.o build\1_2\rodwrite.o build\1_2\passes.o build\1_2\types.o build\1_2\trees.o build\1_2\magicsys.o build\1_2\nimsets.o build\1_2\bitsets.o build\1_2\semthreads.o build\1_2\importer.o build\1_2\lookups.o build\1_2\semdata.o build\1_2\treetab.o build\1_2\evals.o build\1_2\semfold.o build\1_2\transf.o build\1_2\cgmeth.o build\1_2\sem.o build\1_2\procfind.o build\1_2\pragmas.o build\1_2\semtypinst.o build\1_2\sigmatch.o build\1_2\suggest.o build\1_2\aliases.o build\1_2\docgen.o build\1_2\rst.o build\1_2\highlite.o build\1_2\cgen.o build\1_2\ccgutils.o build\1_2\cgendata.o build\1_2\ccgmerge.o build\1_2\ecmasgen.o build\1_2\passaux.o build\1_2\depends.o build\1_2\parseopt.o %LINKER% %LINK_FLAGS% -o bin\nimrod.exe build\1_2\nim__dat.o build\1_2\system.o build\1_2\nimrod.o build\1_2\times.o build\1_2\strutils.o build\1_2\parseutils.o build\1_2\winlean.o build\1_2\commands.o build\1_2\os.o build\1_2\msgs.o build\1_2\options.o build\1_2\lists.o build\1_2\strtabs.o build\1_2\hashes.o build\1_2\tables.o build\1_2\math.o build\1_2\nversion.o build\1_2\condsyms.o build\1_2\ast.o build\1_2\crc.o build\1_2\ropes.o build\1_2\platform.o build\1_2\idents.o build\1_2\intsets.o build\1_2\idgen.o build\1_2\astalgo.o build\1_2\rodutils.o build\1_2\extccomp.o build\1_2\osproc.o build\1_2\streams.o build\1_2\wordrecg.o build\1_2\lexer.o build\1_2\lexbase.o build\1_2\llstream.o build\1_2\nimconf.o build\1_2\main.o build\1_2\syntaxes.o build\1_2\parser.o build\1_2\pbraces.o build\1_2\filters.o build\1_2\renderer.o build\1_2\filter_tmpl.o build\1_2\rodread.o build\1_2\memfiles.o build\1_2\rodwrite.o build\1_2\passes.o build\1_2\types.o build\1_2\trees.o build\1_2\magicsys.o build\1_2\nimsets.o build\1_2\bitsets.o build\1_2\semthreads.o build\1_2\importer.o build\1_2\lookups.o build\1_2\semdata.o build\1_2\treetab.o build\1_2\evals.o build\1_2\semfold.o build\1_2\transf.o build\1_2\cgmeth.o build\1_2\sem.o build\1_2\procfind.o build\1_2\pragmas.o build\1_2\semtypinst.o build\1_2\sigmatch.o build\1_2\suggest.o build\1_2\aliases.o build\1_2\docgen.o build\1_2\rstast.o build\1_2\rst.o build\1_2\rstgen.o build\1_2\highlite.o build\1_2\cgen.o build\1_2\ccgutils.o build\1_2\cgendata.o build\1_2\ccgmerge.o build\1_2\ecmasgen.o build\1_2\passaux.o build\1_2\depends.o build\1_2\parseopt.o
ECHO SUCCESS ECHO SUCCESS

View file

@ -52,9 +52,15 @@ type
nkInt16Lit, nkInt16Lit,
nkInt32Lit, nkInt32Lit,
nkInt64Lit, nkInt64Lit,
nkUIntLit, # an unsigned integer literal
nkUInt8Lit,
nkUInt16Lit,
nkUInt32Lit,
nkUInt64Lit,
nkFloatLit, # a floating point literal nkFloatLit, # a floating point literal
nkFloat32Lit, nkFloat32Lit,
nkFloat64Lit, nkFloat64Lit,
nkFloat128Lit,
nkStrLit, # a string literal "" nkStrLit, # a string literal ""
nkRStrLit, # a raw string literal r"" nkRStrLit, # a raw string literal r""
nkTripleStrLit, # a triple string literal """ nkTripleStrLit, # a triple string literal """
@ -237,6 +243,7 @@ type
sfNamedParamCall, # symbol needs named parameter call syntax in target sfNamedParamCall, # symbol needs named parameter call syntax in target
# language; for interfacing with Objective C # language; for interfacing with Objective C
sfDiscardable # returned value may be discarded implicitely sfDiscardable # returned value may be discarded implicitely
sfDestructor # proc is destructor
TSymFlags* = set[TSymFlag] TSymFlags* = set[TSymFlag]
@ -325,6 +332,8 @@ type
tfEnumHasHoles, # enum cannot be mapped into a range tfEnumHasHoles, # enum cannot be mapped into a range
tfShallow, # type can be shallow copied on assignment tfShallow, # type can be shallow copied on assignment
tfThread, # proc type is marked as ``thread`` tfThread, # proc type is marked as ``thread``
tfUniIntLit # type represents literal value that could be either
# singed or unsigned integer (e.g. 100)
tfFromGeneric # type is an instantiation of a generic; this is needed tfFromGeneric # type is an instantiation of a generic; this is needed
# because for instantiations of objects, structural # because for instantiations of objects, structural
# type equality has to be used # type equality has to be used
@ -408,8 +417,11 @@ type
mNewString, mNewStringOfCap, mNewString, mNewStringOfCap,
mReset, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mArray, mOpenArray, mRange, mSet, mSeq,
mOrdinal, mInt, mInt8, mInt16, mInt32, mOrdinal,
mInt64, mFloat, mFloat32, mFloat64, mBool, mChar, mString, mCstring, mInt, mInt8, mInt16, mInt32, mInt64,
mUInt, mUInt8, mUInt16, mUInt32, mUInt64,
mFloat, mFloat32, mFloat64, mFloat128,
mBool, mChar, mString, mCstring,
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc, mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
mVoidType, mPNimrodNode, mVoidType, mPNimrodNode,
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
@ -464,9 +476,9 @@ type
info*: TLineInfo info*: TLineInfo
flags*: TNodeFlags flags*: TNodeFlags
case Kind*: TNodeKind case Kind*: TNodeKind
of nkCharLit..nkInt64Lit: of nkCharLit..nkUInt64Lit:
intVal*: biggestInt intVal*: biggestInt
of nkFloatLit..nkFloat64Lit: of nkFloatLit..nkFloat128Lit:
floatVal*: biggestFloat floatVal*: biggestFloat
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
strVal*: string strVal*: string
@ -765,8 +777,8 @@ const # for all kind of hash tables:
proc ValueToString*(a: PNode): string = proc ValueToString*(a: PNode): string =
case a.kind case a.kind
of nkCharLit..nkInt64Lit: result = $(a.intVal) of nkCharLit..nkUInt64Lit: result = $(a.intVal)
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result = $(a.floatVal) of nkFloatLit..nkFloat128Lit: result = $(a.floatVal)
of nkStrLit..nkTripleStrLit: result = a.strVal of nkStrLit..nkTripleStrLit: result = a.strVal
else: else:
InternalError(a.info, "valueToString") InternalError(a.info, "valueToString")
@ -888,6 +900,7 @@ proc assignType(dest, src: PType) =
dest.size = src.size dest.size = src.size
dest.align = src.align dest.align = src.align
dest.containerID = src.containerID dest.containerID = src.containerID
dest.destructor = src.destructor
# this fixes 'type TLock = TSysLock': # this fixes 'type TLock = TSysLock':
if src.sym != nil: if src.sym != nil:
if dest.sym != nil: if dest.sym != nil:
@ -1020,8 +1033,8 @@ proc copyNode(src: PNode): PNode =
result.typ = src.typ result.typ = src.typ
result.flags = src.flags * PersistentNodeFlags result.flags = src.flags * PersistentNodeFlags
case src.Kind case src.Kind
of nkCharLit..nkInt64Lit: result.intVal = src.intVal of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result.floatVal = src.floatVal of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym of nkSym: result.sym = src.sym
of nkIdent: result.ident = src.ident of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
@ -1035,8 +1048,8 @@ proc shallowCopy*(src: PNode): PNode =
result.typ = src.typ result.typ = src.typ
result.flags = src.flags * PersistentNodeFlags result.flags = src.flags * PersistentNodeFlags
case src.Kind case src.Kind
of nkCharLit..nkInt64Lit: result.intVal = src.intVal of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result.floatVal = src.floatVal of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym of nkSym: result.sym = src.sym
of nkIdent: result.ident = src.ident of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
@ -1051,8 +1064,8 @@ proc copyTree(src: PNode): PNode =
result.typ = src.typ result.typ = src.typ
result.flags = src.flags * PersistentNodeFlags result.flags = src.flags * PersistentNodeFlags
case src.Kind case src.Kind
of nkCharLit..nkInt64Lit: result.intVal = src.intVal of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result.floatVal = src.floatVal of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym of nkSym: result.sym = src.sym
of nkIdent: result.ident = src.ident of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
@ -1102,14 +1115,14 @@ proc sonsNotNil(n: PNode): bool =
proc getInt*(a: PNode): biggestInt = proc getInt*(a: PNode): biggestInt =
case a.kind case a.kind
of nkIntLit..nkInt64Lit: result = a.intVal of nkIntLit..nkUInt64Lit: result = a.intVal
else: else:
internalError(a.info, "getInt") internalError(a.info, "getInt")
result = 0 result = 0
proc getFloat*(a: PNode): biggestFloat = proc getFloat*(a: PNode): biggestFloat =
case a.kind case a.kind
of nkFloatLit..nkFloat64Lit: result = a.floatVal of nkFloatLit..nkFloat128Lit: result = a.floatVal
else: else:
internalError(a.info, "getFloat") internalError(a.info, "getFloat")
result = 0.0 result = 0.0

View file

@ -274,10 +274,10 @@ proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int,
for i in countup(0, high(n.data)): for i in countup(0, high(n.data)):
if n.data[i] != nil: if n.data[i] != nil:
if mycount > 0: app(result, ",") if mycount > 0: app(result, ",")
appf(result, "$n$1$2", appf(result, "$N$1$2",
[istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)]) [istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
inc(mycount) inc(mycount)
if mycount > 0: appf(result, "$n$1", [spaces(indent)]) if mycount > 0: appf(result, "$N$1", [spaces(indent)])
app(result, "]") app(result, "]")
assert(mycount == n.counter) assert(mycount == n.counter)
@ -288,9 +288,9 @@ proc ropeConstr(indent: int, c: openarray[PRope]): PRope =
var i = 0 var i = 0
while i <= high(c): while i <= high(c):
if i > 0: app(result, ",") if i > 0: app(result, ",")
appf(result, "$n$1\"$2\": $3", [istr, c[i], c[i + 1]]) appf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
inc(i, 2) inc(i, 2)
appf(result, "$n$1}", [spaces(indent)]) appf(result, "$N$1}", [spaces(indent)])
proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int, proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
maxRecDepth: int): PRope = maxRecDepth: int): PRope =
@ -325,9 +325,9 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
result = toRope("[") result = toRope("[")
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: app(result, ",") if i > 0: app(result, ",")
appf(result, "$n$1$2", [spaces(indent + 4), typeToYamlAux(n.sons[i], appf(result, "$N$1$2", [spaces(indent + 4), typeToYamlAux(n.sons[i],
marker, indent + 4, maxRecDepth - 1)]) marker, indent + 4, maxRecDepth - 1)])
appf(result, "$n$1]", [spaces(indent + 2)]) appf(result, "$N$1]", [spaces(indent + 2)])
else: else:
result = toRope("null") result = toRope("null")
result = ropeConstr(indent, [toRope("kind"), result = ropeConstr(indent, [toRope("kind"),
@ -347,36 +347,36 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
result = toRope("null") result = toRope("null")
else: else:
var istr = spaces(indent + 2) var istr = spaces(indent + 2)
result = ropef("{$n$1\"kind\": $2", [istr, makeYamlString($n.kind)]) result = ropef("{$N$1\"kind\": $2", [istr, makeYamlString($n.kind)])
if maxRecDepth != 0: if maxRecDepth != 0:
appf(result, ",$n$1\"info\": $2", [istr, lineInfoToStr(n.info)]) appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
case n.kind case n.kind
of nkCharLit..nkInt64Lit: of nkCharLit..nkInt64Lit:
appf(result, ",$n$1\"intVal\": $2", [istr, toRope(n.intVal)]) appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, ",$n$1\"floatVal\": $2", appf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.ToStrMaxPrecision)]) [istr, toRope(n.floatVal.ToStrMaxPrecision)])
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
appf(result, ",$n$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym: of nkSym:
appf(result, ",$n$1\"sym\": $2", appf(result, ",$N$1\"sym\": $2",
[istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)]) [istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
of nkIdent: of nkIdent:
if n.ident != nil: if n.ident != nil:
appf(result, ",$n$1\"ident\": $2", [istr, makeYamlString(n.ident.s)]) appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
else: else:
appf(result, ",$n$1\"ident\": null", [istr]) appf(result, ",$N$1\"ident\": null", [istr])
else: else:
if sonsLen(n) > 0: if sonsLen(n) > 0:
appf(result, ",$n$1\"sons\": [", [istr]) appf(result, ",$N$1\"sons\": [", [istr])
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: app(result, ",") if i > 0: app(result, ",")
appf(result, "$n$1$2", [spaces(indent + 4), treeToYamlAux(n.sons[i], appf(result, "$N$1$2", [spaces(indent + 4), treeToYamlAux(n.sons[i],
marker, indent + 4, maxRecDepth - 1)]) marker, indent + 4, maxRecDepth - 1)])
appf(result, "$n$1]", [istr]) appf(result, "$N$1]", [istr])
appf(result, ",$n$1\"typ\": $2", appf(result, ",$N$1\"typ\": $2",
[istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)]) [istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
appf(result, "$n$1}", [spaces(indent)]) appf(result, "$N$1}", [spaces(indent)])
proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope = proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope =
var marker = InitIntSet() var marker = InitIntSet()
@ -413,34 +413,34 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
result = toRope("null") result = toRope("null")
else: else:
var istr = spaces(indent + 2) var istr = spaces(indent + 2)
result = ropef("{$n$1\"kind\": $2", result = ropef("{$N$1\"kind\": $2",
[istr, makeYamlString($n.kind)]) [istr, makeYamlString($n.kind)])
if maxRecDepth != 0: if maxRecDepth != 0:
case n.kind case n.kind
of nkCharLit..nkInt64Lit: of nkCharLit..nkInt64Lit:
appf(result, ",$n$1\"intVal\": $2", [istr, toRope(n.intVal)]) appf(result, ",$N$1\"intVal\": $2", [istr, toRope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
appf(result, ",$n$1\"floatVal\": $2", appf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.ToStrMaxPrecision)]) [istr, toRope(n.floatVal.ToStrMaxPrecision)])
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
appf(result, ",$n$1\"strVal\": $2", [istr, makeYamlString(n.strVal)]) appf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
of nkSym: of nkSym:
appf(result, ",$n$1\"sym\": $2_$3", appf(result, ",$N$1\"sym\": $2_$3",
[istr, toRope(n.sym.name.s), toRope(n.sym.id)]) [istr, toRope(n.sym.name.s), toRope(n.sym.id)])
of nkIdent: of nkIdent:
if n.ident != nil: if n.ident != nil:
appf(result, ",$n$1\"ident\": $2", [istr, makeYamlString(n.ident.s)]) appf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
else: else:
appf(result, ",$n$1\"ident\": null", [istr]) appf(result, ",$N$1\"ident\": null", [istr])
else: else:
if sonsLen(n) > 0: if sonsLen(n) > 0:
appf(result, ",$n$1\"sons\": [", [istr]) appf(result, ",$N$1\"sons\": [", [istr])
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: app(result, ",") if i > 0: app(result, ",")
appf(result, "$n$1$2", [spaces(indent + 4), debugTree(n.sons[i], appf(result, "$N$1$2", [spaces(indent + 4), debugTree(n.sons[i],
indent + 4, maxRecDepth - 1)]) indent + 4, maxRecDepth - 1)])
appf(result, "$n$1]", [istr]) appf(result, "$N$1]", [istr])
appf(result, "$n$1}", [spaces(indent)]) appf(result, "$N$1}", [spaces(indent)])
proc debug(n: PSym) = proc debug(n: PSym) =
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1))) #writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))

View file

@ -33,16 +33,14 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
# reset before pass as 'result' var: # reset before pass as 'result' var:
resetLoc(p, d) resetLoc(p, d)
app(pl, addrLoc(d)) app(pl, addrLoc(d))
app(pl, ")") appf(pl, ");$n")
app(p.s(cpsStmts), pl) line(p, cpsStmts, pl)
appf(p.s(cpsStmts), ";$n")
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp) getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp)) app(pl, addrLoc(tmp))
app(pl, ")") appf(pl, ");$n")
app(p.s(cpsStmts), pl) line(p, cpsStmts, pl)
appf(p.s(cpsStmts), ";$n")
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
app(pl, ")") app(pl, ")")
@ -53,9 +51,8 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
list.r = pl list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
app(pl, ")") appf(pl, ");$n")
app(p.s(cpsStmts), pl) line(p, cpsStmts, pl)
appf(p.s(cpsStmts), ";$n")
proc isInCurrentFrame(p: BProc, n: PNode): bool = proc isInCurrentFrame(p: BProc, n: PNode): bool =
# checks if `n` is an expression that refers to the current frame; # checks if `n` is an expression that refers to the current frame;
@ -148,7 +145,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc addComma(r: PRope): PRope = proc addComma(r: PRope): PRope =
result = if r == nil: r else: con(r, ", ") result = if r == nil: r else: con(r, ", ")
const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2)" const CallPattern = "$1.ClEnv? $1.ClPrc($3$1.ClEnv) : (($4)($1.ClPrc))($2);$n"
var op: TLoc var op: TLoc
initLocExpr(p, ri.sons[0], op) initLocExpr(p, ri.sons[0], op)
var pl: PRope var pl: PRope
@ -166,7 +163,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if i < length - 1: app(pl, ", ") if i < length - 1: app(pl, ", ")
template genCallPattern = template genCallPattern =
appf(p.s(cpsStmts), CallPattern, op.r, pl, pl.addComma, rawProc) lineF(p, cpsStmts, CallPattern, op.r, pl, pl.addComma, rawProc)
let rawProc = getRawProcType(p, typ) let rawProc = getRawProcType(p, typ)
if typ.sons[0] != nil: if typ.sons[0] != nil:
@ -181,13 +178,11 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
resetLoc(p, d) resetLoc(p, d)
app(pl, addrLoc(d)) app(pl, addrLoc(d))
genCallPattern() genCallPattern()
appf(p.s(cpsStmts), ";$n")
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp) getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp)) app(pl, addrLoc(tmp))
genCallPattern() genCallPattern()
appf(p.s(cpsStmts), ";$n")
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
if d.k == locNone: getTemp(p, typ.sons[0], d) if d.k == locNone: getTemp(p, typ.sons[0], d)
@ -198,7 +193,6 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
genCallPattern() genCallPattern()
appf(p.s(cpsStmts), ";$n")
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op, a: TLoc var op, a: TLoc
@ -264,16 +258,14 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
if d.k == locNone: getTemp(p, typ.sons[0], d) if d.k == locNone: getTemp(p, typ.sons[0], d)
app(pl, "Result: ") app(pl, "Result: ")
app(pl, addrLoc(d)) app(pl, addrLoc(d))
app(pl, "]") appf(pl, "];$n")
app(p.s(cpsStmts), pl) line(p, cpsStmts, pl)
appf(p.s(cpsStmts), ";$n")
else: else:
var tmp: TLoc var tmp: TLoc
getTemp(p, typ.sons[0], tmp) getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp)) app(pl, addrLoc(tmp))
app(pl, "]") appf(pl, "];$n")
app(p.s(cpsStmts), pl) line(p, cpsStmts, pl)
appf(p.s(cpsStmts), ";$n")
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
app(pl, "]") app(pl, "]")
@ -284,9 +276,8 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
list.r = pl list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying genAssignment(p, d, list, {}) # no need for deep copying
else: else:
app(pl, "]") appf(pl, "];$n")
app(p.s(cpsStmts), pl) line(p, cpsStmts, pl)
appf(p.s(cpsStmts), ";$n")
proc genCall(p: BProc, e: PNode, d: var TLoc) = proc genCall(p: BProc, e: PNode, d: var TLoc) =
if e.sons[0].typ.callConv == ccClosure: if e.sons[0].typ.callConv == ccClosure:

View file

@ -34,7 +34,7 @@ proc int32Literal(i: Int): PRope =
proc genHexLiteral(v: PNode): PRope = proc genHexLiteral(v: PNode): PRope =
# hex literals are unsigned in C # hex literals are unsigned in C
# so we don't generate hex literals any longer. # so we don't generate hex literals any longer.
if not (v.kind in {nkIntLit..nkInt64Lit}): if not (v.kind in {nkIntLit..nkUInt64Lit}):
internalError(v.info, "genHexLiteral") internalError(v.info, "genHexLiteral")
result = intLiteral(v.intVal) result = intLiteral(v.intVal)
@ -47,7 +47,7 @@ proc getStrLit(m: BModule, s: string): PRope =
proc genLiteral(p: BProc, v: PNode, ty: PType): PRope = proc genLiteral(p: BProc, v: PNode, ty: PType): PRope =
if ty == nil: internalError(v.info, "genLiteral: ty is nil") if ty == nil: internalError(v.info, "genLiteral: ty is nil")
case v.kind case v.kind
of nkCharLit..nkInt64Lit: of nkCharLit..nkUInt64Lit:
case skipTypes(ty, abstractVarRange).kind case skipTypes(ty, abstractVarRange).kind
of tyChar, tyInt64, tyNil: of tyChar, tyInt64, tyNil:
result = intLiteral(v.intVal) result = intLiteral(v.intVal)
@ -160,7 +160,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if dest.s == OnStack or optRefcGC notin gGlobalOptions: if dest.s == OnStack or optRefcGC notin gGlobalOptions:
appf(p.s(cpsStmts), "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) lineF(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
if needToKeepAlive in flags: keepAlive(p, dest) if needToKeepAlive in flags: keepAlive(p, dest)
elif dest.s == OnHeap: elif dest.s == OnHeap:
# location is on heap # location is on heap
@ -168,25 +168,25 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# #
# if afSrcIsNotNil in flags: # if afSrcIsNotNil in flags:
# UseMagic(p.module, 'nimGCref') # UseMagic(p.module, 'nimGCref')
# appf(p.s[cpsStmts], 'nimGCref($1);$n', [rdLoc(src)]) # lineF(p, cpsStmts, 'nimGCref($1);$n', [rdLoc(src)])
# elif afSrcIsNil notin flags: # elif afSrcIsNil notin flags:
# UseMagic(p.module, 'nimGCref') # UseMagic(p.module, 'nimGCref')
# appf(p.s[cpsStmts], 'if ($1) nimGCref($1);$n', [rdLoc(src)]) # lineF(p, cpsStmts, 'if ($1) nimGCref($1);$n', [rdLoc(src)])
# if afDestIsNotNil in flags: # if afDestIsNotNil in flags:
# UseMagic(p.module, 'nimGCunref') # UseMagic(p.module, 'nimGCunref')
# appf(p.s[cpsStmts], 'nimGCunref($1);$n', [rdLoc(dest)]) # lineF(p, cpsStmts, 'nimGCunref($1);$n', [rdLoc(dest)])
# elif afDestIsNil notin flags: # elif afDestIsNil notin flags:
# UseMagic(p.module, 'nimGCunref') # UseMagic(p.module, 'nimGCunref')
# appf(p.s[cpsStmts], 'if ($1) nimGCunref($1);$n', [rdLoc(dest)]) # lineF(p, cpsStmts, 'if ($1) nimGCunref($1);$n', [rdLoc(dest)])
# appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]) # lineF(p, cpsStmts, '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
if canFormAcycle(dest.t): if canFormAcycle(dest.t):
appcg(p.module, p.s(cpsStmts), "#asgnRef((void**) $1, $2);$n", lineCg(p, cpsStmts, "#asgnRef((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)]) [addrLoc(dest), rdLoc(src)])
else: else:
appcg(p.module, p.s(cpsStmts), "#asgnRefNoCycle((void**) $1, $2);$n", lineCg(p, cpsStmts, "#asgnRefNoCycle((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)]) [addrLoc(dest), rdLoc(src)])
else: else:
appcg(p.module, p.s(cpsStmts), "#unsureAsgnRef((void**) $1, $2);$n", lineCg(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)]) [addrLoc(dest), rdLoc(src)])
if needToKeepAlive in flags: keepAlive(p, dest) if needToKeepAlive in flags: keepAlive(p, dest)
@ -200,15 +200,15 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if needToCopy notin flags or if needToCopy notin flags or
tfShallow in skipTypes(dest.t, abstractVarRange).flags: tfShallow in skipTypes(dest.t, abstractVarRange).flags:
if dest.s == OnStack or optRefcGC notin gGlobalOptions: if dest.s == OnStack or optRefcGC notin gGlobalOptions:
appcg(p, cpsStmts, lineCg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
[addrLoc(dest), addrLoc(src), rdLoc(dest)]) [addrLoc(dest), addrLoc(src), rdLoc(dest)])
if needToKeepAlive in flags: keepAlive(p, dest) if needToKeepAlive in flags: keepAlive(p, dest)
else: else:
appcg(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n", lineCg(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)]) [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
else: else:
appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", lineCg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)]) [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
@ -216,7 +216,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# the assignment operation in C. # the assignment operation in C.
if src.t != nil and src.t.kind == tyPtr: if src.t != nil and src.t.kind == tyPtr:
# little HACK to support the new 'var T' as return type: # little HACK to support the new 'var T' as return type:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) lineCg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
return return
var ty = skipTypes(dest.t, abstractVarRange) var ty = skipTypes(dest.t, abstractVarRange)
case ty.kind case ty.kind
@ -226,24 +226,24 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if needToCopy notin flags: if needToCopy notin flags:
genRefAssign(p, dest, src, flags) genRefAssign(p, dest, src, flags)
else: else:
appcg(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", lineCg(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
[addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)]) [addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)])
of tyString: of tyString:
if needToCopy notin flags: if needToCopy notin flags:
genRefAssign(p, dest, src, flags) genRefAssign(p, dest, src, flags)
else: else:
if dest.s == OnStack or optRefcGC notin gGlobalOptions: if dest.s == OnStack or optRefcGC notin gGlobalOptions:
appcg(p, cpsStmts, "$1 = #copyString($2);$n", [dest.rdLoc, src.rdLoc]) lineCg(p, cpsStmts, "$1 = #copyString($2);$n", [dest.rdLoc, src.rdLoc])
if needToKeepAlive in flags: keepAlive(p, dest) if needToKeepAlive in flags: keepAlive(p, dest)
elif dest.s == OnHeap: elif dest.s == OnHeap:
# we use a temporary to care for the dreaded self assignment: # we use a temporary to care for the dreaded self assignment:
var tmp: TLoc var tmp: TLoc
getTemp(p, ty, tmp) getTemp(p, ty, tmp)
appcg(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n", lineCg(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n",
[dest.rdLoc, src.rdLoc, tmp.rdLoc]) [dest.rdLoc, src.rdLoc, tmp.rdLoc])
appcg(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", tmp.rdLoc) lineCg(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", tmp.rdLoc)
else: else:
appcg(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n", lineCg(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
[addrLoc(dest), rdLoc(src)]) [addrLoc(dest), rdLoc(src)])
if needToKeepAlive in flags: keepAlive(p, dest) if needToKeepAlive in flags: keepAlive(p, dest)
of tyTuple, tyObject, tyProc: of tyTuple, tyObject, tyProc:
@ -251,34 +251,34 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if needsComplexAssignment(dest.t): if needsComplexAssignment(dest.t):
genGenericAsgn(p, dest, src, flags) genGenericAsgn(p, dest, src, flags)
else: else:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) lineCg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
if needsComplexAssignment(dest.t): if needsComplexAssignment(dest.t):
genGenericAsgn(p, dest, src, flags) genGenericAsgn(p, dest, src, flags)
else: else:
appcg(p, cpsStmts, lineCg(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 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?
if needsComplexAssignment(dest.t): if needsComplexAssignment(dest.t):
appcg(p, cpsStmts, # XXX: is this correct for arrays? lineCg(p, cpsStmts, # XXX: is this correct for arrays?
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n", "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)]) [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
else: else:
appcg(p, cpsStmts, lineCg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len0);$n", "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len0);$n",
[rdLoc(dest), rdLoc(src)]) [rdLoc(dest), rdLoc(src)])
of tySet: of tySet:
if mapType(ty) == ctArray: if mapType(ty) == ctArray:
appcg(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n", lineCg(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
[rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))]) [rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))])
else: else:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) lineCg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString, of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
tyInt..tyFloat128, tyRange: tyInt..tyUInt64, tyRange:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)]) lineCg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
else: InternalError("genAssignment(" & $ty.kind & ')') else: InternalError("genAssignment(" & $ty.kind & ')')
proc expr(p: BProc, e: PNode, d: var TLoc) proc expr(p: BProc, e: PNode, d: var TLoc)
@ -317,20 +317,20 @@ proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
if d.k != locNone: InternalError(e.info, "binaryStmt") if d.k != locNone: InternalError(e.info, "binaryStmt")
InitLocExpr(p, e.sons[1], d) InitLocExpr(p, e.sons[1], d)
InitLocExpr(p, e.sons[2], b) InitLocExpr(p, e.sons[2], b)
appcg(p, cpsStmts, frmt, [rdLoc(d), rdLoc(b)]) lineCg(p, cpsStmts, frmt, [rdLoc(d), rdLoc(b)])
proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc var a: TLoc
if (d.k != locNone): InternalError(e.info, "unaryStmt") if (d.k != locNone): InternalError(e.info, "unaryStmt")
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
appcg(p, cpsStmts, frmt, [rdLoc(a)]) lineCg(p, cpsStmts, frmt, [rdLoc(a)])
proc binaryStmtChar(p: BProc, e: PNode, d: var TLoc, frmt: string) = proc binaryStmtChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc var a, b: TLoc
if (d.k != locNone): InternalError(e.info, "binaryStmtChar") if (d.k != locNone): InternalError(e.info, "binaryStmtChar")
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b) InitLocExpr(p, e.sons[2], b)
appcg(p, cpsStmts, frmt, [rdCharLoc(a), rdCharLoc(b)]) lineCg(p, cpsStmts, frmt, [rdCharLoc(a), rdCharLoc(b)])
proc binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) = proc binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc var a, b: TLoc
@ -382,11 +382,11 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
else: else:
storage = getTypeDesc(p.module, t) storage = getTypeDesc(p.module, t)
var tmp = getTempName() var tmp = getTempName()
appcg(p, cpsLocals, "$1 $2;$n", [storage, tmp]) lineCg(p, cpsLocals, "$1 $2;$n", [storage, tmp])
appcg(p, cpsStmts, "$1 = #$2($3, $4);$n", [tmp, toRope(prc[m]), lineCg(p, cpsStmts, "$1 = #$2($3, $4);$n", [tmp, toRope(prc[m]),
rdLoc(a), rdLoc(b)]) rdLoc(a), rdLoc(b)])
if size < platform.IntSize or t.kind in {tyRange, tyEnum, tySet}: if size < platform.IntSize or t.kind in {tyRange, tyEnum, tySet}:
appcg(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n", lineCg(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n",
[tmp, intLiteral(firstOrd(t)), intLiteral(lastOrd(t))]) [tmp, intLiteral(firstOrd(t)), intLiteral(lastOrd(t))])
putIntoDest(p, d, e.typ, ropef("(NI$1)($2)", [toRope(getSize(t)*8), tmp])) putIntoDest(p, d, e.typ, ropef("(NI$1)($2)", [toRope(getSize(t)*8), tmp]))
@ -404,7 +404,7 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
t = skipTypes(e.typ, abstractRange) t = skipTypes(e.typ, abstractRange)
if optOverflowCheck in p.options: if optOverflowCheck in p.options:
appcg(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n", lineCg(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
[rdLoc(a), intLiteral(firstOrd(t))]) [rdLoc(a), intLiteral(firstOrd(t))])
putIntoDest(p, d, e.typ, ropef(opr[m], [rdLoc(a), toRope(getSize(t) * 8)])) putIntoDest(p, d, e.typ, ropef(opr[m], [rdLoc(a), toRope(getSize(t) * 8)]))
@ -582,7 +582,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
var ty = a.t var ty = a.t
var r = rdLoc(a) var r = rdLoc(a)
case e.sons[1].kind case e.sons[1].kind
of nkIntLit..nkInt64Lit: i = int(e.sons[1].intVal) of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem") else: internalError(e.info, "genTupleElem")
when false: when false:
if ty.n != nil: if ty.n != nil:
@ -634,11 +634,11 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
if id == gBackendId: strLit = getStrLit(p.module, field.name.s) if id == gBackendId: strLit = getStrLit(p.module, field.name.s)
else: strLit = con("TMP", toRope(id)) else: strLit = con("TMP", toRope(id))
if op.magic == mNot: if op.magic == mNot:
appcg(p, cpsStmts, lineCg(p, cpsStmts,
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n", "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
[rdLoc(test), strLit]) [rdLoc(test), strLit])
else: else:
appcg(p, cpsStmts, lineCg(p, cpsStmts,
"if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n", "if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
[rdLoc(test), strLit]) [rdLoc(test), strLit])
appf(r, ".$1", [field.loc.r]) appf(r, ".$1", [field.loc.r])
@ -658,10 +658,10 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
# semantic pass has already checked for const index expressions # semantic pass has already checked for const index expressions
if firstOrd(ty) == 0: if firstOrd(ty) == 0:
if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)): if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)):
appcg(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError();$n", lineCg(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError();$n",
[rdCharLoc(b), intLiteral(lastOrd(ty))]) [rdCharLoc(b), intLiteral(lastOrd(ty))])
else: else:
appcg(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n", lineCg(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
[rdCharLoc(b), first, intLiteral(lastOrd(ty))]) [rdCharLoc(b), first, intLiteral(lastOrd(ty))])
if d.k == locNone: d.s = a.s if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)), putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
@ -681,7 +681,7 @@ proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b) # emit range check: initLocExpr(p, e.sons[1], b) # emit range check:
if optBoundsCheck in p.options: if optBoundsCheck in p.options:
appcg(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n", lineCg(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n",
[rdLoc(b), rdLoc(a)]) # BUGFIX: ``>=`` and not ``>``! [rdLoc(b), rdLoc(a)]) # BUGFIX: ``>=`` and not ``>``!
if d.k == locNone: d.s = a.s if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)), putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
@ -696,11 +696,11 @@ proc genSeqElem(p: BPRoc, e: PNode, d: var TLoc) =
ty = skipTypes(ty.sons[0], abstractVarRange) # emit range check: ty = skipTypes(ty.sons[0], abstractVarRange) # emit range check:
if optBoundsCheck in p.options: if optBoundsCheck in p.options:
if ty.kind == tyString: if ty.kind == tyString:
appcg(p, cpsStmts, lineCg(p, cpsStmts,
"if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", "if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
[rdLoc(b), rdLoc(a), lenField()]) [rdLoc(b), rdLoc(a), lenField()])
else: else:
appcg(p, cpsStmts, lineCg(p, cpsStmts,
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", "if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
[rdLoc(b), rdLoc(a), lenField()]) [rdLoc(b), rdLoc(a), lenField()])
if d.k == locNone: d.s = OnHeap if d.k == locNone: d.s = OnHeap
@ -737,9 +737,9 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
expr(p, e.sons[1], tmp) expr(p, e.sons[1], tmp)
L = getLabel(p) L = getLabel(p)
if m == mOr: if m == mOr:
appf(p.s(cpsStmts), "if ($1) goto $2;$n", [rdLoc(tmp), L]) lineF(p, cpsStmts, "if ($1) goto $2;$n", [rdLoc(tmp), L])
else: else:
appf(p.s(cpsStmts), "if (!($1)) goto $2;$n", [rdLoc(tmp), L]) lineF(p, cpsStmts, "if (!($1)) goto $2;$n", [rdLoc(tmp), L])
expr(p, e.sons[2], tmp) expr(p, e.sons[2], tmp)
fixLabel(p, L) fixLabel(p, L)
if d.k == locNone: if d.k == locNone:
@ -772,9 +772,9 @@ proc genIfExpr(p: BProc, n: PNode, d: var TLoc) =
of nkElifExpr: of nkElifExpr:
initLocExpr(p, it.sons[0], a) initLocExpr(p, it.sons[0], a)
Lelse = getLabel(p) Lelse = getLabel(p)
appf(p.s(cpsStmts), "if (!$1) goto $2;$n", [rdLoc(a), Lelse]) lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), Lelse])
expr(p, it.sons[1], tmp) expr(p, it.sons[1], tmp)
appf(p.s(cpsStmts), "goto $1;$n", [Lend]) lineF(p, cpsStmts, "goto $1;$n", [Lend])
fixLabel(p, Lelse) fixLabel(p, Lelse)
of nkElseExpr: of nkElseExpr:
expr(p, it.sons[0], tmp) expr(p, it.sons[0], tmp)
@ -793,7 +793,7 @@ proc genEcho(p: BProc, n: PNode) =
for i in countup(1, n.len-1): for i in countup(1, n.len-1):
initLocExpr(p, n.sons[i], a) initLocExpr(p, n.sons[i], a)
appf(args, ", ($1)->data", [rdLoc(a)]) appf(args, ", ($1)->data", [rdLoc(a)])
appcg(p, cpsStmts, "printf($1$2);$n", [ lineCg(p, cpsStmts, "printf($1$2);$n", [
makeCString(repeatStr(n.len-1, "%s") & tnl), args]) makeCString(repeatStr(n.len-1, "%s") & tnl), args])
include ccgcalls include ccgcalls
@ -825,14 +825,14 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[i + 1], a) initLocExpr(p, e.sons[i + 1], a)
if skipTypes(e.sons[i + 1].Typ, abstractVarRange).kind == tyChar: if skipTypes(e.sons[i + 1].Typ, abstractVarRange).kind == tyChar:
Inc(L) Inc(L)
appcg(p.module, appends, "#appendChar($1, $2);$n", [tmp.r, rdLoc(a)]) appLineCg(p, appends, "#appendChar($1, $2);$n", [tmp.r, rdLoc(a)])
else: else:
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}: if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
Inc(L, len(e.sons[i + 1].strVal)) Inc(L, len(e.sons[i + 1].strVal))
else: else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()]) appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
appcg(p.module, appends, "#appendString($1, $2);$n", [tmp.r, rdLoc(a)]) appLineCg(p, appends, "#appendString($1, $2);$n", [tmp.r, rdLoc(a)])
appcg(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, toRope(L)]) lineCg(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, toRope(L)])
app(p.s(cpsStmts), appends) app(p.s(cpsStmts), appends)
if d.k == locNone: if d.k == locNone:
d = tmp d = tmp
@ -863,16 +863,16 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[i + 2], a) initLocExpr(p, e.sons[i + 2], a)
if skipTypes(e.sons[i + 2].Typ, abstractVarRange).kind == tyChar: if skipTypes(e.sons[i + 2].Typ, abstractVarRange).kind == tyChar:
Inc(L) Inc(L)
appcg(p.module, appends, "#appendChar($1, $2);$n", appLineCg(p, appends, "#appendChar($1, $2);$n",
[rdLoc(dest), rdLoc(a)]) [rdLoc(dest), rdLoc(a)])
else: else:
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}: if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
Inc(L, len(e.sons[i + 2].strVal)) Inc(L, len(e.sons[i + 2].strVal))
else: else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()]) appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
appcg(p.module, appends, "#appendString($1, $2);$n", appLineCg(p, appends, "#appendString($1, $2);$n",
[rdLoc(dest), rdLoc(a)]) [rdLoc(dest), rdLoc(a)])
appcg(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", lineCg(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
[rdLoc(dest), lens, toRope(L)]) [rdLoc(dest), lens, toRope(L)])
keepAlive(p, dest) keepAlive(p, dest)
app(p.s(cpsStmts), appends) app(p.s(cpsStmts), appends)
@ -881,10 +881,15 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq &= x --> # seq &= x -->
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
# seq->data[seq->len-1] = x; # seq->data[seq->len-1] = x;
let seqAppendPattern = if gCmd != cmdCompileToCpp:
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
else:
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
var a, b, dest: TLoc var a, b, dest: TLoc
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b) InitLocExpr(p, e.sons[2], b)
appcg(p, cpsStmts, "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n", [ lineCg(p, cpsStmts, seqAppendPattern, [
rdLoc(a), rdLoc(a),
getTypeDesc(p.module, skipTypes(e.sons[1].typ, abstractVar)), getTypeDesc(p.module, skipTypes(e.sons[1].typ, abstractVar)),
getTypeDesc(p.module, skipTypes(e.sons[2].Typ, abstractVar))]) getTypeDesc(p.module, skipTypes(e.sons[2].Typ, abstractVar))])
@ -896,7 +901,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
proc genReset(p: BProc, n: PNode) = proc genReset(p: BProc, n: PNode) =
var a: TLoc var a: TLoc
InitLocExpr(p, n.sons[1], a) InitLocExpr(p, n.sons[1], a)
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", lineCg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange))]) [addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange))])
proc genNew(p: BProc, e: PNode) = proc genNew(p: BProc, e: PNode) =
@ -912,11 +917,11 @@ proc genNew(p: BProc, e: PNode) =
if a.s == OnHeap and optRefcGc in gGlobalOptions: if a.s == OnHeap and optRefcGc in gGlobalOptions:
# use newObjRC1 as an optimization; and we don't need 'keepAlive' either # use newObjRC1 as an optimization; and we don't need 'keepAlive' either
if canFormAcycle(a.t): if canFormAcycle(a.t):
appcg(p, cpsStmts, "if ($1) #nimGCunref($1);$n", a.rdLoc) lineCg(p, cpsStmts, "if ($1) #nimGCunref($1);$n", a.rdLoc)
else: else:
appcg(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", a.rdLoc) lineCg(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", a.rdLoc)
b.r = ropecg(p.module, "($1) #newObjRC1($2, sizeof($3))", args) b.r = ropecg(p.module, "($1) #newObjRC1($2, sizeof($3))", args)
appcg(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc) lineCg(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc)
else: else:
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", args) b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", args)
genAssignment(p, a, b, {needToKeepAlive}) # set the object type: genAssignment(p, a, b, {needToKeepAlive}) # set the object type:
@ -930,9 +935,9 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
var call: TLoc var call: TLoc
initLoc(call, locExpr, dest.t, OnHeap) initLoc(call, locExpr, dest.t, OnHeap)
if dest.s == OnHeap and optRefcGc in gGlobalOptions: if dest.s == OnHeap and optRefcGc in gGlobalOptions:
appcg(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc) lineCg(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc)
call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args) call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
appcg(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc) lineCg(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
else: else:
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args) call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
genAssignment(p, dest, call, {needToKeepAlive}) genAssignment(p, dest, call, {needToKeepAlive})
@ -1114,8 +1119,12 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b) InitLocExpr(p, e.sons[2], b)
var t = skipTypes(e.sons[1].typ, abstractVar) var t = skipTypes(e.sons[1].typ, abstractVar)
appcg(p, cpsStmts, let setLenPattern = if gCmd != cmdCompileToCpp:
"$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n", [ "$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n"
else:
"$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n"
lineCg(p, cpsStmts, setLenPattern, [
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t), rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
getTypeDesc(p.module, t.sons[0])]) getTypeDesc(p.module, t.sons[0])])
keepAlive(p, a) keepAlive(p, a)
@ -1172,7 +1181,7 @@ proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
assert(d.k == locNone) assert(d.k == locNone)
InitLocExpr(p, e.sons[1], a) InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b) InitLocExpr(p, e.sons[2], b)
appf(p.s(cpsStmts), frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]) lineF(p, cpsStmts, frmt, [rdLoc(a), rdSetElemLoc(b, a.t)])
proc genInOp(p: BProc, e: PNode, d: var TLoc) = proc genInOp(p: BProc, e: PNode, d: var TLoc) =
var a, b, x, y: TLoc var a, b, x, y: TLoc
@ -1248,7 +1257,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, a.t, d) if d.k == locNone: getTemp(p, a.t, d)
appf(p.s(cpsStmts), lookupOpr[op], lineF(p, cpsStmts, lookupOpr[op],
[rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)]) [rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
of mEqSet: of mEqSet:
binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)") binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)")
@ -1258,7 +1267,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, a.t, d) if d.k == locNone: getTemp(p, a.t, d)
appf(p.s(cpsStmts), lineF(p, cpsStmts,
"for ($1 = 0; $1 < $2; $1++) $n" & "for ($1 = 0; $1 < $2; $1++) $n" &
" $3[$1] = $4[$1] $6 $5[$1];$n", [ " $3[$1] = $4[$1] $6 $5[$1];$n", [
rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b), rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b),
@ -1347,9 +1356,9 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
putIntoDest(p, d, e.typ, ropef("($2 $1 $3)", [ putIntoDest(p, d, e.typ, ropef("($2 $1 $3)", [
toRope(opr[m]), rdLoc(a), rdLoc(b)])) toRope(opr[m]), rdLoc(a), rdLoc(b)]))
if optNanCheck in p.options: if optNanCheck in p.options:
appcg(p, cpsStmts, "#nanCheck($1);$n", [rdLoc(d)]) lineCg(p, cpsStmts, "#nanCheck($1);$n", [rdLoc(d)])
if optInfCheck in p.options: if optInfCheck in p.options:
appcg(p, cpsStmts, "#infCheck($1);$n", [rdLoc(d)]) lineCg(p, cpsStmts, "#infCheck($1);$n", [rdLoc(d)])
else: else:
binaryArith(p, e, d, m) binaryArith(p, e, d, m)
@ -1470,35 +1479,35 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
if d.k == locNone: getTemp(p, e.typ, d) if d.k == locNone: getTemp(p, e.typ, d)
if getSize(e.typ) > 8: if getSize(e.typ) > 8:
# big set: # big set:
appf(p.s(cpsStmts), "memset($1, 0, sizeof($1));$n", [rdLoc(d)]) lineF(p, cpsStmts, "memset($1, 0, sizeof($1));$n", [rdLoc(d)])
for i in countup(0, sonsLen(e) - 1): for i in countup(0, sonsLen(e) - 1):
if e.sons[i].kind == nkRange: if e.sons[i].kind == nkRange:
getTemp(p, getSysType(tyInt), idx) # our counter getTemp(p, getSysType(tyInt), idx) # our counter
initLocExpr(p, e.sons[i].sons[0], a) initLocExpr(p, e.sons[i].sons[0], a)
initLocExpr(p, e.sons[i].sons[1], b) initLocExpr(p, e.sons[i].sons[1], b)
appf(p.s(cpsStmts), "for ($1 = $3; $1 <= $4; $1++) $n" & lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
"$2[$1/8] |=(1<<($1%8));$n", [rdLoc(idx), rdLoc(d), "$2[$1/8] |=(1<<($1%8));$n", [rdLoc(idx), rdLoc(d),
rdSetElemLoc(a, e.typ), rdSetElemLoc(b, e.typ)]) rdSetElemLoc(a, e.typ), rdSetElemLoc(b, e.typ)])
else: else:
initLocExpr(p, e.sons[i], a) initLocExpr(p, e.sons[i], a)
appf(p.s(cpsStmts), "$1[$2/8] |=(1<<($2%8));$n", lineF(p, cpsStmts, "$1[$2/8] |=(1<<($2%8));$n",
[rdLoc(d), rdSetElemLoc(a, e.typ)]) [rdLoc(d), rdSetElemLoc(a, e.typ)])
else: else:
# small set # small set
var ts = "NI" & $(getSize(e.typ) * 8) var ts = "NI" & $(getSize(e.typ) * 8)
appf(p.s(cpsStmts), "$1 = 0;$n", [rdLoc(d)]) lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)])
for i in countup(0, sonsLen(e) - 1): for i in countup(0, sonsLen(e) - 1):
if e.sons[i].kind == nkRange: if e.sons[i].kind == nkRange:
getTemp(p, getSysType(tyInt), idx) # our counter getTemp(p, getSysType(tyInt), idx) # our counter
initLocExpr(p, e.sons[i].sons[0], a) initLocExpr(p, e.sons[i].sons[0], a)
initLocExpr(p, e.sons[i].sons[1], b) initLocExpr(p, e.sons[i].sons[1], b)
appf(p.s(cpsStmts), "for ($1 = $3; $1 <= $4; $1++) $n" & lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
"$2 |=(1<<((" & ts & ")($1)%(sizeof(" & ts & ")*8)));$n", [ "$2 |=(1<<((" & ts & ")($1)%(sizeof(" & ts & ")*8)));$n", [
rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ), rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
rdSetElemLoc(b, e.typ)]) rdSetElemLoc(b, e.typ)])
else: else:
initLocExpr(p, e.sons[i], a) initLocExpr(p, e.sons[i], a)
appf(p.s(cpsStmts), lineF(p, cpsStmts,
"$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n", "$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n",
[rdLoc(d), rdSetElemLoc(a, e.typ)]) [rdLoc(d), rdSetElemLoc(a, e.typ)])
@ -1539,7 +1548,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
initLocExpr(p, n.sons[1], b) initLocExpr(p, n.sons[1], b)
getTemp(p, n.typ, tmp) getTemp(p, n.typ, tmp)
appcg(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n", lineCg(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
tmp.rdLoc, a.rdLoc, b.rdLoc) tmp.rdLoc, a.rdLoc, b.rdLoc)
putLocIntoDest(p, d, tmp) putLocIntoDest(p, d, tmp)
@ -1579,10 +1588,10 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
app(r, ".Sup") app(r, ".Sup")
t = skipTypes(t.sons[0], abstractInst) t = skipTypes(t.sons[0], abstractInst)
if nilCheck != nil: if nilCheck != nil:
appcg(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n", lineCg(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
[nilCheck, r, genTypeInfo(p.module, dest)]) [nilCheck, r, genTypeInfo(p.module, dest)])
else: else:
appcg(p, cpsStmts, "#chckObj($1.m_type, $2);$n", lineCg(p, cpsStmts, "#chckObj($1.m_type, $2);$n",
[r, genTypeInfo(p.module, dest)]) [r, genTypeInfo(p.module, dest)])
if n.sons[0].typ.kind != tyObject: if n.sons[0].typ.kind != tyObject:
putIntoDest(p, d, n.typ, putIntoDest(p, d, n.typ,
@ -1675,8 +1684,8 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
InternalError(e.info, "expr: param not init " & sym.name.s) InternalError(e.info, "expr: param not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc) putLocIntoDest(p, d, sym.loc)
else: InternalError(e.info, "expr(" & $sym.kind & "); unknown symbol") else: InternalError(e.info, "expr(" & $sym.kind & "); unknown symbol")
of nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit, nkFloatLit..nkFloat64Lit, of nkStrLit..nkTripleStrLit, nkIntLit..nkUInt64Lit,
nkNilLit, nkCharLit: nkFloatLit..nkFloat128Lit, nkNilLit, nkCharLit:
putIntoDest(p, d, e.typ, genLiteral(p, e)) putIntoDest(p, d, e.typ, genLiteral(p, e))
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand, of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
nkCallStrLit: nkCallStrLit:

View file

@ -49,12 +49,12 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
proc startBlock(p: BProc, start: TFormatStr = "{$n", proc startBlock(p: BProc, start: TFormatStr = "{$n",
args: openarray[PRope]): int {.discardable.} = args: openarray[PRope]): int {.discardable.} =
lineCg(p, cpsStmts, start, args)
inc(p.labels) inc(p.labels)
result = len(p.blocks) result = len(p.blocks)
setlen(p.blocks, result + 1) setlen(p.blocks, result + 1)
p.blocks[result].id = p.labels p.blocks[result].id = p.labels
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len p.blocks[result].nestedTryStmts = p.nestedTryStmts.len
appcg(p, cpsLocals, start, args)
proc assignLabel(b: var TBlock): PRope {.inline.} = proc assignLabel(b: var TBlock): PRope {.inline.} =
b.label = con("LA", b.id.toRope) b.label = con("LA", b.id.toRope)
@ -70,7 +70,7 @@ proc endBlock(p: BProc, blockEnd: PRope) =
setlen(p.blocks, topBlock) setlen(p.blocks, topBlock)
# this is done after the block is popped so $n is # this is done after the block is popped so $n is
# properly indented when pretty printing is enabled # properly indented when pretty printing is enabled
app(p.s(cpsStmts), blockEnd) line(p, cpsStmts, blockEnd)
var gBlockEndBracket = ropef("}$n") var gBlockEndBracket = ropef("}$n")
@ -184,12 +184,12 @@ proc genIfStmt(p: BProc, n: PNode) =
initLocExpr(p, it.sons[0], a) initLocExpr(p, it.sons[0], a)
Lelse = getLabel(p) Lelse = getLabel(p)
inc(p.labels) inc(p.labels)
appff(p.s(cpsStmts), "if (!$1) goto $2;$n", lineFF(p, cpsStmts, "if (!$1) goto $2;$n",
"br i1 $1, label %LOC$3, label %$2$n" & "LOC$3: $n", "br i1 $1, label %LOC$3, label %$2$n" & "LOC$3: $n",
[rdLoc(a), Lelse, toRope(p.labels)]) [rdLoc(a), Lelse, toRope(p.labels)])
genSimpleBlock(p, it.sons[1]) genSimpleBlock(p, it.sons[1])
if sonsLen(n) > 1: if sonsLen(n) > 1:
appff(p.s(cpsStmts), "goto $1;$n", "br label %$1$n", [Lend]) lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [Lend])
fixLabel(p, Lelse) fixLabel(p, Lelse)
of nkElse: of nkElse:
genSimpleBlock(p, it.sons[0]) genSimpleBlock(p, it.sons[0])
@ -205,23 +205,29 @@ proc blockLeaveActions(p: BProc, howMany: int) =
stack[i-1] = p.nestedTryStmts[L-i] stack[i-1] = p.nestedTryStmts[L-i]
setLen(p.nestedTryStmts, L-howMany) setLen(p.nestedTryStmts, L-howMany)
var alreadyPoppedCnt = p.inExceptBlock
for tryStmt in items(stack): for tryStmt in items(stack):
appcg(p, cpsStmts, "#popSafePoint();$n", []) if gCmd != cmdCompileToCpp:
if alreadyPoppedCnt > 0:
dec alreadyPoppedCnt
else:
lineCg(p, cpsStmts, "#popSafePoint();$n", [])
var finallyStmt = lastSon(tryStmt) var finallyStmt = lastSon(tryStmt)
if finallyStmt.kind == nkFinally: if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0]) genStmts(p, finallyStmt.sons[0])
# push old elements again: # push old elements again:
for i in countdown(howMany-1, 0): for i in countdown(howMany-1, 0):
p.nestedTryStmts.add(stack[i]) p.nestedTryStmts.add(stack[i])
for i in countdown(p.popCurrExc-1, 0): if gCmd != cmdCompileToCpp:
appcg(p, cpsStmts, "#popCurrentException();$n", []) for i in countdown(p.inExceptBlock-1, 0):
lineCg(p, cpsStmts, "#popCurrentException();$n", [])
proc genReturnStmt(p: BProc, t: PNode) = proc genReturnStmt(p: BProc, t: PNode) =
p.beforeRetNeeded = true p.beforeRetNeeded = true
genLineDir(p, t) genLineDir(p, t)
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0]) if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
blockLeaveActions(p, min(1, p.nestedTryStmts.len)) blockLeaveActions(p, min(1, p.nestedTryStmts.len))
appff(p.s(cpsStmts), "goto BeforeRet;$n", "br label %BeforeRet$n", []) lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
proc genWhileStmt(p: BProc, t: PNode) = proc genWhileStmt(p: BProc, t: PNode) =
# we don't generate labels here as for example GCC would produce # we don't generate labels here as for example GCC would produce
@ -239,7 +245,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
initLocExpr(p, t.sons[0], a) initLocExpr(p, t.sons[0], a)
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0): if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
let label = assignLabel(p.blocks[p.breakIdx]) let label = assignLabel(p.blocks[p.breakIdx])
appf(p.s(cpsStmts), "if (!$1) goto $2;$n", [rdLoc(a), label]) lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
genStmts(p, t.sons[1]) genStmts(p, t.sons[1])
endBlock(p) endBlock(p)
@ -273,7 +279,7 @@ proc genParForStmt(p: BProc, t: PNode) =
initLocExpr(p, call.sons[1], rangeA) initLocExpr(p, call.sons[1], rangeA)
initLocExpr(p, call.sons[2], rangeB) initLocExpr(p, call.sons[2], rangeB)
appf(p.s(cpsStmts), "#pragma omp parallel for $4$n" & lineF(p, cpsStmts, "#pragma omp parallel for $4$n" &
"for ($1 = $2; $1 <= $3; ++$1)", "for ($1 = $2; $1 <= $3; ++$1)",
forLoopVar.loc.rdLoc, forLoopVar.loc.rdLoc,
rangeA.rdLoc, rangeB.rdLoc, rangeA.rdLoc, rangeB.rdLoc,
@ -302,29 +308,35 @@ proc genBreakStmt(p: BProc, t: PNode) =
let label = assignLabel(p.blocks[idx]) let label = assignLabel(p.blocks[idx])
blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts) blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts)
genLineDir(p, t) genLineDir(p, t)
appf(p.s(cpsStmts), "goto $1;$n", [label]) lineF(p, cpsStmts, "goto $1;$n", [label])
proc getRaiseFrmt(p: BProc): string = proc getRaiseFrmt(p: BProc): string =
#if gCmd == cmdCompileToCpp: if gCmd == cmdCompileToCpp:
# result = "throw #nimException($1, $2);$n" result = "throw NimException($1, $2);$n"
#else: else:
result = "#raiseException((#E_Base*)$1, $2);$n" result = "#raiseException((#E_Base*)$1, $2);$n"
proc genRaiseStmt(p: BProc, t: PNode) = proc genRaiseStmt(p: BProc, t: PNode) =
if p.inExceptBlock > 0:
# if the current try stmt have a finally block,
# we must execute it before reraising
var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon
if finallyBlock.kind == nkFinally:
genSimpleBlock(p, finallyBlock.sons[0])
if t.sons[0].kind != nkEmpty: if t.sons[0].kind != nkEmpty:
var a: TLoc var a: TLoc
InitLocExpr(p, t.sons[0], a) InitLocExpr(p, t.sons[0], a)
var e = rdLoc(a) var e = rdLoc(a)
var typ = skipTypes(t.sons[0].typ, abstractPtrs) var typ = skipTypes(t.sons[0].typ, abstractPtrs)
genLineDir(p, t) genLineDir(p, t)
appcg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)]) lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)])
else: else:
genLineDir(p, t) genLineDir(p, t)
# reraise the last exception: # reraise the last exception:
#if gCmd == cmdCompileToCpp: if gCmd == cmdCompileToCpp:
# appcg(p, cpsStmts, "throw;$n") lineCg(p, cpsStmts, "throw;$n")
#else: else:
appcg(p, cpsStmts, "#reraiseException();$n") lineCg(p, cpsStmts, "#reraiseException();$n")
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) =
@ -335,20 +347,20 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
if b.sons[i].kind == nkRange: if b.sons[i].kind == nkRange:
initLocExpr(p, b.sons[i].sons[0], x) initLocExpr(p, b.sons[i].sons[0], x)
initLocExpr(p, b.sons[i].sons[1], y) initLocExpr(p, b.sons[i].sons[1], y)
appcg(p, cpsStmts, rangeFormat, lineCg(p, cpsStmts, rangeFormat,
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl]) [rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
else: else:
initLocExpr(p, b.sons[i], x) initLocExpr(p, b.sons[i], x)
appcg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl]) lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel = proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel =
var Lend = getLabel(p) var Lend = getLabel(p)
for i in 1..until: for i in 1..until:
appf(p.s(cpsStmts), "LA$1: ;$n", [toRope(labId + i)]) lineF(p, cpsStmts, "LA$1: ;$n", [toRope(labId + i)])
if t.sons[i].kind == nkOfBranch: if t.sons[i].kind == nkOfBranch:
var length = sonsLen(t.sons[i]) var length = sonsLen(t.sons[i])
genSimpleBlock(p, t.sons[i].sons[length - 1]) genSimpleBlock(p, t.sons[i].sons[length - 1])
appf(p.s(cpsStmts), "goto $1;$n", [Lend]) lineF(p, cpsStmts, "goto $1;$n", [Lend])
else: else:
genSimpleBlock(p, t.sons[i].sons[0]) genSimpleBlock(p, t.sons[i].sons[0])
result = Lend result = Lend
@ -363,13 +375,13 @@ proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr,
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)]) lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
if until < t.len-1: if until < t.len-1:
inc(p.labels) inc(p.labels)
var gotoTarget = p.labels var gotoTarget = p.labels
appf(p.s(cpsStmts), "goto LA$1;$n", [toRope(gotoTarget)]) lineF(p, cpsStmts, "goto LA$1;$n", [toRope(gotoTarget)])
result = genCaseSecondPass(p, t, labId, until) result = genCaseSecondPass(p, t, labId, until)
appf(p.s(cpsStmts), "LA$1: ;$n", [toRope(gotoTarget)]) lineF(p, cpsStmts, "LA$1: ;$n", [toRope(gotoTarget)])
else: else:
result = genCaseSecondPass(p, t, labId, until) result = genCaseSecondPass(p, t, labId, until)
@ -411,7 +423,7 @@ proc genStringCase(p: BProc, t: PNode) =
else: else:
# else statement: nothing to do yet # else statement: nothing to do yet
# but we reserved a label, which we use later # but we reserved a label, which we use later
appcg(p, cpsStmts, "switch (#hashString($1) & $2) {$n", lineCg(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
[rdLoc(a), toRope(bitMask)]) [rdLoc(a), toRope(bitMask)])
for j in countup(0, high(branches)): for j in countup(0, high(branches)):
when false: when false:
@ -421,11 +433,11 @@ proc genStringCase(p: BProc, t: PNode) =
if interior != brn: if interior != brn:
echo "BUG! ", interior, "-", brn echo "BUG! ", interior, "-", brn
if branches[j] != nil: if branches[j] != nil:
appf(p.s(cpsStmts), "case $1: $n$2break;$n", lineF(p, cpsStmts, "case $1: $n$2break;$n",
[intLiteral(j), branches[j]]) [intLiteral(j), branches[j]])
appf(p.s(cpsStmts), "}$n") # else statement: lineF(p, cpsStmts, "}$n") # else statement:
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)]) lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
# third pass: generate statements # third pass: generate statements
var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1) var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1)
fixLabel(p, Lend) fixLabel(p, Lend)
@ -454,16 +466,16 @@ proc genCaseRange(p: BProc, branch: PNode) =
for j in 0 .. length-2: for j in 0 .. length-2:
if branch[j].kind == nkRange: 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", [ lineF(p, cpsStmts, "case $1 ... $2:$n", [
genLiteral(p, branch[j][0]), genLiteral(p, branch[j][0]),
genLiteral(p, branch[j][1])]) genLiteral(p, branch[j][1])])
else: else:
var v = copyNode(branch[j][0]) var v = copyNode(branch[j][0])
while v.intVal <= branch[j][1].intVal: while v.intVal <= branch[j][1].intVal:
appf(p.s(cpsStmts), "case $1:$n", [genLiteral(p, v)]) lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, v)])
Inc(v.intVal) Inc(v.intVal)
else: else:
appf(p.s(cpsStmts), "case $1:$n", [genLiteral(p, branch[j])]) lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, branch[j])])
proc genOrdinalCase(p: BProc, n: PNode) = proc genOrdinalCase(p: BProc, n: PNode) =
# analyse 'case' statement: # analyse 'case' statement:
@ -479,7 +491,7 @@ proc genOrdinalCase(p: BProc, n: PNode) =
# generate switch part (might be empty): # generate switch part (might be empty):
if splitPoint+1 < n.len: if splitPoint+1 < n.len:
appf(p.s(cpsStmts), "switch ($1) {$n", [rdCharLoc(a)]) lineF(p, cpsStmts, "switch ($1) {$n", [rdCharLoc(a)])
var hasDefault = false var hasDefault = false
for i in splitPoint+1 .. < n.len: for i in splitPoint+1 .. < n.len:
var branch = n[i] var branch = n[i]
@ -488,13 +500,13 @@ proc genOrdinalCase(p: BProc, n: PNode) =
genSimpleBlock(p, branch.lastSon) genSimpleBlock(p, branch.lastSon)
else: else:
# else part of case statement: # else part of case statement:
appf(p.s(cpsStmts), "default:$n") lineF(p, cpsStmts, "default:$n")
genSimpleBlock(p, branch[0]) genSimpleBlock(p, branch[0])
hasDefault = true hasDefault = true
appf(p.s(cpsStmts), "break;$n") lineF(p, cpsStmts, "break;$n")
if (hasAssume in CC[ccompiler].props) and not hasDefault: if (hasAssume in CC[ccompiler].props) and not hasDefault:
appf(p.s(cpsStmts), "default: __assume(0);$n") lineF(p, cpsStmts, "default: __assume(0);$n")
appf(p.s(cpsStmts), "}$n") lineF(p, cpsStmts, "}$n")
if Lend != nil: fixLabel(p, Lend) if Lend != nil: fixLabel(p, Lend)
proc genCaseStmt(p: BProc, t: PNode) = proc genCaseStmt(p: BProc, t: PNode) =
@ -521,77 +533,83 @@ proc hasGeneralExceptSection(t: PNode): bool =
proc genTryStmtCpp(p: BProc, t: PNode) = proc genTryStmtCpp(p: BProc, t: PNode) =
# code to generate: # code to generate:
# #
# bool tmpRethrow = false; # XXX: There should be a standard dispatch algorithm
# that's used both here and with multi-methods
#
# try # try
# { # {
# myDiv(4, 9); # myDiv(4, 9);
# } catch (NimException& tmp) { # } catch (NimException& exp) {
# tmpRethrow = true; # if (isObj(exp, EIO) {
# switch (tmp.exc) # ...
# { # } else if (isObj(exp, ESystem) {
# case DIVIDE_BY_ZERO: # ...
# tmpRethrow = false; # finallyPart()
# printf("Division by Zero\n"); # raise;
# break; # } else {
# default: // used for general except! # // general handler
# generalExceptPart();
# tmpRethrow = false;
# } # }
# } # }
# excHandler = excHandler->prev; // we handled the exception
# finallyPart(); # finallyPart();
# if (tmpRethrow) throw;
#
# XXX: push blocks
var var
rethrowFlag: PRope
exc: PRope exc: PRope
i, length, blen: int i, length, blen: int
genLineDir(p, t) genLineDir(p, t)
rethrowFlag = nil
exc = getTempName() exc = getTempName()
if not hasGeneralExceptSection(t): discard cgsym(p.module, "E_Base")
rethrowFlag = getTempName()
appf(p.s(cpsLocals), "volatile NIM_BOOL $1 = NIM_FALSE;$n", [rethrowFlag])
if optStackTrace in p.Options:
appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
appf(p.s(cpsStmts), "try {$n")
add(p.nestedTryStmts, t) add(p.nestedTryStmts, t)
startBlock(p, "try {$n")
genStmts(p, t.sons[0]) genStmts(p, t.sons[0])
length = sonsLen(t) length = sonsLen(t)
if t.sons[1].kind == nkExceptBranch: endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
appf(p.s(cpsStmts), "} catch (NimException& $1) {$n", [exc]) if optStackTrace in p.Options:
if rethrowFlag != nil: lineCg(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
appf(p.s(cpsStmts), "$1 = NIM_TRUE;$n", [rethrowFlag]) inc p.inExceptBlock
appf(p.s(cpsStmts), "if ($1.sp.exc) {$n", [exc])
i = 1 i = 1
var catchAllPresent = false
while (i < length) and (t.sons[i].kind == nkExceptBranch): while (i < length) and (t.sons[i].kind == nkExceptBranch):
blen = sonsLen(t.sons[i]) blen = sonsLen(t.sons[i])
if i > 1: appf(p.s(cpsStmts), "else ")
if blen == 1: if blen == 1:
# general except section: # general except section:
appf(p.s(cpsStmts), "default:$n") catchAllPresent = true
genStmts(p, t.sons[i].sons[0]) genSimpleBlock(p, t.sons[i].sons[0])
else: else:
var orExpr: PRope = nil
for j in countup(0, blen - 2): for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType) assert(t.sons[i].sons[j].kind == nkType)
appf(p.s(cpsStmts), "case $1:$n", [toRope(t.sons[i].sons[j].typ.id)]) if orExpr != nil: app(orExpr, "||")
genStmts(p, t.sons[i].sons[blen - 1]) appcg(p.module, orExpr,
if rethrowFlag != nil: "#isObj($1.exp->m_type, $2)",
appf(p.s(cpsStmts), "$1 = NIM_FALSE; ", [rethrowFlag]) [exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
appf(p.s(cpsStmts), "break;$n") lineF(p, cpsStmts, "if ($1) ", [orExpr])
genSimpleBlock(p, t.sons[i].sons[blen-1])
inc(i) inc(i)
if t.sons[1].kind == nkExceptBranch:
appf(p.s(cpsStmts), "}}$n") # end of catch-switch statement # reraise the exception if there was no catch all
appcg(p, cpsStmts, "#popSafePoint();") # and none of the handlers matched
if not catchAllPresent:
if i > 1: lineF(p, cpsStmts, "else ")
startBlock(p)
var finallyBlock = t.lastSon
if finallyBlock.kind == nkFinally:
genStmts(p, finallyBlock.sons[0])
lineCg(p, cpsStmts, "throw;$n")
endBlock(p)
lineF(p, cpsStmts, "}$n") # end of catch block
dec p.inExceptBlock
discard pop(p.nestedTryStmts) discard pop(p.nestedTryStmts)
if (i < length) and (t.sons[i].kind == nkFinally): if (i < length) and (t.sons[i].kind == nkFinally):
genStmts(p, t.sons[i].sons[0]) genSimpleBlock(p, t.sons[i].sons[0])
if rethrowFlag != nil:
appf(p.s(cpsStmts), "if ($1) { throw; }$n", [rethrowFlag])
proc genTryStmt(p: BProc, t: PNode) = proc genTryStmt(p: BProc, t: PNode) =
# code to generate: # code to generate:
# #
# XXX: There should be a standard dispatch algorithm
# that's used both here and with multi-methods
#
# TSafePoint sp; # TSafePoint sp;
# pushSafePoint(&sp); # pushSafePoint(&sp);
# sp.status = setjmp(sp.context); # sp.status = setjmp(sp.context);
@ -618,32 +636,32 @@ proc genTryStmt(p: BProc, t: PNode) =
genLineDir(p, t) genLineDir(p, t)
var safePoint = getTempName() var safePoint = getTempName()
discard cgsym(p.module, "E_Base") discard cgsym(p.module, "E_Base")
appcg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint]) lineCg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
appcg(p, cpsStmts, "#pushSafePoint(&$1);$n" & lineCg(p, cpsStmts, "#pushSafePoint(&$1);$n", [safePoint])
"$1.status = setjmp($1.context);$n", [safePoint]) lineF(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
if optStackTrace in p.Options:
appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
startBlock(p, "if ($1.status == 0) {$n", [safePoint]) startBlock(p, "if ($1.status == 0) {$n", [safePoint])
var length = sonsLen(t) var length = sonsLen(t)
add(p.nestedTryStmts, t) add(p.nestedTryStmts, t)
genStmts(p, t.sons[0]) genStmts(p, t.sons[0])
endBlock(p, ropecg(p.module, "#popSafePoint();$n } else {$n#popSafePoint();$n")) linecg(p, cpsStmts, "#popSafePoint();$n")
discard pop(p.nestedTryStmts) endBlock(p)
startBlock(p, "else {$n")
lineCg(p, cpsStmts, "#popSafePoint();$n")
if optStackTrace in p.Options:
lineCg(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
inc p.inExceptBlock
var i = 1 var i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch): while (i < length) and (t.sons[i].kind == nkExceptBranch):
var blen = sonsLen(t.sons[i]) var blen = sonsLen(t.sons[i])
if blen == 1: if blen == 1:
# general except section: # general except section:
if i > 1: appf(p.s(cpsStmts), "else") if i > 1: lineF(p, cpsStmts, "else")
startBlock(p) startBlock(p)
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint]) lineCg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
inc p.popCurrExc
genStmts(p, t.sons[i].sons[0]) genStmts(p, t.sons[i].sons[0])
dec p.popCurrExc lineCg(p, cpsStmts, "#popCurrentException();$n")
appcg(p, cpsStmts, "#popCurrentException();$n", [])
endBlock(p) endBlock(p)
else: else:
inc p.popCurrExc
var orExpr: PRope = nil var orExpr: PRope = nil
for j in countup(0, blen - 2): for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType) assert(t.sons[i].sons[j].kind == nkType)
@ -651,17 +669,19 @@ proc genTryStmt(p: BProc, t: PNode) =
appcg(p.module, orExpr, appcg(p.module, orExpr,
"#isObj(#getCurrentException()->Sup.m_type, $1)", "#isObj(#getCurrentException()->Sup.m_type, $1)",
[genTypeInfo(p.module, t.sons[i].sons[j].typ)]) [genTypeInfo(p.module, t.sons[i].sons[j].typ)])
if i > 1: app(p.s(cpsStmts), "else ") if i > 1: line(p, cpsStmts, "else ")
startBlock(p, "if ($1) {$n", [orExpr]) startBlock(p, "if ($1) {$n", [orExpr])
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint]) lineCg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
genStmts(p, t.sons[i].sons[blen-1]) genStmts(p, t.sons[i].sons[blen-1])
dec p.popCurrExc lineCg(p, cpsStmts, "#popCurrentException();$n")
endBlock(p, ropecg(p.module, "#popCurrentException();}$n")) endBlock(p)
inc(i) inc(i)
appf(p.s(cpsStmts), "}$n") # end of else block dec p.inExceptBlock
discard pop(p.nestedTryStmts)
endBlock(p) # end of else block
if i < length and t.sons[i].kind == nkFinally: if i < length and t.sons[i].kind == nkFinally:
genSimpleBlock(p, t.sons[i].sons[0]) genSimpleBlock(p, t.sons[i].sons[0])
appcg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint]) lineCg(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
proc genAsmOrEmitStmt(p: BProc, t: PNode): PRope = proc genAsmOrEmitStmt(p: BProc, t: PNode): PRope =
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
@ -688,7 +708,7 @@ proc genAsmStmt(p: BProc, t: PNode) =
assert(t.kind == nkAsmStmt) assert(t.kind == nkAsmStmt)
genLineDir(p, t) genLineDir(p, t)
var s = genAsmOrEmitStmt(p, t) var s = genAsmOrEmitStmt(p, t)
appf(p.s(cpsStmts), CC[ccompiler].asmStmtFrmt, [s]) lineF(p, cpsStmts, CC[ccompiler].asmStmtFrmt, [s])
proc genEmit(p: BProc, t: PNode) = proc genEmit(p: BProc, t: PNode) =
genLineDir(p, t) genLineDir(p, t)
@ -697,7 +717,7 @@ proc genEmit(p: BProc, t: PNode) =
# top level emit pragma? # top level emit pragma?
app(p.module.s[cfsProcHeaders], s) app(p.module.s[cfsProcHeaders], s)
else: else:
app(p.s(cpsStmts), s) line(p, cpsStmts, s)
var var
breakPointId: int = 0 breakPointId: int = 0
@ -723,7 +743,7 @@ proc genWatchpoint(p: BProc, n: PNode) =
var a: TLoc var a: TLoc
initLocExpr(p, n.sons[1], a) initLocExpr(p, n.sons[1], a)
let typ = skipTypes(n.sons[1].typ, abstractVarRange) let typ = skipTypes(n.sons[1].typ, abstractVarRange)
appcg(p, cpsStmts, "#dbgRegisterWatchpoint($1, (NCSTRING)$2, $3);$n", lineCg(p, cpsStmts, "#dbgRegisterWatchpoint($1, (NCSTRING)$2, $3);$n",
[a.addrLoc, makeCString(renderTree(n.sons[1])), [a.addrLoc, makeCString(renderTree(n.sons[1])),
genTypeInfo(p.module, typ)]) genTypeInfo(p.module, typ)])
@ -763,7 +783,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
if not ContainsOrIncl(p.module.declaredThings, field.id): if not ContainsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1", appcg(p.module, cfsVars, "extern $1",
discriminatorTableDecl(p.module, t, field)) discriminatorTableDecl(p.module, t, field))
appcg(p, cpsStmts, lineCg(p, cpsStmts,
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n", "#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field), [rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
intLiteral(L+1)]) intLiteral(L+1)])
@ -820,9 +840,8 @@ proc genStmts(p: BProc, t: PNode) =
initLocExpr(p, t.sons[0], a) initLocExpr(p, t.sons[0], a)
of nkAsmStmt: genAsmStmt(p, t) of nkAsmStmt: genAsmStmt(p, t)
of nkTryStmt: of nkTryStmt:
#if gCmd == cmdCompileToCpp: genTryStmtCpp(p, t) if gCmd == cmdCompileToCpp: genTryStmtCpp(p, t)
#else: else: genTryStmt(p, t)
genTryStmt(p, t)
of nkRaiseStmt: genRaiseStmt(p, t) of nkRaiseStmt: genRaiseStmt(p, t)
of nkTypeSection: of nkTypeSection:
# we have to emit the type information for object types here to support # we have to emit the type information for object types here to support

View file

@ -19,9 +19,9 @@ proc AccessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.ThreadVarAccessed: if emulatedThreadVars() and not p.ThreadVarAccessed:
p.ThreadVarAccessed = true p.ThreadVarAccessed = true
p.module.usesThreadVars = true p.module.usesThreadVars = true
appf(p.procSec(cpsLocals), "NimThreadVars* NimTV;$n") appf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n")
app(p.procSec(cpsInit), app(p.procSec(cpsInit),
ropecg(p.module, "NimTV=(NimThreadVars*)#GetThreadLocalVars();$n")) ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
var var
nimtv: PRope # nimrod thread vars; the struct body nimtv: PRope # nimrod thread vars; the struct body

View file

@ -31,17 +31,17 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
if (n.sons[0].kind != nkSym): InternalError(n.info, "genTraverseProc") if (n.sons[0].kind != nkSym): InternalError(n.info, "genTraverseProc")
var p = c.p var p = c.p
let disc = n.sons[0].sym let disc = n.sons[0].sym
p.s(cpsStmts).appf("switch ($1.$2) {$n", accessor, disc.loc.r) lineF(p, cpsStmts, "switch ($1.$2) {$n", accessor, disc.loc.r)
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
let branch = n.sons[i] let branch = n.sons[i]
assert branch.kind in {nkOfBranch, nkElse} assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch: if branch.kind == nkOfBranch:
genCaseRange(c.p, branch) genCaseRange(c.p, branch)
else: else:
p.s(cpsStmts).appf("default:$n") lineF(p, cpsStmts, "default:$n")
genTraverseProc(c, accessor, lastSon(branch)) genTraverseProc(c, accessor, lastSon(branch))
p.s(cpsStmts).appf("break;$n") lineF(p, cpsStmts, "break;$n")
p.s(cpsStmts).appf("} $n") lineF(p, cpsStmts, "} $n")
of nkSym: of nkSym:
let field = n.sym let field = n.sym
genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t) genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
@ -63,10 +63,10 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
let arraySize = lengthOrd(typ.sons[0]) let arraySize = lengthOrd(typ.sons[0])
var i: TLoc var i: TLoc
getTemp(p, getSysType(tyInt), i) getTemp(p, getSysType(tyInt), i)
appf(p.s(cpsStmts), "for ($1 = 0; $1 < $2; $1++) {$n", lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
i.r, arraySize.toRope) i.r, arraySize.toRope)
genTraverseProc(c, ropef("$1[$2]", accessor, i.r), typ.sons[1]) genTraverseProc(c, ropef("$1[$2]", accessor, i.r), typ.sons[1])
appf(p.s(cpsStmts), "}$n") lineF(p, cpsStmts, "}$n")
of tyObject: of tyObject:
for i in countup(0, sonsLen(typ) - 1): for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, accessor.parentObj, typ.sons[i]) genTraverseProc(c, accessor.parentObj, typ.sons[i])
@ -79,7 +79,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
for i in countup(0, sonsLen(typ) - 1): for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, ropef("$1.Field$2", accessor, i.toRope), typ.sons[i]) genTraverseProc(c, ropef("$1.Field$2", accessor, i.toRope), typ.sons[i])
of tyRef, tyString, tySequence: of tyRef, tyString, tySequence:
appcg(p, cpsStmts, c.visitorFrmt, accessor) lineCg(p, cpsStmts, c.visitorFrmt, accessor)
else: else:
# no marker procs for closures yet # no marker procs for closures yet
nil nil
@ -89,10 +89,10 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
assert typ.kind == tySequence assert typ.kind == tySequence
var i: TLoc var i: TLoc
getTemp(p, getSysType(tyInt), i) getTemp(p, getSysType(tyInt), i)
appf(p.s(cpsStmts), "for ($1 = 0; $1 < $2->$3; $1++) {$n", lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len")) i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len"))
genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0]) genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
appf(p.s(cpsStmts), "}$n") lineF(p, cpsStmts, "}$n")
proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope = proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
var c: TTraversalClosure var c: TTraversalClosure
@ -106,8 +106,8 @@ proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): PRope =
let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result) let header = ropef("N_NIMCALL(void, $1)(void* p, NI op)", result)
let t = getTypeDesc(m, typ) let t = getTypeDesc(m, typ)
p.s(cpsLocals).appf("$1 a;$n", t) lineF(p, cpsLocals, "$1 a;$n", t)
p.s(cpsInit).appf("a = ($1)p;$n", t) lineF(p, cpsInit, "a = ($1)p;$n", t)
c.p = p c.p = p
if typ.kind == tySequence: if typ.kind == tySequence:

View file

@ -174,7 +174,7 @@ proc mapType(typ: PType): TCTypeKind =
of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct
of tyString: result = ctNimStr of tyString: result = ctNimStr
of tyCString: result = ctCString of tyCString: result = ctCString
of tyInt..tyFloat128: of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt)) result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
else: InternalError("mapType") else: InternalError("mapType")
@ -313,8 +313,10 @@ proc typeNameOrLiteral(t: PType, literal: string): PRope =
proc getSimpleTypeDesc(m: BModule, typ: PType): PRope = proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
const const
NumericalTypeToStr: array[tyInt..tyFloat128, string] = ["NI", "NI8", NumericalTypeToStr: array[tyInt..tyUInt64, string] = [
"NI16", "NI32", "NI64", "NF", "NF32", "NF64", "NF128"] "NI", "NI8", "NI16", "NI32", "NI64",
"NF", "NF32", "NF64", "NF128",
"NU", "NU8", "NU16", "NU32", "NU64",]
case typ.Kind case typ.Kind
of tyPointer: of tyPointer:
result = typeNameOrLiteral(typ, "void*") result = typeNameOrLiteral(typ, "void*")
@ -337,7 +339,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL") of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL")
of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR") of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR")
of tyNil: result = typeNameOrLiteral(typ, "0") of tyNil: result = typeNameOrLiteral(typ, "0")
of tyInt..tyFloat128, tyUInt..tyUInt64: of tyInt..tyUInt64:
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.Kind]) result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.Kind])
of tyRange: result = getSimpleTypeDesc(m, typ.sons[0]) of tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
else: result = nil else: result = nil
@ -871,7 +873,7 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
if dataGenerated: return if dataGenerated: return
case t.kind case t.kind
of tyEmpty: result = toRope"0" of tyEmpty: result = toRope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyFloat128, tyVar: of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
genTypeInfoAuxBase(gNimDat, t, result, toRope"0") genTypeInfoAuxBase(gNimDat, t, result, toRope"0")
of tyProc: of tyProc:
if t.callConv != ccClosure: if t.callConv != ccClosure:

View file

@ -70,9 +70,7 @@ proc GetUniqueType*(key: PType): PType =
var k = key.kind var k = key.kind
case k case k
of tyBool, tyChar, of tyBool, tyChar,
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, tyInt..tyUInt64:
tyFloat, tyFloat32, tyFloat64, tyFloat128,
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64:
# no canonicalization for integral types, so that e.g. ``pid_t`` is # no canonicalization for integral types, so that e.g. ``pid_t`` is
# produced instead of ``NI``. # produced instead of ``NI``.
result = key result = key

View file

@ -153,6 +153,34 @@ proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: openarray[PRope]) = args: openarray[PRope]) =
app(p.s(s), ropecg(p.module, frmt, args)) app(p.s(s), ropecg(p.module, frmt, args))
var indent = "\t".toRope
proc indentLine(p: BProc, r: PRope): PRope =
result = r
for i in countup(0, p.blocks.len-1): prepend(result, indent)
proc line(p: BProc, s: TCProcSection, r: PRope) =
app(p.s(s), indentLine(p, r))
proc line(p: BProc, s: TCProcSection, r: string) =
app(p.s(s), indentLine(p, r.toRope))
proc lineF(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: openarray[PRope]) =
app(p.s(s), indentLine(p, ropef(frmt, args)))
proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: openarray[PRope]) =
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr,
args: openarray[PRope]) =
app(r, indentLine(p, ropecg(p.module, frmt, args)))
proc lineFF(p: BProc, s: TCProcSection, cformat, llvmformat: string,
args: openarray[PRope]) =
if gCmd == cmdCompileToLLVM: lineF(p, s, llvmformat, args)
else: lineF(p, s, cformat, args)
proc safeLineNm(info: TLineInfo): int = proc safeLineNm(info: TLineInfo): int =
result = toLinenumber(info) result = toLinenumber(info)
if result < 0: result = 0 # negative numbers are not allowed in #line if result < 0: result = 0 # negative numbers are not allowed in #line
@ -171,11 +199,11 @@ proc genLineDir(p: BProc, t: PNode) =
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line) genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags): (p.prc == nil or sfPure notin p.prc.flags):
appcg(p, cpsStmts, "#endb($1);$n", [toRope(line)]) lineCg(p, cpsStmts, "#endb($1);$n", [toRope(line)])
elif ({optLineTrace, optStackTrace} * p.Options == elif ({optLineTrace, optStackTrace} * p.Options ==
{optLineTrace, optStackTrace}) and {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags): (p.prc == nil or sfPure notin p.prc.flags):
appf(p.s(cpsStmts), "F.line = $1;F.filename = $2;$n", lineF(p, cpsStmts, "F.line = $1;F.filename = $2;$n",
[toRope(line), makeCString(toFilename(t.info).extractFilename)]) [toRope(line), makeCString(toFilename(t.info).extractFilename)])
include "ccgtypes.nim" include "ccgtypes.nim"
@ -211,11 +239,11 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
while (s.kind == tyObject) and (s.sons[0] != nil): while (s.kind == tyObject) and (s.sons[0] != nil):
app(r, ".Sup") app(r, ".Sup")
s = skipTypes(s.sons[0], abstractInst) s = skipTypes(s.sons[0], abstractInst)
appcg(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t)]) lineCg(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t)])
of frEmbedded: of frEmbedded:
# worst case for performance: # worst case for performance:
var r = if takeAddr: addrLoc(a) else: rdLoc(a) var r = if takeAddr: addrLoc(a) else: rdLoc(a)
appcg(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t)]) lineCg(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t)])
type type
TAssignmentFlag = enum TAssignmentFlag = enum
@ -238,16 +266,16 @@ proc resetLoc(p: BProc, loc: var TLoc) =
nilLoc.r = toRope("NIM_NIL") nilLoc.r = toRope("NIM_NIL")
genRefAssign(p, loc, nilLoc, {afSrcIsNil}) genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else: else:
appf(p.s(cpsStmts), "$1 = 0;$n", [rdLoc(loc)]) lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(loc)])
else: else:
if loc.s != OnStack: if loc.s != OnStack:
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", lineCg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(loc), genTypeInfo(p.module, loc.t)]) [addrLoc(loc), genTypeInfo(p.module, loc.t)])
# XXX: generated reset procs should not touch the m_type # XXX: generated reset procs should not touch the m_type
# field, so disabling this should be safe: # field, so disabling this should be safe:
genObjectInit(p, cpsStmts, loc.t, loc, true) genObjectInit(p, cpsStmts, loc.t, loc, true)
else: else:
appf(p.s(cpsStmts), "memset((void*)$1, 0, sizeof($2));$n", lineF(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
[addrLoc(loc), rdLoc(loc)]) [addrLoc(loc), rdLoc(loc)])
# XXX: We can be extra clever here and call memset only # XXX: We can be extra clever here and call memset only
# on the bytes following the m_type field? # on the bytes following the m_type field?
@ -255,9 +283,9 @@ proc resetLoc(p: BProc, loc: var TLoc) =
proc constructLoc(p: BProc, loc: TLoc, section = cpsStmts) = proc constructLoc(p: BProc, loc: TLoc, section = cpsStmts) =
if not isComplexValueType(skipTypes(loc.t, abstractVarRange)): if not isComplexValueType(skipTypes(loc.t, abstractVarRange)):
appf(p.s(section), "$1 = 0;$n", [rdLoc(loc)]) lineF(p, section, "$1 = 0;$n", [rdLoc(loc)])
else: else:
appf(p.s(section), "memset((void*)$1, 0, sizeof($2));$n", lineF(p, section, "memset((void*)$1, 0, sizeof($2));$n",
[addrLoc(loc), rdLoc(loc)]) [addrLoc(loc), rdLoc(loc)])
genObjectInit(p, section, loc.t, loc, true) genObjectInit(p, section, loc.t, loc, true)
@ -285,7 +313,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc) =
result.r = con("%LOC", toRope(p.labels)) result.r = con("%LOC", toRope(p.labels))
else: else:
result.r = con("LOC", toRope(p.labels)) result.r = con("LOC", toRope(p.labels))
appf(p.s(cpsLocals), "$1 $2;$n", [getTypeDesc(p.module, t), result.r]) lineF(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t), result.r])
result.k = locTemp result.k = locTemp
result.a = - 1 result.a = - 1
result.t = getUniqueType(t) result.t = getUniqueType(t)
@ -311,9 +339,9 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
result.flags = {} result.flags = {}
if not isComplexValueType(skipTypes(toKeepAlive.t, abstractVarRange)): if not isComplexValueType(skipTypes(toKeepAlive.t, abstractVarRange)):
appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(result), rdLoc(toKeepAlive)]) lineF(p, cpsStmts, "$1 = $2;$n", [rdLoc(result), rdLoc(toKeepAlive)])
else: else:
appcg(p, cpsStmts, lineCg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
[addrLoc(result), addrLoc(toKeepAlive), rdLoc(result)]) [addrLoc(result), addrLoc(toKeepAlive), rdLoc(result)])
@ -355,7 +383,7 @@ proc allocParam(p: BProc, s: PSym) =
var tmp = con("%LOC", toRope(p.labels)) var tmp = con("%LOC", toRope(p.labels))
incl(s.loc.flags, lfParamCopy) incl(s.loc.flags, lfParamCopy)
incl(s.loc.flags, lfIndirect) incl(s.loc.flags, lfIndirect)
appf(p.s(cpsInit), "$1 = alloca $3$n" & "store $3 $2, $3* $1$n", lineF(p, cpsInit, "$1 = alloca $3$n" & "store $3 $2, $3* $1$n",
[tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)]) [tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)])
s.loc.r = tmp s.loc.r = tmp
@ -365,7 +393,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
if skipTypes(s.typ, abstractVar).kind == tyOpenArray: return if skipTypes(s.typ, abstractVar).kind == tyOpenArray: return
var a = con("&", s.loc.r) var a = con("&", s.loc.r)
if (s.kind == skParam) and ccgIntroducedPtr(s): a = s.loc.r if (s.kind == skParam) and ccgIntroducedPtr(s): a = s.loc.r
appf(p.s(cpsInit), lineF(p, cpsInit,
"F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n", "F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
[toRope(p.frameLen), makeCString(normalize(s.name.s)), a, [toRope(p.frameLen), makeCString(normalize(s.name.s)), a,
genTypeInfo(p.module, s.loc.t)]) genTypeInfo(p.module, s.loc.t)])
@ -378,13 +406,14 @@ proc assignLocalVar(p: BProc, s: PSym) =
if s.loc.k == locNone: if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack) fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
app(p.s(cpsLocals), getTypeDesc(p.module, s.loc.t)) var decl = getTypeDesc(p.module, s.loc.t)
if sfRegister in s.flags: app(p.s(cpsLocals), " register") if sfRegister in s.flags: app(decl, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(p.s[cpsLocals], " GC_GUARD") # app(decl, " GC_GUARD")
if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0): if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0):
app(p.s(cpsLocals), " volatile") app(decl, " volatile")
appf(p.s(cpsLocals), " $1;$n", [s.loc.r]) appf(decl, " $1;$n", [s.loc.r])
line(p, cpsLocals, decl)
localDebugInfo(p, s) localDebugInfo(p, s)
include ccgthreadvars include ccgthreadvars
@ -427,7 +456,7 @@ proc getLabel(p: BProc): TLabel =
result = con("LA", toRope(p.labels)) result = con("LA", toRope(p.labels))
proc fixLabel(p: BProc, labl: TLabel) = proc fixLabel(p: BProc, labl: TLabel) =
appf(p.s(cpsStmts), "$1: ;$n", [labl]) lineF(p, cpsStmts, "$1: ;$n", [labl])
proc genVarPrototype(m: BModule, sym: PSym) proc genVarPrototype(m: BModule, sym: PSym)
proc requestConstImpl(p: BProc, sym: PSym) proc requestConstImpl(p: BProc, sym: PSym)
@ -545,28 +574,28 @@ proc getFrameDecl(p: BProc) =
[toRope(p.frameLen)]) [toRope(p.frameLen)])
else: else:
slots = nil slots = nil
appff(p.s(cpsLocals), "volatile struct {TFrame* prev;" & lineFF(p, cpsLocals, "volatile struct {TFrame* prev;" &
"NCSTRING procname;NI line;NCSTRING filename;" & "NCSTRING procname;NI line;NCSTRING filename;" &
"NI len;$n$1} F;$n", "NI len;$1} F;$n",
"%TF = type {%TFrame*, i8*, %NI, %NI$1}$n" & "%TF = type {%TFrame*, i8*, %NI, %NI$1}$n" &
"%F = alloca %TF$n", [slots]) "%F = alloca %TF$n", [slots])
inc(p.labels) inc(p.labels)
prepend(p.s(cpsInit), ropeff("F.len = $1;$n", prepend(p.s(cpsInit), indentLine(p, ropeff("F.len = $1;$n",
"%LOC$2 = getelementptr %TF %F, %NI 4$n" & "%LOC$2 = getelementptr %TF %F, %NI 4$n" &
"store %NI $1, %NI* %LOC$2$n", [toRope(p.frameLen), toRope(p.labels)])) "store %NI $1, %NI* %LOC$2$n", [toRope(p.frameLen), toRope(p.labels)])))
proc retIsNotVoid(s: PSym): bool = proc retIsNotVoid(s: PSym): bool =
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0]) result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
proc initFrame(p: BProc, procname, filename: PRope): PRope = proc initFrame(p: BProc, procname, filename: PRope): PRope =
result = ropecg(p.module, result = ropecg(p.module,
"F.procname = $1;$n" & "\tF.procname = $1;$n" &
"F.filename = $2;$n" & "\tF.filename = $2;$n" &
"F.line = 0;$n" & "\tF.line = 0;$n" &
"#pushFrame((TFrame*)&F);$n", [procname, filename]) "\t#pushFrame((TFrame*)&F);$n", [procname, filename])
proc deinitFrame(p: BProc): PRope = proc deinitFrame(p: BProc): PRope =
result = ropecg(p.module, "#popFrame();$n") result = ropecg(p.module, "\t#popFrame();$n")
proc closureSetup(p: BProc, prc: PSym) = proc closureSetup(p: BProc, prc: PSym) =
if prc.typ.callConv != ccClosure: return if prc.typ.callConv != ccClosure: return
@ -578,7 +607,7 @@ proc closureSetup(p: BProc, prc: PSym) =
#echo "created environment: ", env.id, " for ", prc.name.s #echo "created environment: ", env.id, " for ", prc.name.s
assignLocalVar(p, env) assignLocalVar(p, env)
# generate cast assignment: # generate cast assignment:
appcg(p, cpsStmts, "$1 = ($2) ClEnv;$n", rdLoc(env.loc), lineCg(p, cpsStmts, "$1 = ($2) ClEnv;$n", rdLoc(env.loc),
getTypeDesc(p.module, env.typ)) getTypeDesc(p.module, env.typ))
proc genProcAux(m: BModule, prc: PSym) = proc genProcAux(m: BModule, prc: PSym) =
@ -593,7 +622,7 @@ proc genProcAux(m: BModule, prc: PSym) =
# declare the result symbol: # declare the result symbol:
assignLocalVar(p, res) assignLocalVar(p, res)
assert(res.loc.r != nil) assert(res.loc.r != nil)
returnStmt = ropeff("return $1;$n", "ret $1$n", [rdLoc(res.loc)]) returnStmt = ropeff("\treturn $1;$n", "ret $1$n", [rdLoc(res.loc)])
initLocalVar(p, res, immediateAsgn=false) initLocalVar(p, res, immediateAsgn=false)
else: else:
fillResult(res) fillResult(res)
@ -609,10 +638,10 @@ proc genProcAux(m: BModule, prc: PSym) =
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc. genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
var generatedProc: PRope var generatedProc: PRope
if sfPure in prc.flags: if sfPure in prc.flags:
generatedProc = ropeff("$1 {$n$2$3$4}$n", "define $1 {$n$2$3$4}$n", generatedProc = ropeff("$N$1 {$n$2$3$4}$N$N", "define $1 {$n$2$3$4}$N",
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]) [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
else: else:
generatedProc = ropeff("$1 {$n", "define $1 {$n", [header]) generatedProc = ropeff("$N$1 {$N", "$Ndefine $1 {$N", [header])
app(generatedProc, initGCFrame(p)) app(generatedProc, initGCFrame(p))
if optStackTrace in prc.options: if optStackTrace in prc.options:
getFrameDecl(p) getFrameDecl(p)
@ -626,25 +655,25 @@ proc genProcAux(m: BModule, prc: PSym) =
if gProcProfile >= 64 * 1024: if gProcProfile >= 64 * 1024:
InternalError(prc.info, "too many procedures for profiling") InternalError(prc.info, "too many procedures for profiling")
discard cgsym(m, "profileData") discard cgsym(m, "profileData")
appf(p.s(cpsLocals), "ticks NIM_profilingStart;$n") appf(p.s(cpsLocals), "\tticks NIM_profilingStart;$n")
if prc.loc.a < 0: if prc.loc.a < 0:
appf(m.s[cfsDebugInit], "profileData[$1].procname = $2;$n", [ appf(m.s[cfsDebugInit], "\tprofileData[$1].procname = $2;$n", [
toRope(gProcProfile), toRope(gProcProfile),
makeCString(prc.name.s)]) makeCString(prc.name.s)])
prc.loc.a = gProcProfile prc.loc.a = gProcProfile
inc(gProcProfile) inc(gProcProfile)
prepend(p.s(cpsInit), ropef("NIM_profilingStart = getticks();$n")) prepend(p.s(cpsInit), ropef("\tNIM_profilingStart = getticks();$n"))
app(generatedProc, p.s(cpsInit)) app(generatedProc, p.s(cpsInit))
app(generatedProc, p.s(cpsStmts)) app(generatedProc, p.s(cpsStmts))
if p.beforeRetNeeded: appf(generatedProc, "BeforeRet: $n;") if p.beforeRetNeeded: appf(generatedProc, "\tBeforeRet: ;$n")
app(generatedProc, deinitGCFrame(p)) app(generatedProc, deinitGCFrame(p))
if optStackTrace in prc.options: app(generatedProc, deinitFrame(p)) if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM):
appf(generatedProc, appf(generatedProc,
"profileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n", "\tprofileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n",
[toRope(prc.loc.a)]) [toRope(prc.loc.a)])
app(generatedProc, returnStmt) app(generatedProc, returnStmt)
appf(generatedProc, "}$n") appf(generatedProc, "}$N")
app(m.s[cfsProcs], generatedProc) app(m.s[cfsProcs], generatedProc)
proc genProcPrototype(m: BModule, sym: PSym) = proc genProcPrototype(m: BModule, sym: PSym) =

View file

@ -37,9 +37,11 @@ type
cfsDynLibDeinit # section for deinitialization of dynamic cfsDynLibDeinit # section for deinitialization of dynamic
# libraries # libraries
TCTypeKind* = enum # describes the type kind of a C type TCTypeKind* = enum # describes the type kind of a C type
ctVoid, ctChar, ctBool, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64, ctVoid, ctChar, ctBool,
ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64, ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString ctFloat, ctFloat32, ctFloat64, ctFloat128,
ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
TCFileSections* = array[TCFileSection, PRope] # represents a generated C file TCFileSections* = array[TCFileSection, PRope] # represents a generated C file
TCProcSection* = enum # the sections a generated C proc consists of TCProcSection* = enum # the sections a generated C proc consists of
cpsLocals, # section of local variables for C proc cpsLocals, # section of local variables for C proc
@ -62,8 +64,9 @@ type
ThreadVarAccessed*: bool # true if the proc already accessed some threadvar ThreadVarAccessed*: bool # true if the proc already accessed some threadvar
nestedTryStmts*: seq[PNode] # in how many nested try statements we are nestedTryStmts*: seq[PNode] # in how many nested try statements we are
# (the vars must be volatile then) # (the vars must be volatile then)
popCurrExc*: Natural # how often to emit 'popCurrentException()' inExceptBlock*: int # are we currently inside an except block?
# before 'break'|'return' # leaving such scopes by raise or by return must
# execute any applicable finally blocks
labels*: Natural # for generating unique labels in the C proc labels*: Natural # for generating unique labels in the C proc
blocks*: seq[TBlock] # nested blocks blocks*: seq[TBlock] # nested blocks
breakIdx*: int # the block that will be exited breakIdx*: int # the block that will be exited

View file

@ -206,10 +206,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
of tkCharLit: of tkCharLit:
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}", dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
[toRope(esc(d.target, literal))]) [toRope(esc(d.target, literal))])
of tkIntLit..tkInt64Lit: of tkIntLit..tkUInt64Lit:
dispA(result, "<span class=\"DecNumber\">$1</span>", dispA(result, "<span class=\"DecNumber\">$1</span>",
"\\spanDecNumber{$1}", [toRope(esc(d.target, literal))]) "\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
of tkFloatLit..tkFloat64Lit: of tkFloatLit..tkFloat128Lit:
dispA(result, "<span class=\"FloatNumber\">$1</span>", dispA(result, "<span class=\"FloatNumber\">$1</span>",
"\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))]) "\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
of tkSymbol: of tkSymbol:

View file

@ -235,6 +235,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
case t.kind case t.kind
of tyBool, tyEnum, tyChar, tyInt..tyInt64: of tyBool, tyEnum, tyChar, tyInt..tyInt64:
result = newNodeIT(nkIntLit, info, t) result = newNodeIT(nkIntLit, info, t)
of tyUInt..tyUInt64:
result = newNodeIT(nkUIntLit, info, t)
of tyFloat..tyFloat128: of tyFloat..tyFloat128:
result = newNodeIt(nkFloatLit, info, t) result = newNodeIt(nkFloatLit, info, t)
of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr, of tyVar, tyPointer, tyPtr, tyRef, tyCString, tySequence, tyString, tyExpr,

View file

@ -597,7 +597,7 @@ proc CallCCompiler*(projectfile: string) =
proc genMappingFiles(list: TLinkedList): PRope = proc genMappingFiles(list: TLinkedList): PRope =
var it = PStrEntry(list.head) var it = PStrEntry(list.head)
while it != nil: while it != nil:
appf(result, "--file:r\"$1\"$n", [toRope(AddFileExt(it.data, cExt))]) appf(result, "--file:r\"$1\"$N", [toRope(AddFileExt(it.data, cExt))])
it = PStrEntry(it.next) it = PStrEntry(it.next)
proc writeMapping*(gSymbolMapping: PRope) = proc writeMapping*(gSymbolMapping: PRope) =

View file

@ -45,8 +45,10 @@ type
tkTemplate, tkTemplate,
tkTry, tkTuple, tkType, tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor, tkTry, tkTuple, tkType, tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,
tkYield, # end of keywords tkYield, # end of keywords
tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit, tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit,
tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkUIntLit, tkUInt8Lit, tkUInt16Lit, tkUInt32Lit, tkUInt64Lit,
tkFloatLit, tkFloat32Lit, tkFloat64Lit, tkFloat128Lit,
tkStrLit, tkRStrLit, tkTripleStrLit,
tkGStrLit, tkGTripleStrLit, tkCharLit, tkParLe, tkParRi, tkBracketLe, tkGStrLit, tkGTripleStrLit, tkCharLit, tkParLe, tkParRi, tkBracketLe,
tkBracketRi, tkCurlyLe, tkCurlyRi, tkBracketRi, tkCurlyLe, tkCurlyRi,
tkBracketDotLe, tkBracketDotRi, # [. and .] tkBracketDotLe, tkBracketDotRi, # [. and .]
@ -78,7 +80,9 @@ const
"try", "tuple", "type", "var", "when", "while", "with", "without", "xor", "try", "tuple", "type", "var", "when", "while", "with", "without", "xor",
"yield", "yield",
"tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit", "tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit",
"tkFloatLit", "tkFloat32Lit", "tkFloat64Lit", "tkStrLit", "tkRStrLit", "tkUIntLit", "tkUInt8Lit", "tkUInt16Lit", "tkUInt32Lit", "tkUInt64Lit",
"tkFloatLit", "tkFloat32Lit", "tkFloat64Lit", "tkFloat128Lit",
"tkStrLit", "tkRStrLit",
"tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(", "tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(",
")", "[", "]", "{", "}", "[.", ".]", "{.", ".}", "(.", ".)", ")", "[", "]", "{", "}", "[.", ".]", "{.", ".}", "(.", ".)",
",", ";", ",", ";",
@ -283,12 +287,17 @@ proc GetNumber(L: var TLexer): TToken =
case L.buf[endpos] case L.buf[endpos]
of 'f', 'F': of 'f', 'F':
inc(endpos) inc(endpos)
if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'): if (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
result.tokType = tkFloat64Lit
inc(endpos, 2)
elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
result.tokType = tkFloat32Lit result.tokType = tkFloat32Lit
inc(endpos, 2) inc(endpos, 2)
elif (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
result.tokType = tkFloat64Lit
inc(endpos, 2)
elif (L.buf[endpos] == '1') and
(L.buf[endpos + 1] == '2') and
(L.buf[endpos + 2] == '8'):
result.tokType = tkFloat128Lit
inc(endpos, 3)
else: else:
lexMessage(L, errInvalidNumber, result.literal & "'f" & L.buf[endpos]) lexMessage(L, errInvalidNumber, result.literal & "'f" & L.buf[endpos])
of 'i', 'I': of 'i', 'I':
@ -307,6 +316,22 @@ proc GetNumber(L: var TLexer): TToken =
inc(endpos) inc(endpos)
else: else:
lexMessage(L, errInvalidNumber, result.literal & "'i" & L.buf[endpos]) lexMessage(L, errInvalidNumber, result.literal & "'i" & L.buf[endpos])
of 'u', 'U':
inc(endpos)
if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
result.tokType = tkUInt64Lit
inc(endpos, 2)
elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
result.tokType = tkUInt32Lit
inc(endpos, 2)
elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
result.tokType = tkUInt16Lit
inc(endpos, 2)
elif (L.buf[endpos] == '8'):
result.tokType = tkUInt8Lit
inc(endpos)
else:
result.tokType = tkUIntLit
else: lexMessage(L, errInvalidNumber, result.literal & "'" & L.buf[endpos]) else: lexMessage(L, errInvalidNumber, result.literal & "'" & L.buf[endpos])
else: else:
L.bufpos = pos # restore position L.bufpos = pos # restore position
@ -378,6 +403,10 @@ proc GetNumber(L: var TLexer): TToken =
of tkInt8Lit: result.iNumber = biggestInt(int8(toU8(int(xi)))) of tkInt8Lit: result.iNumber = biggestInt(int8(toU8(int(xi))))
of tkInt16Lit: result.iNumber = biggestInt(toU16(int(xi))) of tkInt16Lit: result.iNumber = biggestInt(toU16(int(xi)))
of tkInt32Lit: result.iNumber = biggestInt(toU32(xi)) of tkInt32Lit: result.iNumber = biggestInt(toU32(xi))
of tkUIntLit, tkUInt64Lit: result.iNumber = xi
of tkUInt8Lit: result.iNumber = biggestInt(int8(toU8(int(xi))))
of tkUInt16Lit: result.iNumber = biggestInt(toU16(int(xi)))
of tkUInt32Lit: result.iNumber = biggestInt(toU32(xi))
of tkFloat32Lit: of tkFloat32Lit:
result.fNumber = (cast[PFloat32](addr(xi)))[] result.fNumber = (cast[PFloat32](addr(xi)))[]
# note: this code is endian neutral! # note: this code is endian neutral!

View file

@ -53,9 +53,15 @@ proc getSysType(kind: TTypeKind): PType =
of tyInt16: result = sysTypeFromName("int16") of tyInt16: result = sysTypeFromName("int16")
of tyInt32: result = sysTypeFromName("int32") of tyInt32: result = sysTypeFromName("int32")
of tyInt64: result = sysTypeFromName("int64") of tyInt64: result = sysTypeFromName("int64")
of tyUInt: result = sysTypeFromName("uint")
of tyUInt8: result = sysTypeFromName("uint8")
of tyUInt16: result = sysTypeFromName("uint16")
of tyUInt32: result = sysTypeFromName("uint32")
of tyUInt64: result = sysTypeFromName("uint64")
of tyFloat: result = sysTypeFromName("float") of tyFloat: result = sysTypeFromName("float")
of tyFloat32: result = sysTypeFromName("float32") of tyFloat32: result = sysTypeFromName("float32")
of tyFloat64: result = sysTypeFromName("float64") of tyFloat64: result = sysTypeFromName("float64")
of tyFloat128: result = sysTypeFromName("float128")
of tyBool: result = sysTypeFromName("bool") of tyBool: result = sysTypeFromName("bool")
of tyChar: result = sysTypeFromName("char") of tyChar: result = sysTypeFromName("char")
of tyString: result = sysTypeFromName("string") of tyString: result = sysTypeFromName("string")

View file

@ -416,6 +416,26 @@ proc identOrLiteral(p: var TParser): PNode =
result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p) result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p)
setBaseFlags(result, p.tok.base) setBaseFlags(result, p.tok.base)
getTok(p) getTok(p)
of tkUIntLit:
result = newIntNodeP(nkUIntLit, p.tok.iNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p)
of tkUInt8Lit:
result = newIntNodeP(nkUInt8Lit, p.tok.iNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p)
of tkUInt16Lit:
result = newIntNodeP(nkUInt16Lit, p.tok.iNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p)
of tkUInt32Lit:
result = newIntNodeP(nkUInt32Lit, p.tok.iNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p)
of tkUInt64Lit:
result = newIntNodeP(nkUInt64Lit, p.tok.iNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p)
of tkFloatLit: of tkFloatLit:
result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p) result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p)
setBaseFlags(result, p.tok.base) setBaseFlags(result, p.tok.base)
@ -428,6 +448,10 @@ proc identOrLiteral(p: var TParser): PNode =
result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p) result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p)
setBaseFlags(result, p.tok.base) setBaseFlags(result, p.tok.base)
getTok(p) getTok(p)
of tkFloat128Lit:
result = newFloatNodeP(nkFloat128Lit, p.tok.fNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p)
of tkStrLit: of tkStrLit:
result = newStrNodeP(nkStrLit, p.tok.literal, p) result = newStrNodeP(nkStrLit, p.tok.literal, p)
getTok(p) getTok(p)

View file

@ -23,7 +23,7 @@ const
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wNoStackFrame, wError, wDiscardable, wNoInit} wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor}
converterPragmas* = procPragmas converterPragmas* = procPragmas
methodPragmas* = procPragmas methodPragmas* = procPragmas
templatePragmas* = {wImmediate, wDeprecated, wError} templatePragmas* = {wImmediate, wDeprecated, wError}
@ -508,6 +508,11 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
incl(sym.loc.Flags, lfNoDecl) incl(sym.loc.Flags, lfNoDecl)
# implies nodecl, because otherwise header would not make sense # implies nodecl, because otherwise header would not make sense
if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s) if sym.loc.r == nil: sym.loc.r = toRope(sym.name.s)
of wDestructor:
if sym.typ.sons.len == 2:
sym.flags.incl sfDestructor
else:
invalidPragma(it)
of wNosideeffect: of wNosideeffect:
noVal(it) noVal(it)
incl(sym.flags, sfNoSideEffect) incl(sym.flags, sfNoSideEffect)

View file

@ -705,9 +705,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkInt16Lit: put(g, tkInt16Lit, atom(n)) of nkInt16Lit: put(g, tkInt16Lit, atom(n))
of nkInt32Lit: put(g, tkInt32Lit, atom(n)) of nkInt32Lit: put(g, tkInt32Lit, atom(n))
of nkInt64Lit: put(g, tkInt64Lit, atom(n)) of nkInt64Lit: put(g, tkInt64Lit, atom(n))
of nkUIntLit: put(g, tkUIntLit, atom(n))
of nkUInt8Lit: put(g, tkUInt8Lit, atom(n))
of nkUInt16Lit: put(g, tkUInt16Lit, atom(n))
of nkUInt32Lit: put(g, tkUInt32Lit, atom(n))
of nkUInt64Lit: put(g, tkUInt64Lit, atom(n))
of nkFloatLit: put(g, tkFloatLit, atom(n)) of nkFloatLit: put(g, tkFloatLit, atom(n))
of nkFloat32Lit: put(g, tkFloat32Lit, atom(n)) of nkFloat32Lit: put(g, tkFloat32Lit, atom(n))
of nkFloat64Lit: put(g, tkFloat64Lit, atom(n)) of nkFloat64Lit: put(g, tkFloat64Lit, atom(n))
of nkFloat128Lit: put(g, tkFloat128Lit, atom(n))
of nkStrLit: put(g, tkStrLit, atom(n)) of nkStrLit: put(g, tkStrLit, atom(n))
of nkRStrLit: put(g, tkRStrLit, atom(n)) of nkRStrLit: put(g, tkRStrLit, atom(n))
of nkCharLit: put(g, tkCharLit, atom(n)) of nkCharLit: put(g, tkCharLit, atom(n))

View file

@ -213,6 +213,10 @@ proc markUsed*(n: PNode, s: PSym) =
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s) if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s) if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s)
proc useSym*(sym: PSym): PNode =
result = newSymNode(sym)
markUsed(result, sym)
proc illFormedAst*(n: PNode) = proc illFormedAst*(n: PNode) =
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments})) GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))

View file

@ -132,10 +132,10 @@ proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
proc checkConvertible(info: TLineInfo, castDest, src: PType) = proc checkConvertible(info: TLineInfo, castDest, src: PType) =
const const
IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyFloat128} IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64}
if sameType(castDest, src) and castDest.sym == src.sym: if sameType(castDest, src) and castDest.sym == src.sym:
# don't annoy conversions that may be needed on another processor: # don't annoy conversions that may be needed on another processor:
if not (castDest.kind in {tyInt..tyFloat128, tyNil}): if not (castDest.kind in {tyInt..tyUInt64, tyNil}):
Message(info, hintConvFromXtoItselfNotNeeded, typeToString(castDest)) Message(info, hintConvFromXtoItselfNotNeeded, typeToString(castDest))
return return
var d = skipTypes(castDest, abstractVar) var d = skipTypes(castDest, abstractVar)
@ -1283,6 +1283,20 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
GlobalError(n.info, errInvalidExpressionX, GlobalError(n.info, errInvalidExpressionX,
renderTree(a, {renderNoComments})) renderTree(a, {renderNoComments}))
proc uniIntType(kind: TTypeKind): PType =
result = getSysType(kind).copyType(getCurrOwner(), true)
result.flags.incl(tfUniIntLit)
template memoize(e: expr): expr =
var `*guard` {.global.} = false
var `*memo` {.global.} : type(e)
if not `*guard`:
`*memo` = e
`*guard` = true
`*memo`
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
result = n result = n
if gCmd == cmdIdeTools: suggestExpr(c, n) if gCmd == cmdIdeTools: suggestExpr(c, n)
@ -1303,7 +1317,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ == nil: if result.typ == nil:
let i = result.intVal let i = result.intVal
if i >= low(int32) and i <= high(int32): if i >= low(int32) and i <= high(int32):
if i >= 0:
result.typ = uniIntType(tyInt).memoize
else:
result.typ = getSysType(tyInt) result.typ = getSysType(tyInt)
else:
if i >= 0:
result.typ = uniIntType(tyInt64).memoize
else: else:
result.typ = getSysType(tyInt64) result.typ = getSysType(tyInt64)
of nkInt8Lit: of nkInt8Lit:
@ -1314,12 +1334,24 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ == nil: result.typ = getSysType(tyInt32) if result.typ == nil: result.typ = getSysType(tyInt32)
of nkInt64Lit: of nkInt64Lit:
if result.typ == nil: result.typ = getSysType(tyInt64) if result.typ == nil: result.typ = getSysType(tyInt64)
of nkUIntLit:
if result.typ == nil: result.typ = getSysType(tyUInt)
of nkUInt8Lit:
if result.typ == nil: result.typ = getSysType(tyUInt8)
of nkUInt16Lit:
if result.typ == nil: result.typ = getSysType(tyUInt16)
of nkUInt32Lit:
if result.typ == nil: result.typ = getSysType(tyUInt32)
of nkUInt64Lit:
if result.typ == nil: result.typ = getSysType(tyUInt64)
of nkFloatLit: of nkFloatLit:
if result.typ == nil: result.typ = getSysType(tyFloat) if result.typ == nil: result.typ = getSysType(tyFloat)
of nkFloat32Lit: of nkFloat32Lit:
if result.typ == nil: result.typ = getSysType(tyFloat32) if result.typ == nil: result.typ = getSysType(tyFloat32)
of nkFloat64Lit: of nkFloat64Lit:
if result.typ == nil: result.typ = getSysType(tyFloat64) if result.typ == nil: result.typ = getSysType(tyFloat64)
of nkFloat128Lit:
if result.typ == nil: result.typ = getSysType(tyFloat128)
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if result.typ == nil: result.typ = getSysType(tyString) if result.typ == nil: result.typ = getSysType(tyString)
of nkCharLit: of nkCharLit:

View file

@ -258,15 +258,15 @@ proc partialOrExpr(c: PSym, n: PNode): PNode =
proc leValueConv(a, b: PNode): bool = proc leValueConv(a, b: PNode): bool =
result = false result = false
case a.kind case a.kind
of nkCharLit..nkInt64Lit: of nkCharLit..nkUInt64Lit:
case b.kind case b.kind
of nkCharLit..nkInt64Lit: result = a.intVal <= b.intVal of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat64Lit: result = a.intVal <= round(b.floatVal) of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
else: InternalError(a.info, "leValueConv") else: InternalError(a.info, "leValueConv")
of nkFloatLit..nkFloat64Lit: of nkFloatLit..nkFloat128Lit:
case b.kind case b.kind
of nkFloatLit..nkFloat64Lit: result = a.floatVal <= b.floatVal of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
of nkCharLit..nkInt64Lit: result = a.floatVal <= toFloat(int(b.intVal)) of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
else: InternalError(a.info, "leValueConv") else: InternalError(a.info, "leValueConv")
else: InternalError(a.info, "leValueConv") else: InternalError(a.info, "leValueConv")

View file

@ -682,6 +682,8 @@ proc semLambda(c: PContext, n: PNode): PNode =
popOwner() popOwner()
result.typ = s.typ result.typ = s.typ
proc instantiateDestructor*(c: PContext, typ: PType): bool
proc semProcAux(c: PContext, n: PNode, kind: TSymKind, proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
validPragmas: TSpecialWords): PNode = validPragmas: TSpecialWords): PNode =
result = n result = n
@ -743,6 +745,19 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
popOwner() popOwner()
pushOwner(s) pushOwner(s)
s.options = gOptions s.options = gOptions
if sfDestructor in s.flags:
let t = s.typ.sons[1].skipTypes({tyVar})
t.destructor = s
# automatically insert calls to base classes' destructors
if n.sons[bodyPos].kind != nkEmpty:
for i in countup(0, t.sonsLen - 1):
# when inheriting directly from object
# there will be a single nil son
if t.sons[i] == nil: continue
if instantiateDestructor(c, t.sons[i]):
n.sons[bodyPos].addSon(newNode(nkCall, t.sym.info, @[
useSym(t.sons[i].destructor),
n.sons[paramsPos][1][0]]))
if n.sons[bodyPos].kind != nkEmpty: if n.sons[bodyPos].kind != nkEmpty:
# for DLL generation it is annoying to check for sfImportc! # for DLL generation it is annoying to check for sfImportc!
if sfBorrow in s.flags: if sfBorrow in s.flags:
@ -772,10 +787,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
incl(s.flags, sfForward) incl(s.flags, sfForward)
elif sfBorrow in s.flags: semBorrow(c, n, s) elif sfBorrow in s.flags: semBorrow(c, n, s)
sideEffectsCheck(c, s) sideEffectsCheck(c, s)
if result.sons[namePos].sym.name.id == ord(wDestroy):
if s.typ.sons.len == 2:
let typ = s.typ.sons[1].skipTypes({tyVar})
typ.destructor = s
if s.typ.callConv == ccClosure and s.owner.kind == skModule: if s.typ.callConv == ccClosure and s.owner.kind == skModule:
localError(s.info, errXCannotBeClosure, s.name.s) localError(s.info, errXCannotBeClosure, s.name.s)
closeScope(c.tab) # close scope for parameters closeScope(c.tab) # close scope for parameters
@ -864,6 +875,134 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
if result.isNil: if result.isNil:
LocalError(n.info, errCannotInterpretNodeX, renderTree(n)) LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
# special marker values that indicates that we are
# 1) AnalyzingDestructor: currenlty analyzing the type for destructor
# generation (needed for recursive types)
# 2) DestructorIsTrivial: completed the anlysis before and determined
# that the type has a trivial destructor
var AnalyzingDestructor, DestructorIsTrivial: PSym
new(AnalyzingDestructor)
new(DestructorIsTrivial)
var
destructorName = getIdent"destroy_"
destructorParam = getIdent"this_"
destructorPragma = newIdentNode(getIdent"destructor", UnknownLineInfo())
rangeDestructorProc: PSym
proc destroyField(c: PContext, field: PSym, holder: PNode): PNode =
if instantiateDestructor(c, field.typ):
result = newNode(nkCall, field.info, @[
useSym(field.typ.destructor),
newNode(nkDotExpr, field.info, @[holder, useSym(field)])])
proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
var nonTrivialFields = 0
result = newNode(nkCaseStmt, n.info, @[])
# case x.kind
result.addSon(newNode(nkDotExpr, n.info, @[holder, n.sons[0]]))
for i in countup(1, n.len - 1):
# of A, B:
var caseBranch = newNode(n[i].kind, n[i].info, n[i].sons[0 .. -2])
let recList = n[i].lastSon
var destroyRecList = newNode(nkStmtList, n[i].info, @[])
template addField(f: expr): stmt =
let stmt = destroyField(c, f, holder)
if stmt != nil:
destroyRecList.addSon(stmt)
inc nonTrivialFields
case recList.kind
of nkSym:
addField(recList.sym)
of nkRecList:
for j in countup(0, recList.len - 1):
addField(recList[j].sym)
else:
internalAssert false
caseBranch.addSon(destroyRecList)
result.addSon(caseBranch)
# maybe no fields were destroyed?
if nonTrivialFields == 0:
result = nil
proc generateDestructor(c: PContext, t: PType): PNode =
## generate a destructor for a user-defined object ot tuple type
## returns nil if the destructor turns out to be trivial
template addLine(e: expr): stmt =
if result == nil: result = newNode(nkStmtList)
result.addSon(e)
# XXX: This may be true for some C-imported types such as
# Tposix_spawnattr
if t.n == nil or t.n.sons == nil: return
internalAssert t.n.kind == nkRecList
let destructedObj = newIdentNode(destructorParam, UnknownLineInfo())
# call the destructods of all fields
for s in countup(0, t.n.sons.len - 1):
case t.n.sons[s].kind
of nkRecCase:
let stmt = destroyCase(c, t.n.sons[s], destructedObj)
if stmt != nil: addLine(stmt)
of nkSym:
let stmt = destroyField(c, t.n.sons[s].sym, destructedObj)
if stmt != nil: addLine(stmt)
else:
internalAssert false
# base classes' destructors will be automatically called by
# semProcAux for both auto-generated and user-defined destructors
proc instantiateDestructor*(c: PContext, typ: PType): bool =
# returns true if the type already had a user-defined
# destructor or if the compiler generated a default
# member-wise one
var t = skipTypes(typ, {tyConst, tyMutable})
if t.destructor != nil:
# XXX: This is not entirely correct for recursive types, but we need
# it temporarily to hide the "destroy is alrady defined" problem
return t.destructor notin [AnalyzingDestructor, DestructorIsTrivial]
case t.kind
of tySequence, tyArray, tyArrayConstr, tyOpenArray:
if instantiateDestructor(c, t.sons[0]):
if rangeDestructorProc == nil:
rangeDestructorProc = SymtabGet(c.tab, getIdent"nimDestroyRange")
t.destructor = rangeDestructorProc
return true
else:
return false
of tyTuple, tyObject:
t.destructor = AnalyzingDestructor
let generated = generateDestructor(c, t)
if generated != nil:
internalAssert t.sym != nil
var i = t.sym.info
let fullDef = newNode(nkProcDef, i, @[
newIdentNode(destructorName, i),
emptyNode,
newNode(nkFormalParams, i, @[
emptyNode,
newNode(nkIdentDefs, i, @[
newIdentNode(destructorParam, i),
useSym(t.sym),
emptyNode]),
]),
newNode(nkPragma, i, @[destructorPragma]),
generated
])
discard semProc(c, fullDef)
internalAssert t.destructor != nil
return true
else:
t.destructor = DestructorIsTrivial
return false
else:
return false
proc insertDestructors(c: PContext, varSection: PNode): proc insertDestructors(c: PContext, varSection: PNode):
tuple[outer: PNode, inner: PNode] = tuple[outer: PNode, inner: PNode] =
# Accepts a var or let section. # Accepts a var or let section.
@ -889,7 +1028,7 @@ proc insertDestructors(c: PContext, varSection: PNode):
varTyp = varId.sym.typ varTyp = varId.sym.typ
info = varId.info info = varId.info
if varTyp != nil and instantiateDestructor(varTyp): if varTyp != nil and instantiateDestructor(c, varTyp):
var tryStmt = newNodeI(nkTryStmt, info) var tryStmt = newNodeI(nkTryStmt, info)
if j < totalVars - 1: if j < totalVars - 1:
@ -910,8 +1049,8 @@ proc insertDestructors(c: PContext, varSection: PNode):
tryStmt.addSon( tryStmt.addSon(
newNode(nkFinally, info, @[ newNode(nkFinally, info, @[
semStmt(c, newNode(nkCall, info, @[ semStmt(c, newNode(nkCall, info, @[
semSym(c, varId, varTyp.destructor, {}), useSym(varTyp.destructor),
semSym(c, varId, varId.sym, {})]))])) useSym(varId.sym)]))]))
result.outer = newNodeI(nkStmtList, info) result.outer = newNodeI(nkStmtList, info)
varSection.sons.setLen(j+1) varSection.sons.setLen(j+1)

View file

@ -306,7 +306,9 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
covered: var biggestInt) = covered: var biggestInt) =
for i in countup(0, sonsLen(branch) - 2): for i in countup(0, sonsLen(branch) - 2):
var b = branch.sons[i] var b = branch.sons[i]
if isRange(b): if b.kind == nkRange:
branch.sons[i] = b
elif isRange(b):
branch.sons[i] = semCaseBranchRange(c, t, b, covered) branch.sons[i] = semCaseBranchRange(c, t, b, covered)
else: else:
var r = semConstExpr(c, b) var r = semConstExpr(c, b)
@ -825,9 +827,15 @@ proc processMagicType(c: PContext, m: PSym) =
of mInt16: setMagicType(m, tyInt16, 2) of mInt16: setMagicType(m, tyInt16, 2)
of mInt32: setMagicType(m, tyInt32, 4) of mInt32: setMagicType(m, tyInt32, 4)
of mInt64: setMagicType(m, tyInt64, 8) of mInt64: setMagicType(m, tyInt64, 8)
of mUInt: setMagicType(m, tyUInt, intSize)
of mUInt8: setMagicType(m, tyUInt8, 1)
of mUInt16: setMagicType(m, tyUInt16, 2)
of mUInt32: setMagicType(m, tyUInt32, 4)
of mUInt64: setMagicType(m, tyUInt64, 8)
of mFloat: setMagicType(m, tyFloat, floatSize) of mFloat: setMagicType(m, tyFloat, floatSize)
of mFloat32: setMagicType(m, tyFloat32, 4) of mFloat32: setMagicType(m, tyFloat32, 4)
of mFloat64: setMagicType(m, tyFloat64, 8) of mFloat64: setMagicType(m, tyFloat64, 8)
of mFloat128: setMagicType(m, tyFloat128, 16)
of mBool: setMagicType(m, tyBool, 1) of mBool: setMagicType(m, tyBool, 1)
of mChar: setMagicType(m, tyChar, 1) of mChar: setMagicType(m, tyChar, 1)
of mString: of mString:

View file

@ -163,6 +163,9 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
var k = skipTypes(a, {tyRange}).kind var k = skipTypes(a, {tyRange}).kind
if k == f.kind: result = isSubtype if k == f.kind: result = isSubtype
elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv
elif f.kind == tyUInt and k in {tyUInt..tyUInt32}: result = isIntConv
elif f.kind in {tyUInt..tyUInt64} and k == tyInt and tfUniIntLit in a.flags:
result = isIntConv
elif k >= min and k <= max: result = isConvertible elif k >= min and k <= max: result = isConvertible
else: result = isNone else: result = isNone
@ -306,6 +309,11 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
of tyInt16: result = handleRange(f, a, tyInt8, tyInt16) of tyInt16: result = handleRange(f, a, tyInt8, tyInt16)
of tyInt32: result = handleRange(f, a, tyInt, tyInt32) of tyInt32: result = handleRange(f, a, tyInt, tyInt32)
of tyInt64: result = handleRange(f, a, tyInt, tyInt64) of tyInt64: result = handleRange(f, a, tyInt, tyInt64)
of tyUInt: result = handleRange(f, a, tyUInt8, tyUInt32)
of tyUInt8: result = handleRange(f, a, tyUInt8, tyUInt8)
of tyUInt16: result = handleRange(f, a, tyUInt8, tyUInt16)
of tyUInt32: result = handleRange(f, a, tyUInt, tyUInt32)
of tyUInt64: result = handleRange(f, a, tyUInt, tyUInt64)
of tyFloat: result = handleFloatRange(f, a) of tyFloat: result = handleFloatRange(f, a)
of tyFloat32: result = handleFloatRange(f, a) of tyFloat32: result = handleFloatRange(f, a)
of tyFloat64: result = handleFloatRange(f, a) of tyFloat64: result = handleFloatRange(f, a)

View file

@ -141,7 +141,7 @@ proc skipTypes(t: PType, kinds: TTypeKinds): PType =
proc isOrdinalType(t: PType): bool = proc isOrdinalType(t: PType): bool =
assert(t != nil) assert(t != nil)
result = (t.Kind in {tyChar, tyInt..tyInt64, tyBool, tyEnum}) or result = (t.Kind in {tyChar, tyInt..tyInt64, tyUInt..tyUInt64, tyBool, tyEnum}) or
(t.Kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and (t.Kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and
isOrdinalType(t.sons[0]) isOrdinalType(t.sons[0])
@ -386,10 +386,11 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
"GenericInvokation", "GenericBody", "GenericInst", "GenericParam", "GenericInvokation", "GenericBody", "GenericInst", "GenericParam",
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple", "distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc", "set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
"pointer", "OpenArray[$1]", "string", "CString", "Forward", "int", "int8", "pointer", "OpenArray[$1]", "string", "CString", "Forward",
"int16", "int32", "int64", "float", "float32", "float64", "float128", "int", "int8", "int16", "int32", "int64",
"float", "float32", "float64", "float128",
"uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ", "uint", "uint8", "uint16", "uint32", "uint64",
"bignum", "const ",
"!", "varargs[$1]", "iter[$1]", "proxy[$1]", "TypeClass" ] "!", "varargs[$1]", "iter[$1]", "proxy[$1]", "TypeClass" ]
var t = typ var t = typ
result = "" result = ""
@ -494,6 +495,7 @@ proc firstOrd(t: PType): biggestInt =
of tyInt16: result = - 32768 of tyInt16: result = - 32768
of tyInt32: result = - 2147483646 - 2 of tyInt32: result = - 2147483646 - 2
of tyInt64: result = 0x8000000000000000'i64 of tyInt64: result = 0x8000000000000000'i64
of tyUInt..tyUInt64: result = 0
of tyEnum: of tyEnum:
# if basetype <> nil then return firstOrd of basetype # if basetype <> nil then return firstOrd of basetype
if (sonsLen(t) > 0) and (t.sons[0] != nil): if (sonsLen(t) > 0) and (t.sons[0] != nil):
@ -524,6 +526,13 @@ proc lastOrd(t: PType): biggestInt =
of tyInt16: result = 0x00007FFF of tyInt16: result = 0x00007FFF
of tyInt32: result = 0x7FFFFFFF of tyInt32: result = 0x7FFFFFFF
of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64 of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64
of tyUInt:
if platform.intSize == 4: result = 0xFFFFFFFF
else: result = 0x7FFFFFFFFFFFFFFF'i64
of tyUInt8: result = 0x7F # XXX: Fix these
of tyUInt16: result = 0x7FFF
of tyUInt32: result = 0x7FFFFFFF
of tyUInt64: result = 0x7FFFFFFFFFFFFFFF'i64
of tyEnum: of tyEnum:
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
result = t.n.sons[sonsLen(t.n) - 1].sym.position result = t.n.sons[sonsLen(t.n) - 1].sym.position
@ -980,6 +989,9 @@ proc computeSizeAux(typ: PType, a: var biggestInt): biggestInt =
of tyInt64, tyUInt64, tyFloat64: of tyInt64, tyUInt64, tyFloat64:
result = 8 result = 8
a = result a = result
of tyFloat128:
result = 16
a = result
of tyFloat: of tyFloat:
result = floatSize result = floatSize
a = result a = result
@ -1062,10 +1074,3 @@ proc getSize(typ: PType): biggestInt =
result = computeSize(typ) result = computeSize(typ)
if result < 0: InternalError("getSize(" & $typ.kind & ')') if result < 0: InternalError("getSize(" & $typ.kind & ')')
proc instantiateDestructor*(typ: PType): bool =
# return true if the type already had a user-defined
# destructor or if the compiler generated a default
# member-wise one
if typ.destructor != nil: return true
return false

View file

@ -39,7 +39,7 @@ type
wDestroy, wDestroy,
wImmediate, wImportCpp, wImportObjC, wImmediate, wDestructor, wImportCpp, wImportObjC,
wImportCompilerProc, wImportCompilerProc,
wImportc, wExportc, wIncompleteStruct, wImportc, wExportc, wIncompleteStruct,
wAlign, wNodecl, wPure, wSideeffect, wHeader, wAlign, wNodecl, wPure, wSideeffect, wHeader,
@ -117,7 +117,7 @@ const
"destroy", "destroy",
"immediate", "importcpp", "importobjc", "immediate", "destructor", "importcpp", "importobjc",
"importcompilerproc", "importc", "exportc", "incompletestruct", "importcompilerproc", "importc", "exportc", "incompletestruct",
"align", "nodecl", "pure", "sideeffect", "align", "nodecl", "pure", "sideeffect",
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib", "header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",

View file

@ -62,6 +62,7 @@ hint[LineTooLong]=off
@if not bsd: @if not bsd:
# -fopenmp # -fopenmp
gcc.options.linker = "-ldl" gcc.options.linker = "-ldl"
gpp.options.linker = "-ldl"
clang.options.linker = "-ldl" clang.options.linker = "-ldl"
tcc.options.linker = "-ldl" tcc.options.linker = "-ldl"
@else: @else:
@ -83,24 +84,23 @@ icc.options.linker = "-cxxlib"
tlsEmulation:on tlsEmulation:on
@end @end
@end @end
gcc.options.debug = "-g3 -O0"
@if macosx: @if macosx:
tlsEmulation:on tlsEmulation:on
@if not release:
gcc.options.always = "-w -fasm-blocks -O1"
@else:
gcc.options.always = "-w -fasm-blocks" gcc.options.always = "-w -fasm-blocks"
@end gpp.options.always = "-w -fasm-blocks"
@else:
@if not release:
gcc.options.always = "-w"
@else: @else:
gcc.options.always = "-w" gcc.options.always = "-w"
gpp.options.always = "-w"
@end @end
@end
gcc.options.speed = "-O3 -fno-strict-aliasing" gcc.options.speed = "-O3 -fno-strict-aliasing"
gcc.options.size = "-Os" gcc.options.size = "-Os"
gcc.options.debug = "-g3 -O0"
gpp.options.speed = "-O3 -fno-strict-aliasing"
gpp.options.size = "-Os"
gpp.options.debug = "-g3 -O0"
#passl = "-pg" #passl = "-pg"
# Configuration for the LLVM GCC compiler: # Configuration for the LLVM GCC compiler:

File diff suppressed because it is too large Load diff

View file

@ -17,8 +17,9 @@ type
TNimrodNodeKind* = enum TNimrodNodeKind* = enum
nnkNone, nnkEmpty, nnkIdent, nnkSym, nnkNone, nnkEmpty, nnkIdent, nnkSym,
nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit, nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkFloatLit, nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
nnkFloat32Lit, nnkFloat64Lit, nnkStrLit, nnkRStrLit, nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall, nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall,
nnkCommand, nnkCall, nnkCallStrLit, nnkExprEqExpr, nnkCommand, nnkCall, nnkCallStrLit, nnkExprEqExpr,
nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkInfix, nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkInfix,

View file

@ -43,7 +43,12 @@ type
akFloat = 36, ## any represents a float akFloat = 36, ## any represents a float
akFloat32 = 37, ## any represents a float32 akFloat32 = 37, ## any represents a float32
akFloat64 = 38, ## any represents a float64 akFloat64 = 38, ## any represents a float64
akFloat128 = 39 ## any represents a float128 akFloat128 = 39, ## any represents a float128
akUInt = 40, ## any represents an unsigned int
akUInt8 = 41, ## any represents an unsigned int8
akUInt16 = 42, ## any represents an unsigned in16
akUInt32 = 43, ## any represents an unsigned int32
akUInt64 = 44, ## any represents an unsigned int64
TAny* = object {.pure.} ## can represent any nimrod value; NOTE: the wrapped TAny* = object {.pure.} ## can represent any nimrod value; NOTE: the wrapped
## value can be modified with its wrapper! This means ## value can be modified with its wrapper! This means

View file

@ -10,6 +10,8 @@
## This module provides an easy to use sockets-style ## This module provides an easy to use sockets-style
## nimrod interface to the OpenSSL library. ## nimrod interface to the OpenSSL library.
{.deprecate.}
import openssl, strutils, os import openssl, strutils, os
type type

View file

@ -192,7 +192,7 @@ __clang__
** long int lrint (double x); ** long int lrint (double x);
*/ */
#if defined(__LCC__) || (defined(__GNUC__) && defined(WIN32)) #if defined(__LCC__) || (defined(__GNUC__))
/* Linux' GCC does not seem to have these. Why? */ /* Linux' GCC does not seem to have these. Why? */
# define HAVE_LRINT # define HAVE_LRINT
# define HAVE_LRINTF # define HAVE_LRINTF
@ -281,6 +281,13 @@ static unsigned long nimInf[2]={0xffffffff, 0x7fffffff};
# endif # endif
# define NIM_BOOL bool # define NIM_BOOL bool
# define NIM_NIL 0 # define NIM_NIL 0
struct NimException
{
NimException(struct E_Base* exp, const char* msg): exp(exp), msg(msg) {}
struct E_Base* exp;
const char* msg;
};
#else #else
# ifdef bool # ifdef bool
# define NIM_BOOL bool # define NIM_BOOL bool

View file

@ -42,6 +42,14 @@
## body.add("--xyz--") ## body.add("--xyz--")
## ##
## echo(postContent("http://validator.w3.org/check", headers, body)) ## echo(postContent("http://validator.w3.org/check", headers, body))
##
## SSL/TLS support
## ===============
## This requires the OpenSSL library, fortunately it's widely used and installed
## on many operating systems. httpclient will use SSL automatically if you give
## any of the functions a url with the ``https`` schema, for example:
## ``https://github.com/``, you also have to compile with ``ssl`` defined like so:
## ``nimrod c -d:ssl ...``.
import sockets, strutils, parseurl, parseutils, strtabs import sockets, strutils, parseurl, parseutils, strtabs
@ -79,10 +87,11 @@ proc charAt(d: var string, i: var int, s: TSocket): char {.inline.} =
i = 0 i = 0
result = d[i] result = d[i]
proc parseChunks(d: var string, start: int, s: TSocket): string = proc parseChunks(s: TSocket): string =
# get chunks: # get chunks:
var i = start var i = 0
result = "" result = ""
var d = s.recv().string
while true: while true:
var chunkSize = 0 var chunkSize = 0
var digitFound = false var digitFound = false
@ -128,88 +137,87 @@ proc parseChunks(d: var string, start: int, s: TSocket): string =
# skip trailing CR-LF: # skip trailing CR-LF:
while charAt(d, i, s) in {'\C', '\L'}: inc(i) while charAt(d, i, s) in {'\C', '\L'}: inc(i)
proc parseBody(d: var string, start: int, s: TSocket, proc parseBody(s: TSocket,
headers: PStringTable): string = headers: PStringTable): string =
result = ""
if headers["Transfer-Encoding"] == "chunked": if headers["Transfer-Encoding"] == "chunked":
result = parseChunks(d, start, s) result = parseChunks(s)
else: else:
result = substr(d, start)
# -REGION- Content-Length # -REGION- Content-Length
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3 # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
var contentLengthHeader = headers["Content-Length"] var contentLengthHeader = headers["Content-Length"]
if contentLengthHeader != "": if contentLengthHeader != "":
var length = contentLengthHeader.parseint() var length = contentLengthHeader.parseint()
while result.len() < length: result.add(s.recv.string) result = newString(length)
var received = 0
while true:
if received >= length: break
let r = s.recv(addr(result[received]), length-received)
if r == 0: break
received += r
if received != length:
httpError("Got invalid content length. Expected: " & $length &
" got: " & $received)
else: else:
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO
# -REGION- Connection: Close # -REGION- Connection: Close
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5 # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5
if headers["Connection"] == "close": if headers["Connection"] == "close":
var buf = ""
while True: while True:
var moreData = recv(s).string buf = newString(4000)
if moreData.len == 0: break let r = s.recv(addr(buf[0]), 4000)
result.add(moreData) if r == 0: break
buf.setLen(r)
result.add(buf)
proc parseResponse(s: TSocket): TResponse = proc parseResponse(s: TSocket, getBody: bool): TResponse =
var d = s.recv.string var parsedStatus = false
var i = 0 var linei = 0
var fullyRead = false
# Parse the version var line = ""
# Parses the first line of the headers
# ``HTTP/1.1`` 200 OK
var L = skipIgnoreCase(d, "HTTP/1.1", i)
if L > 0:
result.version = "1.1"
inc(i, L)
else:
L = skipIgnoreCase(d, "HTTP/1.0", i)
if L > 0:
result.version = "1.0"
inc(i, L)
else:
httpError("invalid HTTP header")
L = skipWhiteSpace(d, i)
if L <= 0: httpError("invalid HTTP header")
inc(i, L)
result.status = ""
while d[i] notin {'\C', '\L', '\0'}:
result.status.add(d[i])
inc(i)
if d[i] == '\C': inc(i)
if d[i] == '\L': inc(i)
else: httpError("invalid HTTP header, CR-LF expected")
# Parse the headers
# Everything after the first line leading up to the body
# htype: hvalue
result.headers = newStringTable(modeCaseInsensitive) result.headers = newStringTable(modeCaseInsensitive)
while true: while True:
var key = "" line = ""
while d[i] != ':': linei = 0
if d[i] == '\0': httpError("invalid HTTP header, ':' expected") if s.recvLine(line):
key.add(d[i]) if line == "": break # We've been disconnected.
inc(i) if line == "\c\L":
inc(i) # skip ':' fullyRead = true
if d[i] == ' ': inc(i) # skip if the character is a space
var val = ""
while d[i] notin {'\C', '\L', '\0'}:
val.add(d[i])
inc(i)
result.headers[key] = val
if d[i] == '\C': inc(i)
if d[i] == '\L': inc(i)
else: httpError("invalid HTTP header, CR-LF expected")
if d[i] == '\C': inc(i)
if d[i] == '\L':
inc(i)
break break
if not parsedStatus:
# Parse HTTP version info and status code.
var le = skipIgnoreCase(line, "HTTP/", linei)
if le <= 0: httpError("invalid http version")
inc(linei, le)
le = skipIgnoreCase(line, "1.1", linei)
if le > 0: result.version = "1.1"
else:
le = skipIgnoreCase(line, "1.0", linei)
if le <= 0: httpError("unsupported http version")
result.version = "1.0"
inc(linei, le)
# Status code
linei.inc skipWhitespace(line, linei)
result.status = line[linei .. -1]
parsedStatus = true
else:
# Parse headers
var name = ""
var le = parseUntil(line, name, ':', linei)
if le <= 0: httpError("invalid headers")
inc(linei, le)
if line[linei] != ':': httpError("invalid headers")
inc(linei) # Skip :
linei += skipWhitespace(line, linei)
result.body = parseBody(d, i, s, result.headers) result.headers[name] = line[linei.. -1]
if not fullyRead: httpError("Connection was closed before full request has been made")
if getBody:
result.body = parseBody(s, result.headers)
else:
result.body = ""
type type
THttpMethod* = enum ## the requested HttpMethod THttpMethod* = enum ## the requested HttpMethod
@ -238,6 +246,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
var headers = substr($httpMethod, len("http")) var headers = substr($httpMethod, len("http"))
headers.add(" /" & r.path & r.query) headers.add(" /" & r.path & r.query)
headers.add(" HTTP/1.1\c\L") headers.add(" HTTP/1.1\c\L")
add(headers, "Host: " & r.hostname & "\c\L") add(headers, "Host: " & r.hostname & "\c\L")
@ -245,12 +254,21 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
add(headers, "\c\L") add(headers, "\c\L")
var s = socket() var s = socket()
s.connect(r.hostname, TPort(80)) var port = TPort(80)
if r.scheme == "https":
when defined(ssl):
s.wrapSocket(verifyMode = CVerifyNone)
else:
raise newException(EHttpRequestErr, "SSL support was not compiled in. Cannot connect over SSL.")
port = TPort(443)
if r.port != "":
port = TPort(r.port.parseInt)
s.connect(r.hostname, port)
s.send(headers) s.send(headers)
if body != "": if body != "":
s.send(body) s.send(body)
result = parseResponse(s) result = parseResponse(s, httpMethod != httpHEAD)
s.close() s.close()
proc redirection(status: string): bool = proc redirection(status: string): bool =

View file

@ -86,7 +86,7 @@ proc storeAny(s: PStream, a: TAny, stored: var TIntSet) =
var x = getString(a) var x = getString(a)
if IsNil(x): s.write("null") if IsNil(x): s.write("null")
else: s.write(escapeJson(x)) else: s.write(escapeJson(x))
of akInt..akInt64: s.write($getBiggestInt(a)) of akInt..akInt64, akUInt..akUInt64: s.write($getBiggestInt(a))
of akFloat..akFloat128: s.write($getBiggestFloat(a)) of akFloat..akFloat128: s.write($getBiggestFloat(a))
proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) = proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) =
@ -197,7 +197,7 @@ proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) =
setString(a, p.str) setString(a, p.str)
next(p) next(p)
else: raiseParseErr(p, "string expected") else: raiseParseErr(p, "string expected")
of akInt..akInt64: of akInt..akInt64, akUInt..akUInt64:
if p.kind == jsonInt: if p.kind == jsonInt:
setBiggestInt(a, getInt(p)) setBiggestInt(a, getInt(p))
next(p) next(p)

View file

@ -186,10 +186,12 @@ when not defined(ECMAScript):
proc trunc*(x: float): float {.importc: "trunc", nodecl.} proc trunc*(x: float): float {.importc: "trunc", nodecl.}
proc floor*(x: float): float {.importc: "floor", nodecl.} proc floor*(x: float): float {.importc: "floor", nodecl.}
proc ceil*(x: float): float {.importc: "ceil", nodecl.}
else: else:
proc mathrandom(): float {.importc: "Math.random", nodecl.} proc mathrandom(): float {.importc: "Math.random", nodecl.}
proc floor*(x: float): float {.importc: "Math.floor", nodecl.} proc floor*(x: float): float {.importc: "Math.floor", nodecl.}
proc ceil*(x: float): float {.importc: "Math.ceil", nodecl.}
proc random*(max: int): int = return int(floor(mathrandom() * float(max))) proc random*(max: int): int = return int(floor(mathrandom() * float(max)))
proc randomize*() = nil proc randomize*() = nil

View file

@ -1346,11 +1346,15 @@ when defined(linux) or defined(solaris) or defined(bsd) or defined(aix):
setlen(result, len) setlen(result, len)
when defined(macosx): when defined(macosx):
type
cuint32* {.importc: "unsigned int", nodecl.} = int
## This is the same as the type ``uint32_t`` in *C*.
# a really hacky solution: since we like to include 2 headers we have to # a really hacky solution: since we like to include 2 headers we have to
# define two procs which in reality are the same # define two procs which in reality are the same
proc getExecPath1(c: cstring, size: var int32) {. proc getExecPath1(c: cstring, size: var cuint32) {.
importc: "_NSGetExecutablePath", header: "<sys/param.h>".} importc: "_NSGetExecutablePath", header: "<sys/param.h>".}
proc getExecPath2(c: cstring, size: var int32): bool {. proc getExecPath2(c: cstring, size: var cuint32): bool {.
importc: "_NSGetExecutablePath", header: "<mach-o/dyld.h>".} importc: "_NSGetExecutablePath", header: "<mach-o/dyld.h>".}
proc getAppFilename*(): string {.rtl, extern: "nos$1".} = proc getAppFilename*(): string {.rtl, extern: "nos$1".} =
@ -1379,7 +1383,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1".} =
elif defined(bsd): elif defined(bsd):
result = getApplAux("/proc/" & $getpid() & "/file") result = getApplAux("/proc/" & $getpid() & "/file")
elif defined(macosx): elif defined(macosx):
var size: int32 var size: cuint32
getExecPath1(nil, size) getExecPath1(nil, size)
result = newString(int(size)) result = newString(int(size))
if getExecPath2(result, size): if getExecPath2(result, size):

View file

@ -123,7 +123,7 @@ when defined(macosx) or defined(bsd):
HW_AVAILCPU = 25 HW_AVAILCPU = 25
HW_NCPU = 3 HW_NCPU = 3
proc sysctl(x: ptr array[0..3, cint], y: cint, z: pointer, proc sysctl(x: ptr array[0..3, cint], y: cint, z: pointer,
a: var int, b: pointer, c: int): cint {. a: var csize, b: pointer, c: int): cint {.
importc: "sysctl", header: "<sys/sysctl.h>".} importc: "sysctl", header: "<sys/sysctl.h>".}
proc countProcessors*(): int {.rtl, extern: "nosp$1".} = proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
@ -135,7 +135,8 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
elif defined(macosx) or defined(bsd): elif defined(macosx) or defined(bsd):
var var
mib: array[0..3, cint] mib: array[0..3, cint]
len, numCPU: int numCPU: int
len: csize
mib[0] = CTL_HW mib[0] = CTL_HW
mib[1] = HW_AVAILCPU mib[1] = HW_AVAILCPU
len = sizeof(numCPU) len = sizeof(numCPU)

View file

@ -25,20 +25,17 @@
## smtp.sendmail("username@gmail.com", @["foo@gmail.com"], $msg) ## smtp.sendmail("username@gmail.com", @["foo@gmail.com"], $msg)
## ##
## ##
## For SSL support this module relies on the SSL module. If you want to ## For SSL support this module relies on OpenSSL. If you want to
## disable SSL, compile with ``-d:NoSSL``. ## enable SSL, compile with ``-d:ssl``.
when not defined(ssl):
{.error: "The SMTP module should be compiled with SSL support. Compile with -d:ssl."}
import sockets, strutils, strtabs, base64, os import sockets, strutils, strtabs, base64, os
when not defined(noSSL):
import ssl
type type
TSMTP* {.final.} = object TSMTP* {.final.} = object
sock: TSocket sock: TSocket
when not defined(noSSL):
sslSock: TSecureSocket
ssl: Bool
debug: Bool debug: Bool
TMessage* {.final.} = object TMessage* {.final.} = object
@ -53,20 +50,13 @@ type
proc debugSend(smtp: TSMTP, cmd: string) = proc debugSend(smtp: TSMTP, cmd: string) =
if smtp.debug: if smtp.debug:
echo("C:" & cmd) echo("C:" & cmd)
if not smtp.ssl:
smtp.sock.send(cmd) smtp.sock.send(cmd)
else:
when not defined(noSSL):
smtp.sslSock.send(cmd)
proc debugRecv(smtp: TSMTP): TaintedString = proc debugRecv(smtp: var TSMTP): TaintedString =
var line = TaintedString"" var line = TaintedString""
var ret = False var ret = False
if not smtp.ssl:
ret = smtp.sock.recvLine(line) ret = smtp.sock.recvLine(line)
else:
when not defined(noSSL):
ret = smtp.sslSock.recvLine(line)
if ret: if ret:
if smtp.debug: if smtp.debug:
echo("S:" & line.string) echo("S:" & line.string)
@ -79,7 +69,7 @@ proc quitExcpt(smtp: TSMTP, msg: string) =
smtp.debugSend("QUIT") smtp.debugSend("QUIT")
raise newException(EInvalidReply, msg) raise newException(EInvalidReply, msg)
proc checkReply(smtp: TSMTP, reply: string) = proc checkReply(smtp: var TSMTP, reply: string) =
var line = smtp.debugRecv() var line = smtp.debugRecv()
if not line.string.startswith(reply): if not line.string.startswith(reply):
quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string) quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string)
@ -88,25 +78,21 @@ proc connect*(address: string, port = 25,
ssl = false, debug = false): TSMTP = ssl = false, debug = false): TSMTP =
## Establishes a connection with a SMTP server. ## Establishes a connection with a SMTP server.
## May fail with EInvalidReply or with a socket error. ## May fail with EInvalidReply or with a socket error.
if not ssl:
result.sock = socket() result.sock = socket()
result.sock.connect(address, TPort(port)) if ssl:
when defined(ssl):
result.sock.wrapSocket(verifyMode = CVerifyNone)
else: else:
when not defined(noSSL): raise newException(ESystem,
result.ssl = True
discard result.sslSock.connect(address, port)
else:
raise newException(EInvalidReply,
"SMTP module compiled without SSL support") "SMTP module compiled without SSL support")
result.sock.connect(address, TPort(port))
result.debug = debug result.debug = debug
result.checkReply("220") result.checkReply("220")
result.debugSend("HELO " & address & "\c\L") result.debugSend("HELO " & address & "\c\L")
result.checkReply("250") result.checkReply("250")
proc auth*(smtp: TSMTP, username, password: string) = proc auth*(smtp: var TSMTP, username, password: string) =
## Sends an AUTH command to the server to login as the `username` ## Sends an AUTH command to the server to login as the `username`
## using `password`. ## using `password`.
## May fail with EInvalidReply. ## May fail with EInvalidReply.
@ -120,7 +106,7 @@ proc auth*(smtp: TSMTP, username, password: string) =
smtp.debugSend(encode(password) & "\c\L") smtp.debugSend(encode(password) & "\c\L")
smtp.checkReply("235") # Check whether the authentification was successful. smtp.checkReply("235") # Check whether the authentification was successful.
proc sendmail*(smtp: TSMTP, fromaddr: string, proc sendmail*(smtp: var TSMTP, fromaddr: string,
toaddrs: seq[string], msg: string) = toaddrs: seq[string], msg: string) =
## Sends `msg` from `fromaddr` to `toaddr`. ## Sends `msg` from `fromaddr` to `toaddr`.
## Messages may be formed using ``createMessage`` by converting the ## Messages may be formed using ``createMessage`` by converting the
@ -142,10 +128,7 @@ proc sendmail*(smtp: TSMTP, fromaddr: string,
proc close*(smtp: TSMTP) = proc close*(smtp: TSMTP) =
## Disconnects from the SMTP server and closes the socket. ## Disconnects from the SMTP server and closes the socket.
smtp.debugSend("QUIT\c\L") smtp.debugSend("QUIT\c\L")
if not smtp.ssl:
smtp.sock.close() smtp.sock.close()
else:
smtp.sslSock.close()
proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string], proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string],
otherHeaders: openarray[tuple[name, value: string]]): TMessage = otherHeaders: openarray[tuple[name, value: string]]): TMessage =

View file

@ -10,11 +10,16 @@
## This module implements a simple portable type-safe sockets layer. ## This module implements a simple portable type-safe sockets layer.
## ##
## Most procedures raise EOS on error. ## Most procedures raise EOS on error.
##
## For OpenSSL support compile with ``-d:ssl``. When using SSL be aware that
## most functions will then raise ``ESSL`` on SSL errors.
import os, parseutils import os, parseutils
from times import epochTime from times import epochTime
when defined(ssl):
import openssl
when defined(Windows): when defined(Windows):
import winlean import winlean
else: else:
@ -22,8 +27,40 @@ else:
# Note: The enumerations are mapped to Window's constants. # Note: The enumerations are mapped to Window's constants.
when defined(ssl):
type type
TSocket* = distinct cint ## socket type ESSL* = object of ESynch
TSSLCVerifyMode* = enum
CVerifyNone, CVerifyPeer
TSSLProtVersion* = enum
protSSLv2, protSSLv3, protTLSv1, protSSLv23
TSSLOptions* = object
verifyMode*: TSSLCVerifyMode
certFile*, keyFile*: string
protVer*: TSSLprotVersion
type
TSocketImpl = object ## socket type
fd: cint
case isBuffered: bool # determines whether this socket is buffered.
of true:
buffer: array[0..4000, char]
currPos: int # current index in buffer
bufLen: int # current length of buffer
of false: nil
when defined(ssl):
case isSsl: bool
of true:
sslHandle: PSSL
sslContext: PSSLCTX
wrapOptions: TSSLOptions
of false: nil
TSocket* = ref TSocketImpl
TPort* = distinct int16 ## port type TPort* = distinct int16 ## port type
TDomain* = enum ## domain, which specifies the protocol family of the TDomain* = enum ## domain, which specifies the protocol family of the
@ -65,11 +102,15 @@ type
ETimeout* = object of ESynch ETimeout* = object of ESynch
const proc newTSocket(fd: int32, isBuff: bool): TSocket =
InvalidSocket* = TSocket(-1'i32) ## invalid socket number new(result)
result.fd = fd
result.isBuffered = isBuff
if isBuff:
result.currPos = 0
proc `==`*(a, b: TSocket): bool {.borrow.} let
## ``==`` for sockets. InvalidSocket*: TSocket = nil ## invalid socket
proc `==`*(a, b: TPort): bool {.borrow.} proc `==`*(a, b: TPort): bool {.borrow.}
## ``==`` for ports. ## ``==`` for ports.
@ -144,18 +185,111 @@ else:
result = cint(ord(p)) result = cint(ord(p))
proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
protocol: TProtocol = IPPROTO_TCP): TSocket = protocol: TProtocol = IPPROTO_TCP, buffered = true): TSocket =
## creates a new socket; returns `InvalidSocket` if an error occurs. ## creates a new socket; returns `InvalidSocket` if an error occurs.
when defined(Windows): when defined(Windows):
result = TSocket(winlean.socket(ord(domain), ord(typ), ord(protocol))) result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
else: else:
result = TSocket(posix.socket(ToInt(domain), ToInt(typ), ToInt(protocol))) result = newTSocket(posix.socket(ToInt(domain), ToInt(typ), ToInt(protocol)), buffered)
when defined(ssl):
CRYPTO_malloc_init()
SslLibraryInit()
SslLoadErrorStrings()
ErrLoadBioStrings()
OpenSSL_add_all_algorithms()
proc SSLError(s = "") =
if s != "":
raise newException(ESSL, s)
let err = ErrGetError()
if err == 0:
raise newException(ESSL, "An EOF was observed that violates the protocol.")
if err == -1:
OSError()
var errStr = ErrErrorString(err, nil)
raise newException(ESSL, $errStr)
# http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
proc loadCertificates(socket: var TSocket, certFile, keyFile: string) =
if certFile != "":
if SSLCTXUseCertificateFile(socket.sslContext, certFile,
SSL_FILETYPE_PEM) != 1:
SSLError()
if keyFile != "":
if SSL_CTX_use_PrivateKey_file(socket.sslContext, keyFile,
SSL_FILETYPE_PEM) != 1:
SSLError()
if SSL_CTX_check_private_key(socket.sslContext) != 1:
SSLError("Verification of private key file failed.")
proc wrapSocket*(socket: var TSocket, protVersion = ProtSSLv23,
verifyMode = CVerifyPeer,
certFile = "", keyFile = "") =
## Creates a SSL context for ``socket`` and wraps the socket in it.
##
## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are
## are available with the addition of ``ProtSSLv23`` which allows for
## compatibility with all of them.
##
## There are currently only two options for verify mode; one is ``CVerifyNone``
## and with it certificates will not be verified the other is ``CVerifyPeer``
## and certificates will be verified for it, ``CVerifyPeer`` is the safest choice.
##
## The last two parameters specify the certificate file path and the key file
## path, a server socket will most likely not work without these.
## Certificates can be generated using the following command:
## ``openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem``.
##
## **Warning:** Because SSL is meant to be secure I feel the need to warn you
## that this "wrapper" has not been thorougly tested and is therefore
## most likely very prone to security vulnerabilities.
socket.isSSL = true
socket.wrapOptions.verifyMode = verifyMode
socket.wrapOptions.certFile = certFile
socket.wrapOptions.keyFile = keyFile
socket.wrapOptions.protVer = protVersion
case protVersion
of protSSLv23:
socket.sslContext = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
of protSSLv2:
socket.sslContext = SSL_CTX_new(SSLv2_method())
of protSSLv3:
socket.sslContext = SSL_CTX_new(SSLv3_method())
of protTLSv1:
socket.sslContext = SSL_CTX_new(TLSv1_method())
if socket.sslContext.SSLCTXSetCipherList("ALL") != 1:
SSLError()
case verifyMode
of CVerifyPeer:
socket.sslContext.SSLCTXSetVerify(SSLVerifyPeer, nil)
of CVerifyNone:
socket.sslContext.SSLCTXSetVerify(SSLVerifyNone, nil)
if socket.sslContext == nil:
SSLError()
socket.loadCertificates(certFile, keyFile)
socket.sslHandle = SSLNew(socket.sslContext)
if socket.sslHandle == nil:
SSLError()
if SSLSetFd(socket.sslHandle, socket.fd) != 1:
SSLError()
proc wrapSocket*(socket: var TSocket, wo: TSSLOptions) =
## A variant of the above with a options object.
wrapSocket(socket, wo.protVer, wo.verifyMode, wo.certFile, wo.keyFile)
proc listen*(socket: TSocket, backlog = SOMAXCONN) = proc listen*(socket: TSocket, backlog = SOMAXCONN) =
## Marks ``socket`` as accepting connections. ## Marks ``socket`` as accepting connections.
## ``Backlog`` specifies the maximum length of the ## ``Backlog`` specifies the maximum length of the
## queue of pending connections. ## queue of pending connections.
if listen(cint(socket), cint(backlog)) < 0'i32: OSError() if listen(socket.fd, cint(backlog)) < 0'i32: OSError()
proc invalidIp4(s: string) {.noreturn, noinline.} = proc invalidIp4(s: string) {.noreturn, noinline.} =
raise newException(EInvalidValue, "invalid ip4 address: " & s) raise newException(EInvalidValue, "invalid ip4 address: " & s)
@ -208,7 +342,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") =
name.sin_family = posix.AF_INET name.sin_family = posix.AF_INET
name.sin_port = sockets.htons(int16(port)) name.sin_port = sockets.htons(int16(port))
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY) name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
if bindSocket(cint(socket), cast[ptr TSockAddr](addr(name)), if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)),
sizeof(name)) < 0'i32: sizeof(name)) < 0'i32:
OSError() OSError()
else: else:
@ -218,7 +352,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") =
hints.ai_socktype = toInt(SOCK_STREAM) hints.ai_socktype = toInt(SOCK_STREAM)
hints.ai_protocol = toInt(IPPROTO_TCP) hints.ai_protocol = toInt(IPPROTO_TCP)
gaiNim(address, port, hints, aiList) gaiNim(address, port, hints, aiList)
if bindSocket(cint(socket), aiList.ai_addr, aiList.ai_addrLen) < 0'i32: if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrLen) < 0'i32:
OSError() OSError()
when false: when false:
@ -245,22 +379,29 @@ proc getSockName*(socket: TSocket): TPort =
#name.sin_port = htons(cint16(port)) #name.sin_port = htons(cint16(port))
#name.sin_addr.s_addr = htonl(INADDR_ANY) #name.sin_addr.s_addr = htonl(INADDR_ANY)
var namelen: cint = sizeof(name) var namelen: cint = sizeof(name)
if getsockname(cint(socket), cast[ptr TSockAddr](addr(name)), if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)),
addr(namelen)) == -1'i32: addr(namelen)) == -1'i32:
OSError() OSError()
result = TPort(sockets.ntohs(name.sin_port)) result = TPort(sockets.ntohs(name.sin_port))
proc acceptAddr*(server: TSocket): tuple[sock: TSocket, address: string] = proc selectWrite*(writefds: var seq[TSocket], timeout = 500): int
proc acceptAddr*(server: TSocket): tuple[client: TSocket, address: string] =
## Blocks until a connection is being made from a client. When a connection ## Blocks until a connection is being made from a client. When a connection
## is made returns the client socket and address of the connecting client. ## is made sets ``client`` to the client socket and ``address`` to the address
## of the connecting client.
## If ``server`` is non-blocking then this function returns immediately, and ## If ``server`` is non-blocking then this function returns immediately, and
## if there are no connections queued the returned socket will be ## if there are no connections queued the returned socket will be
## ``InvalidSocket``. ## ``InvalidSocket``.
## This function will raise EOS if an error occurs. ## This function will raise EOS if an error occurs.
var address: Tsockaddr_in ##
var addrLen: cint = sizeof(address) ## **Warning:** This function might block even if socket is non-blocking
var sock = accept(cint(server), cast[ptr TSockAddr](addr(address)), ## when using SSL.
var sockAddress: Tsockaddr_in
var addrLen: cint = sizeof(sockAddress)
var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
addr(addrLen)) addr(addrLen))
if sock < 0: if sock < 0:
# TODO: Test on Windows. # TODO: Test on Windows.
when defined(windows): when defined(windows):
@ -272,20 +413,54 @@ proc acceptAddr*(server: TSocket): tuple[sock: TSocket, address: string] =
if errno == EAGAIN or errno == EWOULDBLOCK: if errno == EAGAIN or errno == EWOULDBLOCK:
return (InvalidSocket, "") return (InvalidSocket, "")
else: OSError() else: OSError()
else: return (TSocket(sock), $inet_ntoa(address.sin_addr)) else:
when defined(ssl):
if server.isSSL:
# We must wrap the client sock in a ssl context.
var client = newTSocket(sock, server.isBuffered)
let wo = server.wrapOptions
wrapSocket(client, wo.protVer, wo.verifyMode,
wo.certFile, wo.keyFile)
let ret = SSLAccept(client.sslHandle)
while ret <= 0:
let err = SSLGetError(client.sslHandle, ret)
if err != SSL_ERROR_WANT_ACCEPT:
case err
of SSL_ERROR_ZERO_RETURN:
SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT:
SSLError("The operation did not complete. Perhaps you should use connectAsync?")
of SSL_ERROR_WANT_ACCEPT:
var sss: seq[TSocket] = @[client]
discard selectWrite(sss, 1500)
continue
of SSL_ERROR_WANT_X509_LOOKUP:
SSLError("Function for x509 lookup has been called.")
of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
SSLError()
else:
SSLError("Unknown error")
return (client, $inet_ntoa(sockAddress.sin_addr))
return (newTSocket(sock, server.isBuffered), $inet_ntoa(sockAddress.sin_addr))
proc accept*(server: TSocket): TSocket = proc accept*(server: TSocket): TSocket =
## Equivalent to ``acceptAddr`` but doesn't return the address, only the ## Equivalent to ``acceptAddr`` but doesn't return the address, only the
## socket. ## socket.
var (client, a) = acceptAddr(server) let (client, a) = acceptAddr(server)
return client return client
proc close*(socket: TSocket) = proc close*(socket: TSocket) =
## closes a socket. ## closes a socket.
when defined(windows): when defined(windows):
discard winlean.closeSocket(cint(socket)) discard winlean.closeSocket(socket.fd)
else: else:
discard posix.close(cint(socket)) discard posix.close(socket.fd)
when defined(ssl):
if socket.isSSL:
discard SSLShutdown(socket.sslHandle)
SSLCTXFree(socket.sslContext)
proc getServByName*(name, proto: string): TServent = proc getServByName*(name, proto: string): TServent =
## well-known getservbyname proc. ## well-known getservbyname proc.
@ -365,7 +540,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int =
## getsockopt for integer options. ## getsockopt for integer options.
var res: cint var res: cint
var size: cint = sizeof(res) var size: cint = sizeof(res)
if getsockopt(cint(socket), cint(level), cint(optname), if getsockopt(socket.fd, cint(level), cint(optname),
addr(res), addr(size)) < 0'i32: addr(res), addr(size)) < 0'i32:
OSError() OSError()
result = int(res) result = int(res)
@ -373,7 +548,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int =
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) = proc setSockOptInt*(socket: TSocket, level, optname, optval: int) =
## setsockopt for integer options. ## setsockopt for integer options.
var value = cint(optval) var value = cint(optval)
if setsockopt(cint(socket), cint(level), cint(optname), addr(value), if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
sizeof(value)) < 0'i32: sizeof(value)) < 0'i32:
OSError() OSError()
@ -395,7 +570,7 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
var success = false var success = false
var it = aiList var it = aiList
while it != nil: while it != nil:
if connect(cint(socket), it.ai_addr, it.ai_addrlen) == 0'i32: if connect(socket.fd, it.ai_addr, it.ai_addrlen) == 0'i32:
success = true success = true
break break
it = it.ai_next it = it.ai_next
@ -403,6 +578,24 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
freeaddrinfo(aiList) freeaddrinfo(aiList)
if not success: OSError() if not success: OSError()
when defined(ssl):
if socket.isSSL:
let ret = SSLConnect(socket.sslHandle)
if ret <= 0:
let err = SSLGetError(socket.sslHandle, ret)
case err
of SSL_ERROR_ZERO_RETURN:
SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT,
SSL_ERROR_WANT_ACCEPT:
SSLError("The operation did not complete. Perhaps you should use connectAsync?")
of SSL_ERROR_WANT_X509_LOOKUP:
SSLError("Function for x509 lookup has been called.")
of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
SSLError()
else:
SSLError("Unknown error")
when false: when false:
var s: TSockAddrIn var s: TSockAddrIn
s.sin_addr.s_addr = inet_addr(name) s.sin_addr.s_addr = inet_addr(name)
@ -415,7 +608,7 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
of AF_INET: s.sin_family = posix.AF_INET of AF_INET: s.sin_family = posix.AF_INET
of AF_INET6: s.sin_family = posix.AF_INET6 of AF_INET6: s.sin_family = posix.AF_INET6
else: nil else: nil
if connect(cint(socket), cast[ptr TSockAddr](addr(s)), sizeof(s)) < 0'i32: if connect(socket.fd, cast[ptr TSockAddr](addr(s)), sizeof(s)) < 0'i32:
OSError() OSError()
proc connectAsync*(socket: TSocket, name: string, port = TPort(0), proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
@ -431,7 +624,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
var success = false var success = false
var it = aiList var it = aiList
while it != nil: while it != nil:
var ret = connect(cint(socket), it.ai_addr, it.ai_addrlen) var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen)
if ret == 0'i32: if ret == 0'i32:
success = true success = true
break break
@ -453,6 +646,26 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
freeaddrinfo(aiList) freeaddrinfo(aiList)
if not success: OSError() if not success: OSError()
when defined(ssl):
if socket.isSSL:
var ret = SSLConnect(socket.sslHandle)
if ret <= 0:
var errret = SSLGetError(socket.sslHandle, ret)
case errret
of SSL_ERROR_ZERO_RETURN:
SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE,
SSL_ERROR_WANT_ACCEPT:
SSLError("Unexpected error occured.") # This should just not happen.
of SSL_ERROR_WANT_CONNECT:
return
of SSL_ERROR_WANT_X509_LOOKUP:
SSLError("Function for x509 lookup has been called.")
of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
SSLError()
else:
SSLError("Unknown Error")
proc timeValFromMilliseconds(timeout = 500): TTimeVal = proc timeValFromMilliseconds(timeout = 500): TTimeVal =
if timeout != -1: if timeout != -1:
var seconds = timeout div 1000 var seconds = timeout div 1000
@ -467,14 +680,14 @@ proc timeValFromMilliseconds(timeout = 500): TTimeVal =
proc createFdSet(fd: var TFdSet, s: seq[TSocket], m: var int) = proc createFdSet(fd: var TFdSet, s: seq[TSocket], m: var int) =
FD_ZERO(fd) FD_ZERO(fd)
for i in items(s): for i in items(s):
m = max(m, int(i)) m = max(m, int(i.fd))
FD_SET(cint(i), fd) FD_SET(i.fd, fd)
proc pruneSocketSet(s: var seq[TSocket], fd: var TFdSet) = proc pruneSocketSet(s: var seq[TSocket], fd: var TFdSet) =
var i = 0 var i = 0
var L = s.len var L = s.len
while i < L: while i < L:
if FD_ISSET(cint(s[i]), fd) != 0'i32: if FD_ISSET(s[i].fd, fd) != 0'i32:
s[i] = s[L-1] s[i] = s[L-1]
dec(L) dec(L)
else: else:
@ -553,11 +766,76 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int =
pruneSocketSet(readfds, (rd)) pruneSocketSet(readfds, (rd))
proc readIntoBuf(socket: TSocket, flags: int32): int =
result = 0
when defined(ssl):
if socket.isSSL:
result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
else:
result = recv(socket.fd, addr(socket.buffer), int(socket.buffer.high), flags)
else:
result = recv(socket.fd, addr(socket.buffer), int(socket.buffer.high), flags)
if result <= 0:
socket.buflen = 0
socket.currPos = 0
return result
socket.bufLen = result
socket.currPos = 0
template retRead(flags, readBytes: int) =
let res = socket.readIntoBuf(flags)
if res <= 0:
if readBytes > 0:
return readBytes
else:
return res
proc recv*(socket: TSocket, data: pointer, size: int): int = proc recv*(socket: TSocket, data: pointer, size: int): int =
## receives data from a socket ## receives data from a socket
result = recv(cint(socket), data, size, 0'i32) if socket.isBuffered:
if socket.bufLen == 0:
retRead(0'i32, 0)
template waitFor(): stmt = when true:
var read = 0
while read < size:
if socket.currPos >= socket.bufLen:
retRead(0'i32, read)
let chunk = min(socket.bufLen-socket.currPos, size-read)
var d = cast[cstring](data)
copyMem(addr(d[read]), addr(socket.buffer[socket.currPos]), chunk)
read.inc(chunk)
socket.currPos.inc(chunk)
else:
var read = 0
while read < size:
if socket.currPos >= socket.bufLen:
retRead(0'i32, read)
var d = cast[cstring](data)
d[read] = socket.buffer[socket.currPos]
read.inc(1)
socket.currPos.inc(1)
result = read
else:
when defined(ssl):
if socket.isSSL:
result = SSLRead(socket.sslHandle, data, size)
else:
result = recv(socket.fd, data, size, 0'i32)
else:
result = recv(socket.fd, data, size, 0'i32)
proc waitFor(socket: TSocket, waited: var float, timeout: int): int =
## returns the number of characters available to be read. In unbuffered
## sockets this is always 1, otherwise this may as big as the buffer, currently
## 4000.
result = 1
if socket.isBuffered and socket.bufLen != 0 and socket.bufLen != socket.currPos:
result = socket.bufLen - socket.currPos
else:
if timeout - int(waited * 1000.0) < 1: if timeout - int(waited * 1000.0) < 1:
raise newException(ETimeout, "Call to recv() timed out.") raise newException(ETimeout, "Call to recv() timed out.")
var s = @[socket] var s = @[socket]
@ -566,20 +844,38 @@ template waitFor(): stmt =
raise newException(ETimeout, "Call to recv() timed out.") raise newException(ETimeout, "Call to recv() timed out.")
waited += (epochTime() - startTime) waited += (epochTime() - startTime)
proc recv*(socket: TSocket, data: var string, size: int, timeout: int): int = proc recv*(socket: TSocket, data: pointer, size: int, timeout: int): int =
## overload with a ``timeout`` parameter in miliseconds. ## overload with a ``timeout`` parameter in miliseconds.
var waited = 0.0 # number of seconds already waited var waited = 0.0 # number of seconds already waited
var read = 0 var read = 0
while read < size: while read < size:
waitFor() let avail = waitFor(socket, waited, timeout)
result = recv(cint(socket), addr(data[read]), 1, 0'i32) var d = cast[cstring](data)
result = recv(socket, addr(d[read]), avail)
if result == 0: break
if result < 0: if result < 0:
return return result
inc(read) inc(read, result)
result = read result = read
proc peekChar(socket: TSocket, c: var char): int =
if socket.isBuffered:
result = 1
if socket.bufLen == 0 or socket.currPos > socket.bufLen-1:
var res = socket.readIntoBuf(0'i32)
if res <= 0:
result = res
c = socket.buffer[socket.currPos]
else:
when defined(ssl):
if socket.isSSL:
raise newException(ESSL, "Sorry, you cannot use recvLine on an unbuffered SSL socket.")
result = recv(socket.fd, addr(c), 1, MSG_PEEK)
proc recvLine*(socket: TSocket, line: var TaintedString): bool = proc recvLine*(socket: TSocket, line: var TaintedString): bool =
## retrieves a line from ``socket``. If a full line is received ``\r\L`` is not ## retrieves a line from ``socket``. If a full line is received ``\r\L`` is not
## added to ``line``, however if solely ``\r\L`` is received then ``data`` ## added to ``line``, however if solely ``\r\L`` is received then ``data``
@ -590,6 +886,9 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
## ##
## If the socket is disconnected, ``line`` will be set to ``""`` and ``True`` ## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
## will be returned. ## will be returned.
##
## **Warning:** Using this function on a unbuffered ssl socket will result
## in an error.
template addNLIfEmpty(): stmt = template addNLIfEmpty(): stmt =
if line.len == 0: if line.len == 0:
line.add("\c\L") line.add("\c\L")
@ -597,13 +896,13 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
setLen(line.string, 0) setLen(line.string, 0)
while true: while true:
var c: char var c: char
var n = recv(cint(socket), addr(c), 1, 0'i32) var n = recv(socket, addr(c), 1)
if n < 0: return if n < 0: return
elif n == 0: return true elif n == 0: return true
if c == '\r': if c == '\r':
n = recv(cint(socket), addr(c), 1, MSG_PEEK) n = peekChar(socket, c)
if n > 0 and c == '\L': if n > 0 and c == '\L':
discard recv(cint(socket), addr(c), 1, 0'i32) discard recv(socket, addr(c), 1)
elif n <= 0: return false elif n <= 0: return false
addNlIfEmpty() addNlIfEmpty()
return true return true
@ -624,15 +923,15 @@ proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool =
setLen(line.string, 0) setLen(line.string, 0)
while true: while true:
var c: char var c: char
waitFor() discard waitFor(socket, waited, timeout)
var n = recv(cint(socket), addr(c), 1, 0'i32) var n = recv(socket, addr(c), 1)
if n < 0: return if n < 0: return
elif n == 0: return true elif n == 0: return true
if c == '\r': if c == '\r':
waitFor() discard waitFor(socket, waited, timeout)
n = recv(cint(socket), addr(c), 1, MSG_PEEK) n = peekChar(socket, c)
if n > 0 and c == '\L': if n > 0 and c == '\L':
discard recv(cint(socket), addr(c), 1, 0'i32) discard recv(socket, addr(c), 1)
elif n <= 0: return false elif n <= 0: return false
addNlIfEmpty() addNlIfEmpty()
return true return true
@ -651,15 +950,15 @@ proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
setLen(line.string, 0) setLen(line.string, 0)
while true: while true:
var c: char var c: char
var n = recv(cint(socket), addr(c), 1, 0'i32) var n = recv(socket, addr(c), 1)
if n < 0: if n < 0:
return (if line.len == 0: RecvFail else: RecvPartialLine) return (if line.len == 0: RecvFail else: RecvPartialLine)
elif n == 0: elif n == 0:
return (if line.len == 0: RecvDisconnected else: RecvPartialLine) return (if line.len == 0: RecvDisconnected else: RecvPartialLine)
if c == '\r': if c == '\r':
n = recv(cint(socket), addr(c), 1, MSG_PEEK) n = peekChar(socket, c)
if n > 0 and c == '\L': if n > 0 and c == '\L':
discard recv(cint(socket), addr(c), 1, 0'i32) discard recv(socket, addr(c), 1)
elif n <= 0: elif n <= 0:
return (if line.len == 0: RecvFail else: RecvPartialLine) return (if line.len == 0: RecvFail else: RecvPartialLine)
return RecvFullLine return RecvFullLine
@ -671,7 +970,7 @@ proc recv*(socket: TSocket): TaintedString =
## Socket errors will result in an ``EOS`` error. ## Socket errors will result in an ``EOS`` error.
## If socket is not a connectionless socket and socket is not connected ## If socket is not a connectionless socket and socket is not connected
## ``""`` will be returned. ## ``""`` will be returned.
const bufSize = 1000 const bufSize = 4000
result = newStringOfCap(bufSize).TaintedString result = newStringOfCap(bufSize).TaintedString
var pos = 0 var pos = 0
while true: while true:
@ -699,6 +998,7 @@ proc recvTimeout*(socket: TSocket, timeout: int): TaintedString =
## overloaded variant to support a ``timeout`` parameter, the ``timeout`` ## overloaded variant to support a ``timeout`` parameter, the ``timeout``
## parameter specifies the amount of miliseconds to wait for data on the ## parameter specifies the amount of miliseconds to wait for data on the
## socket. ## socket.
if socket.bufLen == 0:
var s = @[socket] var s = @[socket]
if s.select(timeout) != 1: if s.select(timeout) != 1:
raise newException(ETimeout, "Call to recv() timed out.") raise newException(ETimeout, "Call to recv() timed out.")
@ -718,7 +1018,24 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
var pos = 0 var pos = 0
while true: while true:
var bytesRead = recv(socket, addr(string(s)[pos]), bufSize-1) var bytesRead = recv(socket, addr(string(s)[pos]), bufSize-1)
if bytesRead == -1: when defined(ssl):
if socket.isSSL:
if bytesRead <= 0:
var ret = SSLGetError(socket.sslHandle, bytesRead)
case ret
of SSL_ERROR_ZERO_RETURN:
SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
SSLError("Unexpected error occured.") # This should just not happen.
of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
return false
of SSL_ERROR_WANT_X509_LOOKUP:
SSLError("Function for x509 lookup has been called.")
of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
SSLError()
else: SSLError("Unknown Error")
if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
when defined(windows): when defined(windows):
# TODO: Test on Windows # TODO: Test on Windows
var err = WSAGetLastError() var err = WSAGetLastError()
@ -746,19 +1063,46 @@ proc skip*(socket: TSocket) =
proc send*(socket: TSocket, data: pointer, size: int): int = proc send*(socket: TSocket, data: pointer, size: int): int =
## sends data to a socket. ## sends data to a socket.
when defined(ssl):
if socket.isSSL:
return SSLWrite(socket.sslHandle, cast[cstring](data), size)
when defined(windows) or defined(macosx): when defined(windows) or defined(macosx):
result = send(cint(socket), data, size, 0'i32) result = send(socket.fd, data, size, 0'i32)
else: else:
result = send(cint(socket), data, size, int32(MSG_NOSIGNAL)) result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
proc send*(socket: TSocket, data: string) = proc send*(socket: TSocket, data: string) =
## sends data to a socket. ## sends data to a socket.
if send(socket, cstring(data), data.len) != data.len: OSError() if send(socket, cstring(data), data.len) != data.len:
when defined(ssl):
if socket.isSSL:
SSLError()
OSError()
proc sendAsync*(socket: TSocket, data: string): bool = proc sendAsync*(socket: TSocket, data: string): bool =
## sends data to a non-blocking socket. Returns whether ``data`` was sent. ## sends data to a non-blocking socket. Returns whether ``data`` was sent.
result = true result = true
var bytesSent = send(socket, cstring(data), data.len) var bytesSent = send(socket, cstring(data), data.len)
when defined(ssl):
if socket.isSSL:
if bytesSent <= 0:
let ret = SSLGetError(socket.sslHandle, bytesSent)
case ret
of SSL_ERROR_ZERO_RETURN:
SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
SSLError("Unexpected error occured.") # This should just not happen.
of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
return false
of SSL_ERROR_WANT_X509_LOOKUP:
SSLError("Function for x509 lookup has been called.")
of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
SSLError()
else: SSLError("Unknown Error")
else:
return
if bytesSent == -1: if bytesSent == -1:
when defined(windows): when defined(windows):
var err = WSAGetLastError() var err = WSAGetLastError()
@ -792,15 +1136,15 @@ proc setBlocking*(s: TSocket, blocking: bool) =
## sets blocking mode on socket ## sets blocking mode on socket
when defined(Windows): when defined(Windows):
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
if SOCKET_ERROR == ioctlsocket(TWinSocket(s), FIONBIO, addr(mode)): if SOCKET_ERROR == ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)):
OSError() OSError()
else: # BSD sockets else: # BSD sockets
var x: int = fcntl(cint(s), F_GETFL, 0) var x: int = fcntl(s.fd, F_GETFL, 0)
if x == -1: if x == -1:
OSError() OSError()
else: else:
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
if fcntl(cint(s), F_SETFL, mode) == -1: if fcntl(s.fd, F_SETFL, mode) == -1:
OSError() OSError()
proc connect*(socket: TSocket, timeout: int, name: string, port = TPort(0), proc connect*(socket: TSocket, timeout: int, name: string, port = TPort(0),

View file

@ -557,9 +557,9 @@ proc format*(info: TTimeInfo, f: string): string =
result.add("0") result.add("0")
result.add($info.monthday) result.add($info.monthday)
of "ddd": of "ddd":
result.add(($info.monthday)[0 .. 2]) result.add(($info.weekday)[0 .. 2])
of "dddd": of "dddd":
result.add($info.monthday) result.add($info.weekday)
of "h": of "h":
result.add($(info.hour - 12)) result.add($(info.hour - 12))
of "hh": of "hh":

View file

@ -18,9 +18,9 @@ type
TRune* = distinct irune ## type that can hold any Unicode character TRune* = distinct irune ## type that can hold any Unicode character
TRune16* = distinct int16 ## 16 bit Unicode character TRune16* = distinct int16 ## 16 bit Unicode character
proc `<=%`*(a, b: TRune): bool {.borrow.} proc `<=%`*(a, b: TRune): bool = return int(a) <=% int(b)
proc `<%`*(a, b: TRune): bool {.borrow.} proc `<%`*(a, b: TRune): bool = return int(a) <% int(b)
proc `==`*(a, b: TRune): bool {.borrow.} proc `==`*(a, b: TRune): bool = return int(a) == int(b)
template ones(n: expr): expr = ((1 shl n)-1) template ones(n: expr): expr = ((1 shl n)-1)

View file

@ -21,9 +21,15 @@ type
int16* {.magic: Int16.} ## signed 16 bit integer type int16* {.magic: Int16.} ## signed 16 bit integer type
int32* {.magic: Int32.} ## signed 32 bit integer type int32* {.magic: Int32.} ## signed 32 bit integer type
int64* {.magic: Int64.} ## signed 64 bit integer type int64* {.magic: Int64.} ## signed 64 bit integer type
uint* {.magic: UInt.} ## unsigned default integer type
uint8* {.magic: UInt8.} ## unsigned 8 bit integer type
uint16* {.magic: UInt16.} ## unsigned 16 bit integer type
uint32* {.magic: UInt32.} ## unsigned 32 bit integer type
uint64* {.magic: UInt64.} ## unsigned 64 bit integer type
float* {.magic: Float.} ## default floating point type float* {.magic: Float.} ## default floating point type
float32* {.magic: Float32.} ## 32 bit floating point type float32* {.magic: Float32.} ## 32 bit floating point type
float64* {.magic: Float64.} ## 64 bit floating point type float64* {.magic: Float64.} ## 64 bit floating point type
type # we need to start a new type section here, so that ``0`` can have a type type # we need to start a new type section here, so that ``0`` can have a type
bool* {.magic: Bool.} = enum ## built-in boolean type bool* {.magic: Bool.} = enum ## built-in boolean type
false = 0, true = 1 false = 0, true = 1
@ -49,14 +55,23 @@ type
## a type description (for templates) ## a type description (for templates)
void* {.magic: "VoidType".} ## meta type to denote the absense of any type void* {.magic: "VoidType".} ## meta type to denote the absense of any type
TInteger* = int|int8|int16|int32|int64 TSignedInt* = distinct int|int8|int16|int32|int64
## type class matching all signed integer types
TUnsignedInt* = distinct uint|uint8|uint16|uint32|uint64
## type class matching all unsigned integer types
TInteger* = distinct TSignedInt|TUnsignedInt
## type class matching all integer types ## type class matching all integer types
TOrdinal* = TInteger|bool|enum TOrdinal* = distinct TInteger|bool|enum
## type class matching all ordinal types; however this includes enums with ## type class matching all ordinal types; however this includes enums with
## holes. ## holes.
TNumber* = TInteger|float|float32|float64 TReal* = distinct float|float32|float64
## type class matching all floating point number types
TNumber* = distinct TInteger|TReal
## type class matching all number types ## type class matching all number types
proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.} proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.}
@ -517,65 +532,88 @@ proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.}
## is -MININT for its type), an overflow exception is thrown (if overflow ## is -MININT for its type), an overflow exception is thrown (if overflow
## checking is turned on). ## checking is turned on).
proc `+%` *(x, y: int): int {.magic: "AddU", noSideEffect.} type
proc `+%` *(x, y: int8): int8 {.magic: "AddU", noSideEffect.} UIntMax32 = distinct uint|uint8|uint16|uint32
proc `+%` *(x, y: int16): int16 {.magic: "AddU", noSideEffect.} IntMax32 = distinct int|int8|int16|int32
proc `+%` *(x, y: int32): int32 {.magic: "AddU", noSideEffect.}
proc `+%` *(x, y: int64): int64 {.magic: "AddU64", noSideEffect.} proc `+` *(x, y: UIntMax32): UIntMax32 {.magic: "AddU", noSideEffect.}
proc `+` *(x, y: UInt64): uint64 {.magic: "AddU64", noSideEffect.}
## Binary `+` operator for unsigned integers.
proc `+%` *(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.}
proc `+%` *(x, y: Int64): Int64 {.magic: "AddU64", noSideEffect.}
## treats `x` and `y` as unsigned and adds them. The result is truncated to ## treats `x` and `y` as unsigned and adds them. The result is truncated to
## fit into the result. This implements modulo arithmetic. No overflow ## fit into the result. This implements modulo arithmetic. No overflow
## errors are possible. ## errors are possible.
proc `-%` *(x, y: int): int {.magic: "SubU", noSideEffect.} proc `-` *(x, y: UIntMax32): UIntMax32 {.magic: "SubU", noSideEffect.}
proc `-%` *(x, y: int8): int8 {.magic: "SubU", noSideEffect.} proc `-` *(x, y: UInt64): UInt64 {.magic: "SubU64", noSideEffect.}
proc `-%` *(x, y: int16): int16 {.magic: "SubU", noSideEffect.} ## Binary `-` operator for unsigned integers.
proc `-%` *(x, y: int32): int32 {.magic: "SubU", noSideEffect.}
proc `-%` *(x, y: int64): int64 {.magic: "SubU64", noSideEffect.} proc `-%` *(x, y: IntMax32): IntMax32 {.magic: "SubU", noSideEffect.}
proc `-%` *(x, y: Int64): Int64 {.magic: "SubU64", noSideEffect.}
## treats `x` and `y` as unsigned and subtracts them. The result is ## treats `x` and `y` as unsigned and subtracts them. The result is
## truncated to fit into the result. This implements modulo arithmetic. ## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible. ## No overflow errors are possible.
proc `*%` *(x, y: int): int {.magic: "MulU", noSideEffect.} proc `*` *(x, y: UIntMax32): UIntMax32 {.magic: "MulU", noSideEffect.}
proc `*%` *(x, y: int8): int8 {.magic: "MulU", noSideEffect.} proc `*` *(x, y: UInt64): UInt64 {.magic: "MulU64", noSideEffect.}
proc `*%` *(x, y: int16): int16 {.magic: "MulU", noSideEffect.} ## Binary `*` operator for unsigned integers.
proc `*%` *(x, y: int32): int32 {.magic: "MulU", noSideEffect.}
proc `*%` *(x, y: int64): int64 {.magic: "MulU64", noSideEffect.} proc `*%` *(x, y: IntMax32): IntMax32 {.magic: "MulU", noSideEffect.}
proc `*%` *(x, y: Int64): Int64 {.magic: "MulU64", noSideEffect.}
## treats `x` and `y` as unsigned and multiplies them. The result is ## treats `x` and `y` as unsigned and multiplies them. The result is
## truncated to fit into the result. This implements modulo arithmetic. ## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible. ## No overflow errors are possible.
proc `/%` *(x, y: int): int {.magic: "DivU", noSideEffect.} proc `div` *(x, y: UIntMax32): UIntMax32 {.magic: "DivU", noSideEffect.}
proc `/%` *(x, y: int8): int8 {.magic: "DivU", noSideEffect.} proc `div` *(x, y: UInt64): UInt64 {.magic: "DivU64", noSideEffect.}
proc `/%` *(x, y: int16): int16 {.magic: "DivU", noSideEffect.} ## computes the integer division. This is roughly the same as
proc `/%` *(x, y: int32): int32 {.magic: "DivU", noSideEffect.} ## ``floor(x/y)``.
proc `/%` *(x, y: int64): int64 {.magic: "DivU64", noSideEffect.}
proc `/` *(x, y: UIntMax32): UIntMax32 {.magic: "DivU", noSideEffect.}
proc `/` *(x, y: UInt64): UInt64 {.magic: "DivU64", noSideEffect.}
## computes the integer division. This is roughly the same as
## ``floor(x/y)``.
proc `/%` *(x, y: IntMax32): IntMax32 {.magic: "DivU", noSideEffect.}
proc `/%` *(x, y: Int64): Int64 {.magic: "DivU64", noSideEffect.}
## treats `x` and `y` as unsigned and divides them. The result is ## treats `x` and `y` as unsigned and divides them. The result is
## truncated to fit into the result. This implements modulo arithmetic. ## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible. ## No overflow errors are possible.
proc `%%` *(x, y: int): int {.magic: "ModU", noSideEffect.} proc `%` *(x, y: UIntMax32): UIntMax32 {.magic: "DivU", noSideEffect.}
proc `%%` *(x, y: int8): int8 {.magic: "ModU", noSideEffect.} proc `%` *(x, y: UInt64): UInt64 {.magic: "DivU64", noSideEffect.}
proc `%%` *(x, y: int16): int16 {.magic: "ModU", noSideEffect.} ## computes the integer modulo operation. This is the same as
proc `%%` *(x, y: int32): int32 {.magic: "ModU", noSideEffect.} ## ``x - (x div y) * y``.
proc `%%` *(x, y: int64): int64 {.magic: "ModU64", noSideEffect.}
proc `mod` *(x, y: UIntMax32): UIntMax32 {.magic: "DivU", noSideEffect.}
proc `mod` *(x, y: UInt64): UInt64 {.magic: "DivU64", noSideEffect.}
## computes the integer modulo operation. This is the same as
## ``x - (x div y) * y``.
proc `%%` *(x, y: IntMax32): IntMax32 {.magic: "ModU", noSideEffect.}
proc `%%` *(x, y: Int64): Int64 {.magic: "ModU64", noSideEffect.}
## treats `x` and `y` as unsigned and compute the modulo of `x` and `y`. ## treats `x` and `y` as unsigned and compute the modulo of `x` and `y`.
## The result is truncated to fit into the result. ## The result is truncated to fit into the result.
## This implements modulo arithmetic. ## This implements modulo arithmetic.
## No overflow errors are possible. ## No overflow errors are possible.
proc `<=%` *(x, y: int): bool {.magic: "LeU", noSideEffect.} proc `<=` *(x, y: UIntMax32): bool {.magic: "LeU", noSideEffect.}
proc `<=%` *(x, y: int8): bool {.magic: "LeU", noSideEffect.} proc `<=` *(x, y: UInt64): bool {.magic: "LeU64", noSideEffect.}
proc `<=%` *(x, y: int16): bool {.magic: "LeU", noSideEffect.} ## Returns true iff ``x <= y``.
proc `<=%` *(x, y: int32): bool {.magic: "LeU", noSideEffect.}
proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.} proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
proc `<=%` *(x, y: Int64): bool {.magic: "LeU64", noSideEffect.}
## treats `x` and `y` as unsigned and compares them. ## treats `x` and `y` as unsigned and compares them.
## Returns true iff ``unsigned(x) <= unsigned(y)``. ## Returns true iff ``unsigned(x) <= unsigned(y)``.
proc `<%` *(x, y: int): bool {.magic: "LtU", noSideEffect.} proc `<` *(x, y: UIntMax32): bool {.magic: "LtU", noSideEffect.}
proc `<%` *(x, y: int8): bool {.magic: "LtU", noSideEffect.} proc `<` *(x, y: UInt64): bool {.magic: "LtU64", noSideEffect.}
proc `<%` *(x, y: int16): bool {.magic: "LtU", noSideEffect.} ## Returns true iff ``unsigned(x) < unsigned(y)``.
proc `<%` *(x, y: int32): bool {.magic: "LtU", noSideEffect.}
proc `<%` *(x, y: int64): bool {.magic: "LtU64", noSideEffect.} proc `<%` *(x, y: IntMax32): bool {.magic: "LtU", noSideEffect.}
proc `<%` *(x, y: Int64): bool {.magic: "LtU64", noSideEffect.}
## treats `x` and `y` as unsigned and compares them. ## treats `x` and `y` as unsigned and compares them.
## Returns true iff ``unsigned(x) < unsigned(y)``. ## Returns true iff ``unsigned(x) < unsigned(y)``.
@ -935,6 +973,8 @@ type # these work for most platforms:
## This is the same as the type ``short`` in *C*. ## This is the same as the type ``short`` in *C*.
cint* {.importc: "int", nodecl.} = int32 cint* {.importc: "int", nodecl.} = int32
## This is the same as the type ``int`` in *C*. ## This is the same as the type ``int`` in *C*.
csize* {.importc: "size_t", nodecl.} = int
## This is the same as the type ``size_t`` in *C*.
clong* {.importc: "long", nodecl.} = int clong* {.importc: "long", nodecl.} = int
## This is the same as the type ``long`` in *C*. ## This is the same as the type ``long`` in *C*.
clonglong* {.importc: "long long", nodecl.} = int64 clonglong* {.importc: "long long", nodecl.} = int64

View file

@ -139,6 +139,10 @@ proc objectInit(dest: Pointer, typ: PNimType) =
# ---------------------- assign zero ----------------------------------------- # ---------------------- assign zero -----------------------------------------
proc nimDestroyRange*[T](r: T) =
# internal proc used for destroying sequences and arrays
for i in countup(0, r.len - 1): destroy(r[i])
proc genericReset(dest: Pointer, mt: PNimType) {.compilerProc.} proc genericReset(dest: Pointer, mt: PNimType) {.compilerProc.}
proc genericResetAux(dest: Pointer, n: ptr TNimNode) = proc genericResetAux(dest: Pointer, n: ptr TNimNode) =
var d = cast[TAddress](dest) var d = cast[TAddress](dest)

View file

@ -37,7 +37,9 @@ type # This should be he same as ast.TTypeKind
tyPointer, tyOpenArray, tyPointer, tyOpenArray,
tyString, tyCString, tyForward, tyString, tyCString, tyForward,
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
tyFloat, tyFloat32, tyFloat64, tyFloat128 tyFloat, tyFloat32, tyFloat64, tyFloat128,
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
tyBigNum,
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
TNimNode {.codegenType, final.} = object TNimNode {.codegenType, final.} = object

View file

@ -41,10 +41,6 @@ type # WinNT.h -- Defines the 32-Bit Windows types and constants
type # BaseTsd.h -- Type definitions for the basic sized types type # BaseTsd.h -- Type definitions for the basic sized types
# Give here only the bare minimum, to be expanded as needs arise # Give here only the bare minimum, to be expanded as needs arise
UINT8* = int8
UINT16* = int16
UINT32* = int32
UINT64* = int64
LONG32* = int32 LONG32* = int32
ULONG32* = int32 ULONG32* = int32
DWORD32* = int32 DWORD32* = int32
@ -95,7 +91,6 @@ type # WinDef.h -- Basic Windows Type Definitions
LPCVOID* = pointer LPCVOID* = pointer
# INT* = int # Cannot work and not necessary anyway # INT* = int # Cannot work and not necessary anyway
UINT* = int
PUINT* = ptr int PUINT* = ptr int
WPARAM* = LONG_PTR WPARAM* = LONG_PTR
@ -18518,9 +18513,9 @@ proc DisableThreadLibraryCalls*(hLibModule: HMODULE): WINBOOL{.stdcall,
proc GetProcAddress*(hModule: HINST, lpProcName: LPCSTR): FARPROC{.stdcall, proc GetProcAddress*(hModule: HINST, lpProcName: LPCSTR): FARPROC{.stdcall,
dynlib: "kernel32", importc: "GetProcAddress".} dynlib: "kernel32", importc: "GetProcAddress".}
proc GetVersion*(): DWORD{.stdcall, dynlib: "kernel32", importc: "GetVersion".} proc GetVersion*(): DWORD{.stdcall, dynlib: "kernel32", importc: "GetVersion".}
proc GlobalAlloc*(uFlags: UINT, dwBytes: DWORD): HGLOBAL{.stdcall, proc GlobalAlloc*(uFlags: INT, dwBytes: DWORD): HGLOBAL{.stdcall,
dynlib: "kernel32", importc: "GlobalAlloc".} dynlib: "kernel32", importc: "GlobalAlloc".}
proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: UINT): HGLOBAL{. proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: INT): HGLOBAL{.
stdcall, dynlib: "kernel32", importc: "GlobalReAlloc".} stdcall, dynlib: "kernel32", importc: "GlobalReAlloc".}
proc GlobalSize*(hMem: HGLOBAL): DWORD{.stdcall, dynlib: "kernel32", proc GlobalSize*(hMem: HGLOBAL): DWORD{.stdcall, dynlib: "kernel32",
importc: "GlobalSize".} importc: "GlobalSize".}
@ -23620,8 +23615,8 @@ proc ListView_SetItemPosition32(hwndLV: HWND, i, x, y: int32): LRESULT =
proc ListView_SetItemState(hwndLV: HWND, i, data, mask: int32): LRESULT = proc ListView_SetItemState(hwndLV: HWND, i, data, mask: int32): LRESULT =
var gnu_lvi: LV_ITEM var gnu_lvi: LV_ITEM
gnu_lvi.stateMask = mask gnu_lvi.stateMask = uint(mask)
gnu_lvi.state = data gnu_lvi.state = uint(data)
result = SendMessage(hwndLV, LVM_SETITEMSTATE, WPARAM(i), result = SendMessage(hwndLV, LVM_SETITEMSTATE, WPARAM(i),
cast[LPARAM](addr(gnu_lvi))) cast[LPARAM](addr(gnu_lvi)))

View file

@ -192,19 +192,44 @@ const
BIO_C_DO_STATE_MACHINE = 101 BIO_C_DO_STATE_MACHINE = 101
BIO_C_GET_SSL = 110 BIO_C_GET_SSL = 110
proc SSL_library_init*(): cInt{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_library_init*(): cInt{.cdecl, dynlib: DLLSSLName, importc, discardable.}
proc SSL_load_error_strings*(){.cdecl, dynlib: DLLSSLName, importc.} proc SSL_load_error_strings*(){.cdecl, dynlib: DLLSSLName, importc.}
proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLSSLName, importc.} proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLSSLName, importc.}
proc SSLv23_client_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} proc SSLv23_client_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
proc SSLv23_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
proc SSLv2_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
proc SSLv3_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
proc TLSv1_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_new*(context: PSSL_CTX): PSSL{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_free*(ssl: PSSL){.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_CTX_new*(meth: PSSL_METHOD): PSSL_CTX{.cdecl, proc SSL_CTX_new*(meth: PSSL_METHOD): PSSL_CTX{.cdecl,
dynlib: DLLSSLName, importc.} dynlib: DLLSSLName, importc.}
proc SSL_CTX_load_verify_locations*(ctx: PSSL_CTX, CAfile: cstring, proc SSL_CTX_load_verify_locations*(ctx: PSSL_CTX, CAfile: cstring,
CApath: cstring): cInt{.cdecl, dynlib: DLLSSLName, importc.} CApath: cstring): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_CTX_free*(arg0: PSSL_CTX){.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_CTX_set_verify*(s: PSSL_CTX, mode: int, cb: proc (a: int, b: pointer): int){.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_get_verify_result*(ssl: PSSL): int{.cdecl, proc SSL_get_verify_result*(ssl: PSSL): int{.cdecl,
dynlib: DLLSSLName, importc.} dynlib: DLLSSLName, importc.}
proc SSL_CTX_set_cipher_list*(s: PSSLCTX, ciphers: cstring): cint{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_CTX_use_certificate_file*(ctx: PSSL_CTX, filename: cstring, typ: cInt): cInt{.
cdecl, dynlib: DLLSSLName, importc.}
proc SSL_CTX_use_PrivateKey_file*(ctx: PSSL_CTX,
filename: cstring, typ: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_CTX_check_private_key*(ctx: PSSL_CTX): cInt{.cdecl, dynlib: DLLSSLName,
importc.}
proc SSL_set_fd*(ssl: PSSL, fd: cint): cint{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_shutdown*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_connect*(ssl: PSSL): cint{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_read*(ssl: PSSL, buf: pointer, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_write*(ssl: PSSL, buf: cstring, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_get_error*(s: PSSL, ret_code: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SSL_accept*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc BIO_new_ssl_connect*(ctx: PSSL_CTX): PBIO{.cdecl, proc BIO_new_ssl_connect*(ctx: PSSL_CTX): PBIO{.cdecl,
dynlib: DLLSSLName, importc.} dynlib: DLLSSLName, importc.}
proc BIO_ctrl*(bio: PBIO, cmd: cint, larg: int, arg: cstring): int{.cdecl, proc BIO_ctrl*(bio: PBIO, cmd: cint, larg: int, arg: cstring): int{.cdecl,
@ -227,16 +252,27 @@ proc BIO_free*(b: PBIO): cInt{.cdecl, dynlib: DLLUtilName, importc.}
proc ERR_print_errors_fp*(fp: TFile){.cdecl, dynlib: DLLSSLName, importc.} proc ERR_print_errors_fp*(fp: TFile){.cdecl, dynlib: DLLSSLName, importc.}
proc ERR_error_string*(e: cInt, buf: cstring): cstring{.cdecl,
dynlib: DLLUtilName, importc.}
proc ERR_get_error*(): cInt{.cdecl, dynlib: DLLUtilName, importc.}
proc OpenSSL_add_all_algorithms*(){.cdecl, dynlib: DLLSSLName, importc: "OPENSSL_add_all_algorithms_conf".}
proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.}
proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, dynlib: DLLSSLName, importc.}
proc CRYPTO_malloc_init*() =
CRYPTO_set_mem_functions(alloc, realloc, dealloc)
when True: when True:
nil nil
else: else:
proc SslGetError*(s: PSSL, ret_code: cInt): cInt{.cdecl, dynlib: DLLSSLName,
importc.}
proc SslCtxSetCipherList*(arg0: PSSL_CTX, str: cstring): cInt{.cdecl, proc SslCtxSetCipherList*(arg0: PSSL_CTX, str: cstring): cInt{.cdecl,
dynlib: DLLSSLName, importc.} dynlib: DLLSSLName, importc.}
proc SslCtxNew*(meth: PSSL_METHOD): PSSL_CTX{.cdecl, proc SslCtxNew*(meth: PSSL_METHOD): PSSL_CTX{.cdecl,
dynlib: DLLSSLName, importc.} dynlib: DLLSSLName, importc.}
proc SslCtxFree*(arg0: PSSL_CTX){.cdecl, dynlib: DLLSSLName, importc.}
proc SslSetFd*(s: PSSL, fd: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.} proc SslSetFd*(s: PSSL, fd: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SslCtrl*(ssl: PSSL, cmd: cInt, larg: int, parg: Pointer): int{.cdecl, proc SslCtrl*(ssl: PSSL, cmd: cInt, larg: int, parg: Pointer): int{.cdecl,
dynlib: DLLSSLName, importc.} dynlib: DLLSSLName, importc.}
@ -255,19 +291,15 @@ else:
dynlib: DLLSSLName, importc.} dynlib: DLLSSLName, importc.}
proc SslCtxUsePrivateKeyASN1*(pk: cInt, ctx: PSSL_CTX, proc SslCtxUsePrivateKeyASN1*(pk: cInt, ctx: PSSL_CTX,
d: cstring, length: int): cInt{.cdecl, dynlib: DLLSSLName, importc.} d: cstring, length: int): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SslCtxUsePrivateKeyFile*(ctx: PSSL_CTX,
filename: cstring, typ: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SslCtxUseCertificate*(ctx: PSSL_CTX, x: SslPtr): cInt{.cdecl, proc SslCtxUseCertificate*(ctx: PSSL_CTX, x: SslPtr): cInt{.cdecl,
dynlib: DLLSSLName, importc.} dynlib: DLLSSLName, importc.}
proc SslCtxUseCertificateASN1*(ctx: PSSL_CTX, length: int, d: cstring): cInt{. proc SslCtxUseCertificateASN1*(ctx: PSSL_CTX, length: int, d: cstring): cInt{.
cdecl, dynlib: DLLSSLName, importc.} cdecl, dynlib: DLLSSLName, importc.}
proc SslCtxUseCertificateFile*(ctx: PSSL_CTX, filename: cstring, typ: cInt): cInt{.
cdecl, dynlib: DLLSSLName, importc.}
# function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const filename: PChar):cInt; # function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const filename: PChar):cInt;
proc SslCtxUseCertificateChainFile*(ctx: PSSL_CTX, filename: cstring): cInt{. proc SslCtxUseCertificateChainFile*(ctx: PSSL_CTX, filename: cstring): cInt{.
cdecl, dynlib: DLLSSLName, importc.} cdecl, dynlib: DLLSSLName, importc.}
proc SslCtxCheckPrivateKeyFile*(ctx: PSSL_CTX): cInt{.cdecl, dynlib: DLLSSLName,
importc.}
proc SslCtxSetDefaultPasswdCb*(ctx: PSSL_CTX, cb: PPasswdCb){.cdecl, proc SslCtxSetDefaultPasswdCb*(ctx: PSSL_CTX, cb: PPasswdCb){.cdecl,
dynlib: DLLSSLName, importc.} dynlib: DLLSSLName, importc.}
proc SslCtxSetDefaultPasswdCbUserdata*(ctx: PSSL_CTX, u: SslPtr){.cdecl, proc SslCtxSetDefaultPasswdCbUserdata*(ctx: PSSL_CTX, u: SslPtr){.cdecl,
@ -276,10 +308,10 @@ else:
proc SslCtxLoadVerifyLocations*(ctx: PSSL_CTX, CAfile: cstring, CApath: cstring): cInt{. proc SslCtxLoadVerifyLocations*(ctx: PSSL_CTX, CAfile: cstring, CApath: cstring): cInt{.
cdecl, dynlib: DLLSSLName, importc.} cdecl, dynlib: DLLSSLName, importc.}
proc SslNew*(ctx: PSSL_CTX): PSSL{.cdecl, dynlib: DLLSSLName, importc.} proc SslNew*(ctx: PSSL_CTX): PSSL{.cdecl, dynlib: DLLSSLName, importc.}
proc SslFree*(ssl: PSSL){.cdecl, dynlib: DLLSSLName, importc.}
proc SslAccept*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SslConnect*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.} proc SslConnect*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SslShutdown*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SslRead*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl, proc SslRead*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl,
dynlib: DLLSSLName, importc.} dynlib: DLLSSLName, importc.}
proc SslPeek*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl, proc SslPeek*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl,
@ -339,9 +371,7 @@ else:
proc EVPcleanup*(){.cdecl, dynlib: DLLUtilName, importc.} proc EVPcleanup*(){.cdecl, dynlib: DLLUtilName, importc.}
# function ErrErrorString(e: cInt; buf: PChar): PChar; # function ErrErrorString(e: cInt; buf: PChar): PChar;
proc SSLeayversion*(t: cInt): cstring{.cdecl, dynlib: DLLUtilName, importc.} proc SSLeayversion*(t: cInt): cstring{.cdecl, dynlib: DLLUtilName, importc.}
proc ErrErrorString*(e: cInt, buf: cstring, length: cInt){.cdecl,
dynlib: DLLUtilName, importc.}
proc ErrGetError*(): cInt{.cdecl, dynlib: DLLUtilName, importc.}
proc ErrClearError*(){.cdecl, dynlib: DLLUtilName, importc.} proc ErrClearError*(){.cdecl, dynlib: DLLUtilName, importc.}
proc ErrFreeStrings*(){.cdecl, dynlib: DLLUtilName, importc.} proc ErrFreeStrings*(){.cdecl, dynlib: DLLUtilName, importc.}
proc ErrRemoveState*(pid: cInt){.cdecl, dynlib: DLLUtilName, importc.} proc ErrRemoveState*(pid: cInt){.cdecl, dynlib: DLLUtilName, importc.}

View file

@ -756,9 +756,7 @@ type
PUInt8Array* = ptr TUInt8Array PUInt8Array* = ptr TUInt8Array
TUInt8Array* = array[0..high(int) shr 1, byte] TUInt8Array* = array[0..high(int) shr 1, byte]
PUInt16* = ptr UInt16 PUInt16* = ptr UInt16
UInt16* = int16 PUInt32* = ptr UInt32
PUInt32* = ptr int32
UInt32* = int32
PUInt64* = ptr UInt64 PUInt64* = ptr UInt64
UInt64*{.final.} = object UInt64*{.final.} = object
hi*: int32 hi*: int32

View file

@ -1,6 +1,6 @@
discard """ discard """
file: "system.nim" file: "system.nim"
line: 640 line: 678
errormsg: "type mismatch" errormsg: "type mismatch"
""" """

66
tests/run/texceptions.nim Normal file
View file

@ -0,0 +1,66 @@
discard """
output: '''
BEFORE
FINALLY
BEFORE
EXCEPT
FINALLY
RECOVER
BEFORE
EXCEPT
FINALLY
'''
"""
echo ""
proc no_expcetion =
try:
echo "BEFORE"
except:
echo "EXCEPT"
raise
finally:
echo "FINALLY"
try: no_expcetion()
except: echo "RECOVER"
echo ""
proc reraise_in_except =
try:
echo "BEFORE"
raise newException(EIO, "")
except EIO:
echo "EXCEPT"
raise
finally:
echo "FINALLY"
try: reraise_in_except()
except: echo "RECOVER"
echo ""
proc return_in_except =
try:
echo "BEFORE"
raise newException(EIO, "")
except:
echo "EXCEPT"
return
finally:
echo "FINALLY"
try: return_in_except()
except: echo "RECOVER"

View file

@ -391,7 +391,7 @@ proc srcdist(c: var TConfigData) =
if existsDir(dir): removeDir(dir) if existsDir(dir): removeDir(dir)
createDir(dir) createDir(dir)
var cmd = ("nimrod compile -f --symbolfiles:off --compileonly " & var cmd = ("nimrod compile -f --symbolfiles:off --compileonly " &
"--gen_mapping --cc:gcc" & "--gen_mapping --cc:gcc --skipUserCfg" &
" --os:$# --cpu:$# $# $#") % " --os:$# --cpu:$# $# $#") %
[c.oses[osA-1], c.cpus[cpuA-1], c.nimrodArgs, [c.oses[osA-1], c.cpus[cpuA-1], c.nimrodArgs,
changeFileExt(c.infile, "nim")] changeFileExt(c.infile, "nim")]

View file

@ -51,7 +51,11 @@ Library Additions
- Added ``system.||`` for parallel for loop support. - Added ``system.||`` for parallel for loop support.
- The GC supports (soft) realtime systems via ``GC_setMaxPause`` - The GC supports (soft) realtime systems via ``GC_setMaxPause``
and ``GC_step`` procs. and ``GC_step`` procs.
- The sockets module now supports ssl through the OpenSSL library, ``recvLine``
is now much more efficient thanks to the newly implemented sockets buffering.
- The httpclient module now supports ssl/tls.
- Added ``times.format`` as well as many other utility functions
for managing time.
Changes affecting backwards compatibility Changes affecting backwards compatibility
----------------------------------------- -----------------------------------------
@ -77,7 +81,7 @@ Changes affecting backwards compatibility
- RTTI and thus the ``marshall`` module don't contain the proper field names - RTTI and thus the ``marshall`` module don't contain the proper field names
of tuples anymore. This had to be changed as the old behaviour never of tuples anymore. This had to be changed as the old behaviour never
produced consistent results. produced consistent results.
- Deprecated the ``ssl`` module.
Compiler Additions Compiler Additions
------------------ ------------------