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

This commit is contained in:
Araq
2012-06-19 22:38:48 +02:00
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
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
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
%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
%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
@@ -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
%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
%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\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

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
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
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
%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
%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
@@ -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
%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
%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\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

View File

@@ -52,9 +52,15 @@ type
nkInt16Lit,
nkInt32Lit,
nkInt64Lit,
nkUIntLit, # an unsigned integer literal
nkUInt8Lit,
nkUInt16Lit,
nkUInt32Lit,
nkUInt64Lit,
nkFloatLit, # a floating point literal
nkFloat32Lit,
nkFloat64Lit,
nkFloat128Lit,
nkStrLit, # a string literal ""
nkRStrLit, # a raw string literal r""
nkTripleStrLit, # a triple string literal """
@@ -237,6 +243,7 @@ type
sfNamedParamCall, # symbol needs named parameter call syntax in target
# language; for interfacing with Objective C
sfDiscardable # returned value may be discarded implicitely
sfDestructor # proc is destructor
TSymFlags* = set[TSymFlag]
@@ -325,6 +332,8 @@ type
tfEnumHasHoles, # enum cannot be mapped into a range
tfShallow, # type can be shallow copied on assignment
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
# because for instantiations of objects, structural
# type equality has to be used
@@ -408,8 +417,11 @@ type
mNewString, mNewStringOfCap,
mReset,
mArray, mOpenArray, mRange, mSet, mSeq,
mOrdinal, mInt, mInt8, mInt16, mInt32,
mInt64, mFloat, mFloat32, mFloat64, mBool, mChar, mString, mCstring,
mOrdinal,
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,
mVoidType, mPNimrodNode,
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
@@ -464,11 +476,11 @@ type
info*: TLineInfo
flags*: TNodeFlags
case Kind*: TNodeKind
of nkCharLit..nkInt64Lit:
of nkCharLit..nkUInt64Lit:
intVal*: biggestInt
of nkFloatLit..nkFloat64Lit:
of nkFloatLit..nkFloat128Lit:
floatVal*: biggestFloat
of nkStrLit..nkTripleStrLit:
of nkStrLit..nkTripleStrLit:
strVal*: string
of nkSym:
sym*: PSym
@@ -765,8 +777,8 @@ const # for all kind of hash tables:
proc ValueToString*(a: PNode): string =
case a.kind
of nkCharLit..nkInt64Lit: result = $(a.intVal)
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result = $(a.floatVal)
of nkCharLit..nkUInt64Lit: result = $(a.intVal)
of nkFloatLit..nkFloat128Lit: result = $(a.floatVal)
of nkStrLit..nkTripleStrLit: result = a.strVal
else:
InternalError(a.info, "valueToString")
@@ -888,6 +900,7 @@ proc assignType(dest, src: PType) =
dest.size = src.size
dest.align = src.align
dest.containerID = src.containerID
dest.destructor = src.destructor
# this fixes 'type TLock = TSysLock':
if src.sym != nil:
if dest.sym != nil:
@@ -1020,8 +1033,8 @@ proc copyNode(src: PNode): PNode =
result.typ = src.typ
result.flags = src.flags * PersistentNodeFlags
case src.Kind
of nkCharLit..nkInt64Lit: result.intVal = src.intVal
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result.floatVal = src.floatVal
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym
of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
@@ -1035,8 +1048,8 @@ proc shallowCopy*(src: PNode): PNode =
result.typ = src.typ
result.flags = src.flags * PersistentNodeFlags
case src.Kind
of nkCharLit..nkInt64Lit: result.intVal = src.intVal
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result.floatVal = src.floatVal
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym
of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
@@ -1051,8 +1064,8 @@ proc copyTree(src: PNode): PNode =
result.typ = src.typ
result.flags = src.flags * PersistentNodeFlags
case src.Kind
of nkCharLit..nkInt64Lit: result.intVal = src.intVal
of nkFloatLit, nkFloat32Lit, nkFloat64Lit: result.floatVal = src.floatVal
of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
of nkSym: result.sym = src.sym
of nkIdent: result.ident = src.ident
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
@@ -1102,14 +1115,14 @@ proc sonsNotNil(n: PNode): bool =
proc getInt*(a: PNode): biggestInt =
case a.kind
of nkIntLit..nkInt64Lit: result = a.intVal
of nkIntLit..nkUInt64Lit: result = a.intVal
else:
internalError(a.info, "getInt")
result = 0
proc getFloat*(a: PNode): biggestFloat =
case a.kind
of nkFloatLit..nkFloat64Lit: result = a.floatVal
of nkFloatLit..nkFloat128Lit: result = a.floatVal
else:
internalError(a.info, "getFloat")
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)):
if n.data[i] != nil:
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)])
inc(mycount)
if mycount > 0: appf(result, "$n$1", [spaces(indent)])
if mycount > 0: appf(result, "$N$1", [spaces(indent)])
app(result, "]")
assert(mycount == n.counter)
@@ -288,9 +288,9 @@ proc ropeConstr(indent: int, c: openarray[PRope]): PRope =
var i = 0
while i <= high(c):
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)
appf(result, "$n$1}", [spaces(indent)])
appf(result, "$N$1}", [spaces(indent)])
proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
maxRecDepth: int): PRope =
@@ -325,9 +325,9 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
result = toRope("[")
for i in countup(0, sonsLen(n) - 1):
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)])
appf(result, "$n$1]", [spaces(indent + 2)])
appf(result, "$N$1]", [spaces(indent + 2)])
else:
result = toRope("null")
result = ropeConstr(indent, [toRope("kind"),
@@ -347,36 +347,36 @@ proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
result = toRope("null")
else:
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:
appf(result, ",$n$1\"info\": $2", [istr, lineInfoToStr(n.info)])
appf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
case n.kind
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:
appf(result, ",$n$1\"floatVal\": $2",
appf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.ToStrMaxPrecision)])
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:
appf(result, ",$n$1\"sym\": $2",
appf(result, ",$N$1\"sym\": $2",
[istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
of nkIdent:
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:
appf(result, ",$n$1\"ident\": null", [istr])
appf(result, ",$N$1\"ident\": null", [istr])
else:
if sonsLen(n) > 0:
appf(result, ",$n$1\"sons\": [", [istr])
appf(result, ",$N$1\"sons\": [", [istr])
for i in countup(0, sonsLen(n) - 1):
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)])
appf(result, "$n$1]", [istr])
appf(result, ",$n$1\"typ\": $2",
appf(result, "$N$1]", [istr])
appf(result, ",$N$1\"typ\": $2",
[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 =
var marker = InitIntSet()
@@ -413,34 +413,34 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope =
result = toRope("null")
else:
var istr = spaces(indent + 2)
result = ropef("{$n$1\"kind\": $2",
result = ropef("{$N$1\"kind\": $2",
[istr, makeYamlString($n.kind)])
if maxRecDepth != 0:
case n.kind
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:
appf(result, ",$n$1\"floatVal\": $2",
appf(result, ",$N$1\"floatVal\": $2",
[istr, toRope(n.floatVal.ToStrMaxPrecision)])
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:
appf(result, ",$n$1\"sym\": $2_$3",
appf(result, ",$N$1\"sym\": $2_$3",
[istr, toRope(n.sym.name.s), toRope(n.sym.id)])
of nkIdent:
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:
appf(result, ",$n$1\"ident\": null", [istr])
appf(result, ",$N$1\"ident\": null", [istr])
else:
if sonsLen(n) > 0:
appf(result, ",$n$1\"sons\": [", [istr])
appf(result, ",$N$1\"sons\": [", [istr])
for i in countup(0, sonsLen(n) - 1):
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)])
appf(result, "$n$1]", [istr])
appf(result, "$n$1}", [spaces(indent)])
appf(result, "$N$1]", [istr])
appf(result, "$N$1}", [spaces(indent)])
proc debug(n: PSym) =
#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:
resetLoc(p, d)
app(pl, addrLoc(d))
app(pl, ")")
app(p.s(cpsStmts), pl)
appf(p.s(cpsStmts), ";$n")
appf(pl, ");$n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc
getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp))
app(pl, ")")
app(p.s(cpsStmts), pl)
appf(p.s(cpsStmts), ";$n")
appf(pl, ");$n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
app(pl, ")")
@@ -53,9 +51,8 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, pl: PRope) =
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
app(pl, ")")
app(p.s(cpsStmts), pl)
appf(p.s(cpsStmts), ";$n")
appf(pl, ");$n")
line(p, cpsStmts, pl)
proc isInCurrentFrame(p: BProc, n: PNode): bool =
# 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 =
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
initLocExpr(p, ri.sons[0], op)
var pl: PRope
@@ -166,7 +163,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if i < length - 1: app(pl, ", ")
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)
if typ.sons[0] != nil:
@@ -181,13 +178,11 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
resetLoc(p, d)
app(pl, addrLoc(d))
genCallPattern()
appf(p.s(cpsStmts), ";$n")
else:
var tmp: TLoc
getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp))
app(pl, addrLoc(tmp))
genCallPattern()
appf(p.s(cpsStmts), ";$n")
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
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
else:
genCallPattern()
appf(p.s(cpsStmts), ";$n")
proc genInfixCall(p: BProc, le, ri: PNode, d: var 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)
app(pl, "Result: ")
app(pl, addrLoc(d))
app(pl, "]")
app(p.s(cpsStmts), pl)
appf(p.s(cpsStmts), ";$n")
appf(pl, "];$n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc
getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp))
app(pl, "]")
app(p.s(cpsStmts), pl)
appf(p.s(cpsStmts), ";$n")
appf(pl, "];$n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
app(pl, "]")
@@ -284,9 +276,8 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
app(pl, "]")
app(p.s(cpsStmts), pl)
appf(p.s(cpsStmts), ";$n")
appf(pl, "];$n")
line(p, cpsStmts, pl)
proc genCall(p: BProc, e: PNode, d: var TLoc) =
if e.sons[0].typ.callConv == ccClosure:

View File

@@ -34,7 +34,7 @@ proc int32Literal(i: Int): PRope =
proc genHexLiteral(v: PNode): PRope =
# hex literals are unsigned in C
# 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")
result = intLiteral(v.intVal)
@@ -47,7 +47,7 @@ proc getStrLit(m: BModule, s: string): PRope =
proc genLiteral(p: BProc, v: PNode, ty: PType): PRope =
if ty == nil: internalError(v.info, "genLiteral: ty is nil")
case v.kind
of nkCharLit..nkInt64Lit:
of nkCharLit..nkUInt64Lit:
case skipTypes(ty, abstractVarRange).kind
of tyChar, tyInt64, tyNil:
result = intLiteral(v.intVal)
@@ -160,7 +160,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
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)
elif dest.s == OnHeap:
# location is on heap
@@ -168,25 +168,25 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
#
# if afSrcIsNotNil in flags:
# 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:
# 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:
# 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:
# UseMagic(p.module, 'nimGCunref')
# appf(p.s[cpsStmts], 'if ($1) nimGCunref($1);$n', [rdLoc(dest)])
# appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
# lineF(p, cpsStmts, 'if ($1) nimGCunref($1);$n', [rdLoc(dest)])
# lineF(p, cpsStmts, '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
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)])
else:
appcg(p.module, p.s(cpsStmts), "#asgnRefNoCycle((void**) $1, $2);$n",
lineCg(p, cpsStmts, "#asgnRefNoCycle((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)])
else:
appcg(p.module, p.s(cpsStmts), "#unsureAsgnRef((void**) $1, $2);$n",
lineCg(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)])
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
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
if dest.s == OnStack or optRefcGC notin gGlobalOptions:
appcg(p, cpsStmts,
lineCg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
[addrLoc(dest), addrLoc(src), rdLoc(dest)])
if needToKeepAlive in flags: keepAlive(p, dest)
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)])
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)])
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.
if src.t != nil and src.t.kind == tyPtr:
# 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
var ty = skipTypes(dest.t, abstractVarRange)
case ty.kind
@@ -226,24 +226,24 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if needToCopy notin flags:
genRefAssign(p, dest, src, flags)
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)])
of tyString:
if needToCopy notin flags:
genRefAssign(p, dest, src, flags)
else:
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)
elif dest.s == OnHeap:
# we use a temporary to care for the dreaded self assignment:
var tmp: TLoc
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])
appcg(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", tmp.rdLoc)
lineCg(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", tmp.rdLoc)
else:
appcg(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
lineCg(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
[addrLoc(dest), rdLoc(src)])
if needToKeepAlive in flags: keepAlive(p, dest)
of tyTuple, tyObject, tyProc:
@@ -251,34 +251,34 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if needsComplexAssignment(dest.t):
genGenericAsgn(p, dest, src, flags)
else:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
lineCg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyArray, tyArrayConstr:
if needsComplexAssignment(dest.t):
genGenericAsgn(p, dest, src, flags)
else:
appcg(p, cpsStmts,
lineCg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
[rdLoc(dest), rdLoc(src)])
of tyOpenArray:
# open arrays are always on the stack - really? What if a sequence is
# passed to an open array?
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",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
else:
appcg(p, cpsStmts,
lineCg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len0);$n",
[rdLoc(dest), rdLoc(src)])
of tySet:
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))])
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,
tyInt..tyFloat128, tyRange:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
tyInt..tyUInt64, tyRange:
lineCg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
else: InternalError("genAssignment(" & $ty.kind & ')')
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")
InitLocExpr(p, e.sons[1], d)
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) =
var a: TLoc
if (d.k != locNone): InternalError(e.info, "unaryStmt")
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) =
var a, b: TLoc
if (d.k != locNone): InternalError(e.info, "binaryStmtChar")
InitLocExpr(p, e.sons[1], a)
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) =
var a, b: TLoc
@@ -382,11 +382,11 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
else:
storage = getTypeDesc(p.module, t)
var tmp = getTempName()
appcg(p, cpsLocals, "$1 $2;$n", [storage, tmp])
appcg(p, cpsStmts, "$1 = #$2($3, $4);$n", [tmp, toRope(prc[m]),
lineCg(p, cpsLocals, "$1 $2;$n", [storage, tmp])
lineCg(p, cpsStmts, "$1 = #$2($3, $4);$n", [tmp, toRope(prc[m]),
rdLoc(a), rdLoc(b)])
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))])
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)
t = skipTypes(e.typ, abstractRange)
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))])
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 r = rdLoc(a)
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")
when false:
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)
else: strLit = con("TMP", toRope(id))
if op.magic == mNot:
appcg(p, cpsStmts,
lineCg(p, cpsStmts,
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
[rdLoc(test), strLit])
else:
appcg(p, cpsStmts,
lineCg(p, cpsStmts,
"if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
[rdLoc(test), strLit])
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
if firstOrd(ty) == 0:
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))])
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))])
if d.k == locNone: d.s = a.s
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[1], b) # emit range check:
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 ``>``!
if d.k == locNone: d.s = a.s
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:
if optBoundsCheck in p.options:
if ty.kind == tyString:
appcg(p, cpsStmts,
lineCg(p, cpsStmts,
"if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
[rdLoc(b), rdLoc(a), lenField()])
else:
appcg(p, cpsStmts,
lineCg(p, cpsStmts,
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
[rdLoc(b), rdLoc(a), lenField()])
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)
L = getLabel(p)
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:
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)
fixLabel(p, L)
if d.k == locNone:
@@ -772,9 +772,9 @@ proc genIfExpr(p: BProc, n: PNode, d: var TLoc) =
of nkElifExpr:
initLocExpr(p, it.sons[0], a)
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)
appf(p.s(cpsStmts), "goto $1;$n", [Lend])
lineF(p, cpsStmts, "goto $1;$n", [Lend])
fixLabel(p, Lelse)
of nkElseExpr:
expr(p, it.sons[0], tmp)
@@ -793,7 +793,7 @@ proc genEcho(p: BProc, n: PNode) =
for i in countup(1, n.len-1):
initLocExpr(p, n.sons[i], 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])
include ccgcalls
@@ -825,14 +825,14 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[i + 1], a)
if skipTypes(e.sons[i + 1].Typ, abstractVarRange).kind == tyChar:
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:
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
Inc(L, len(e.sons[i + 1].strVal))
else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
appcg(p.module, appends, "#appendString($1, $2);$n", [tmp.r, rdLoc(a)])
appcg(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, toRope(L)])
appLineCg(p, appends, "#appendString($1, $2);$n", [tmp.r, rdLoc(a)])
lineCg(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, toRope(L)])
app(p.s(cpsStmts), appends)
if d.k == locNone:
d = tmp
@@ -863,16 +863,16 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[i + 2], a)
if skipTypes(e.sons[i + 2].Typ, abstractVarRange).kind == tyChar:
Inc(L)
appcg(p.module, appends, "#appendChar($1, $2);$n",
appLineCg(p, appends, "#appendChar($1, $2);$n",
[rdLoc(dest), rdLoc(a)])
else:
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
Inc(L, len(e.sons[i + 2].strVal))
else:
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)])
appcg(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
lineCg(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
[rdLoc(dest), lens, toRope(L)])
keepAlive(p, dest)
app(p.s(cpsStmts), appends)
@@ -881,10 +881,15 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq &= x -->
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(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
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
appcg(p, cpsStmts, "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n", [
lineCg(p, cpsStmts, seqAppendPattern, [
rdLoc(a),
getTypeDesc(p.module, skipTypes(e.sons[1].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) =
var a: TLoc
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))])
proc genNew(p: BProc, e: PNode) =
@@ -912,11 +917,11 @@ proc genNew(p: BProc, e: PNode) =
if a.s == OnHeap and optRefcGc in gGlobalOptions:
# use newObjRC1 as an optimization; and we don't need 'keepAlive' either
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:
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)
appcg(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc)
lineCg(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc)
else:
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", args)
genAssignment(p, a, b, {needToKeepAlive}) # set the object type:
@@ -930,9 +935,9 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
var call: TLoc
initLoc(call, locExpr, dest.t, OnHeap)
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)
appcg(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
lineCg(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
else:
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
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[2], b)
var t = skipTypes(e.sons[1].typ, abstractVar)
appcg(p, cpsStmts,
"$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n", [
let setLenPattern = if gCmd != cmdCompileToCpp:
"$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),
getTypeDesc(p.module, t.sons[0])])
keepAlive(p, a)
@@ -1172,7 +1181,7 @@ proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
assert(d.k == locNone)
InitLocExpr(p, e.sons[1], a)
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) =
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[2], b)
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)])
of mEqSet:
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[2], b)
if d.k == locNone: getTemp(p, a.t, d)
appf(p.s(cpsStmts),
lineF(p, cpsStmts,
"for ($1 = 0; $1 < $2; $1++) $n" &
" $3[$1] = $4[$1] $6 $5[$1];$n", [
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)", [
toRope(opr[m]), rdLoc(a), rdLoc(b)]))
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:
appcg(p, cpsStmts, "#infCheck($1);$n", [rdLoc(d)])
lineCg(p, cpsStmts, "#infCheck($1);$n", [rdLoc(d)])
else:
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 getSize(e.typ) > 8:
# 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):
if e.sons[i].kind == nkRange:
getTemp(p, getSysType(tyInt), idx) # our counter
initLocExpr(p, e.sons[i].sons[0], a)
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),
rdSetElemLoc(a, e.typ), rdSetElemLoc(b, e.typ)])
else:
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)])
else:
# small set
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):
if e.sons[i].kind == nkRange:
getTemp(p, getSysType(tyInt), idx) # our counter
initLocExpr(p, e.sons[i].sons[0], a)
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", [
rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
rdSetElemLoc(b, e.typ)])
else:
initLocExpr(p, e.sons[i], a)
appf(p.s(cpsStmts),
lineF(p, cpsStmts,
"$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n",
[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[1], b)
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)
putLocIntoDest(p, d, tmp)
@@ -1579,10 +1588,10 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
app(r, ".Sup")
t = skipTypes(t.sons[0], abstractInst)
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)])
else:
appcg(p, cpsStmts, "#chckObj($1.m_type, $2);$n",
lineCg(p, cpsStmts, "#chckObj($1.m_type, $2);$n",
[r, genTypeInfo(p.module, dest)])
if n.sons[0].typ.kind != tyObject:
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)
putLocIntoDest(p, d, sym.loc)
else: InternalError(e.info, "expr(" & $sym.kind & "); unknown symbol")
of nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit, nkFloatLit..nkFloat64Lit,
nkNilLit, nkCharLit:
of nkStrLit..nkTripleStrLit, nkIntLit..nkUInt64Lit,
nkFloatLit..nkFloat128Lit, nkNilLit, nkCharLit:
putIntoDest(p, d, e.typ, genLiteral(p, e))
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
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",
args: openarray[PRope]): int {.discardable.} =
lineCg(p, cpsStmts, start, args)
inc(p.labels)
result = len(p.blocks)
setlen(p.blocks, result + 1)
p.blocks[result].id = p.labels
p.blocks[result].nestedTryStmts = p.nestedTryStmts.len
appcg(p, cpsLocals, start, args)
proc assignLabel(b: var TBlock): PRope {.inline.} =
b.label = con("LA", b.id.toRope)
@@ -70,7 +70,7 @@ proc endBlock(p: BProc, blockEnd: PRope) =
setlen(p.blocks, topBlock)
# this is done after the block is popped so $n is
# properly indented when pretty printing is enabled
app(p.s(cpsStmts), blockEnd)
line(p, cpsStmts, blockEnd)
var gBlockEndBracket = ropef("}$n")
@@ -184,12 +184,12 @@ proc genIfStmt(p: BProc, n: PNode) =
initLocExpr(p, it.sons[0], a)
Lelse = getLabel(p)
inc(p.labels)
appff(p.s(cpsStmts), "if (!$1) goto $2;$n",
"br i1 $1, label %LOC$3, label %$2$n" & "LOC$3: $n",
lineFF(p, cpsStmts, "if (!$1) goto $2;$n",
"br i1 $1, label %LOC$3, label %$2$n" & "LOC$3: $n",
[rdLoc(a), Lelse, toRope(p.labels)])
genSimpleBlock(p, it.sons[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)
of nkElse:
genSimpleBlock(p, it.sons[0])
@@ -205,23 +205,29 @@ proc blockLeaveActions(p: BProc, howMany: int) =
stack[i-1] = p.nestedTryStmts[L-i]
setLen(p.nestedTryStmts, L-howMany)
var alreadyPoppedCnt = p.inExceptBlock
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)
if finallyStmt.kind == nkFinally:
genStmts(p, finallyStmt.sons[0])
# push old elements again:
for i in countdown(howMany-1, 0):
p.nestedTryStmts.add(stack[i])
for i in countdown(p.popCurrExc-1, 0):
appcg(p, cpsStmts, "#popCurrentException();$n", [])
if gCmd != cmdCompileToCpp:
for i in countdown(p.inExceptBlock-1, 0):
lineCg(p, cpsStmts, "#popCurrentException();$n", [])
proc genReturnStmt(p: BProc, t: PNode) =
p.beforeRetNeeded = true
genLineDir(p, t)
if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
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) =
# 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)
if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
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])
endBlock(p)
@@ -273,7 +279,7 @@ proc genParForStmt(p: BProc, t: PNode) =
initLocExpr(p, call.sons[1], rangeA)
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)",
forLoopVar.loc.rdLoc,
rangeA.rdLoc, rangeB.rdLoc,
@@ -302,29 +308,35 @@ proc genBreakStmt(p: BProc, t: PNode) =
let label = assignLabel(p.blocks[idx])
blockLeaveActions(p, p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts)
genLineDir(p, t)
appf(p.s(cpsStmts), "goto $1;$n", [label])
lineF(p, cpsStmts, "goto $1;$n", [label])
proc getRaiseFrmt(p: BProc): string =
#if gCmd == cmdCompileToCpp:
# result = "throw #nimException($1, $2);$n"
#else:
result = "#raiseException((#E_Base*)$1, $2);$n"
if gCmd == cmdCompileToCpp:
result = "throw NimException($1, $2);$n"
else:
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:
var a: TLoc
InitLocExpr(p, t.sons[0], a)
var e = rdLoc(a)
var typ = skipTypes(t.sons[0].typ, abstractPtrs)
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:
genLineDir(p, t)
# reraise the last exception:
#if gCmd == cmdCompileToCpp:
# appcg(p, cpsStmts, "throw;$n")
#else:
appcg(p, cpsStmts, "#reraiseException();$n")
if gCmd == cmdCompileToCpp:
lineCg(p, cpsStmts, "throw;$n")
else:
lineCg(p, cpsStmts, "#reraiseException();$n")
proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
rangeFormat, eqFormat: TFormatStr, labl: TLabel) =
@@ -335,20 +347,20 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
if b.sons[i].kind == nkRange:
initLocExpr(p, b.sons[i].sons[0], x)
initLocExpr(p, b.sons[i].sons[1], y)
appcg(p, cpsStmts, rangeFormat,
lineCg(p, cpsStmts, rangeFormat,
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
else:
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 =
var Lend = getLabel(p)
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:
var length = sonsLen(t.sons[i])
genSimpleBlock(p, t.sons[i].sons[length - 1])
appf(p.s(cpsStmts), "goto $1;$n", [Lend])
lineF(p, cpsStmts, "goto $1;$n", [Lend])
else:
genSimpleBlock(p, t.sons[i].sons[0])
result = Lend
@@ -363,13 +375,13 @@ proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr,
genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
con("LA", toRope(p.labels)))
else:
appf(p.s(cpsStmts), "goto LA$1;$n", [toRope(p.labels)])
lineF(p, cpsStmts, "goto LA$1;$n", [toRope(p.labels)])
if until < t.len-1:
inc(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)
appf(p.s(cpsStmts), "LA$1: ;$n", [toRope(gotoTarget)])
lineF(p, cpsStmts, "LA$1: ;$n", [toRope(gotoTarget)])
else:
result = genCaseSecondPass(p, t, labId, until)
@@ -411,7 +423,7 @@ proc genStringCase(p: BProc, t: PNode) =
else:
# else statement: nothing to do yet
# 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)])
for j in countup(0, high(branches)):
when false:
@@ -421,11 +433,11 @@ proc genStringCase(p: BProc, t: PNode) =
if interior != brn:
echo "BUG! ", interior, "-", brn
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]])
appf(p.s(cpsStmts), "}$n") # else statement:
lineF(p, cpsStmts, "}$n") # else statement:
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
var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1)
fixLabel(p, Lend)
@@ -454,16 +466,16 @@ proc genCaseRange(p: BProc, branch: PNode) =
for j in 0 .. length-2:
if branch[j].kind == nkRange:
if hasSwitchRange in CC[ccompiler].props:
appf(p.s(cpsStmts), "case $1 ... $2:$n", [
lineF(p, cpsStmts, "case $1 ... $2:$n", [
genLiteral(p, branch[j][0]),
genLiteral(p, branch[j][1])])
else:
var v = copyNode(branch[j][0])
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)
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) =
# analyse 'case' statement:
@@ -479,7 +491,7 @@ proc genOrdinalCase(p: BProc, n: PNode) =
# generate switch part (might be empty):
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
for i in splitPoint+1 .. < n.len:
var branch = n[i]
@@ -488,13 +500,13 @@ proc genOrdinalCase(p: BProc, n: PNode) =
genSimpleBlock(p, branch.lastSon)
else:
# else part of case statement:
appf(p.s(cpsStmts), "default:$n")
lineF(p, cpsStmts, "default:$n")
genSimpleBlock(p, branch[0])
hasDefault = true
appf(p.s(cpsStmts), "break;$n")
lineF(p, cpsStmts, "break;$n")
if (hasAssume in CC[ccompiler].props) and not hasDefault:
appf(p.s(cpsStmts), "default: __assume(0);$n")
appf(p.s(cpsStmts), "}$n")
lineF(p, cpsStmts, "default: __assume(0);$n")
lineF(p, cpsStmts, "}$n")
if Lend != nil: fixLabel(p, Lend)
proc genCaseStmt(p: BProc, t: PNode) =
@@ -518,80 +530,86 @@ proc hasGeneralExceptSection(t: PNode): bool =
inc(i)
result = false
proc genTryStmtCpp(p: BProc, t: PNode) =
proc genTryStmtCpp(p: BProc, t: PNode) =
# code to generate:
#
# bool tmpRethrow = false;
# XXX: There should be a standard dispatch algorithm
# that's used both here and with multi-methods
#
# try
# {
# myDiv(4, 9);
# } catch (NimException& tmp) {
# tmpRethrow = true;
# switch (tmp.exc)
# {
# case DIVIDE_BY_ZERO:
# tmpRethrow = false;
# printf("Division by Zero\n");
# break;
# default: // used for general except!
# generalExceptPart();
# tmpRethrow = false;
# } catch (NimException& exp) {
# if (isObj(exp, EIO) {
# ...
# } else if (isObj(exp, ESystem) {
# ...
# finallyPart()
# raise;
# } else {
# // general handler
# }
# }
# excHandler = excHandler->prev; // we handled the exception
# finallyPart();
# if (tmpRethrow) throw;
#
# XXX: push blocks
var
rethrowFlag: PRope
var
exc: PRope
i, length, blen: int
genLineDir(p, t)
rethrowFlag = nil
exc = getTempName()
if not hasGeneralExceptSection(t):
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")
discard cgsym(p.module, "E_Base")
add(p.nestedTryStmts, t)
startBlock(p, "try {$n")
genStmts(p, t.sons[0])
length = sonsLen(t)
if t.sons[1].kind == nkExceptBranch:
appf(p.s(cpsStmts), "} catch (NimException& $1) {$n", [exc])
if rethrowFlag != nil:
appf(p.s(cpsStmts), "$1 = NIM_TRUE;$n", [rethrowFlag])
appf(p.s(cpsStmts), "if ($1.sp.exc) {$n", [exc])
endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
if optStackTrace in p.Options:
lineCg(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
inc p.inExceptBlock
i = 1
while (i < length) and (t.sons[i].kind == nkExceptBranch):
var catchAllPresent = false
while (i < length) and (t.sons[i].kind == nkExceptBranch):
blen = sonsLen(t.sons[i])
if blen == 1:
if i > 1: appf(p.s(cpsStmts), "else ")
if blen == 1:
# general except section:
appf(p.s(cpsStmts), "default:$n")
genStmts(p, t.sons[i].sons[0])
else:
for j in countup(0, blen - 2):
catchAllPresent = true
genSimpleBlock(p, t.sons[i].sons[0])
else:
var orExpr: PRope = nil
for j in countup(0, blen - 2):
assert(t.sons[i].sons[j].kind == nkType)
appf(p.s(cpsStmts), "case $1:$n", [toRope(t.sons[i].sons[j].typ.id)])
genStmts(p, t.sons[i].sons[blen - 1])
if rethrowFlag != nil:
appf(p.s(cpsStmts), "$1 = NIM_FALSE; ", [rethrowFlag])
appf(p.s(cpsStmts), "break;$n")
if orExpr != nil: app(orExpr, "||")
appcg(p.module, orExpr,
"#isObj($1.exp->m_type, $2)",
[exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
lineF(p, cpsStmts, "if ($1) ", [orExpr])
genSimpleBlock(p, t.sons[i].sons[blen-1])
inc(i)
if t.sons[1].kind == nkExceptBranch:
appf(p.s(cpsStmts), "}}$n") # end of catch-switch statement
appcg(p, cpsStmts, "#popSafePoint();")
# reraise the exception if there was no catch all
# 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)
if (i < length) and (t.sons[i].kind == nkFinally):
genStmts(p, t.sons[i].sons[0])
if rethrowFlag != nil:
appf(p.s(cpsStmts), "if ($1) { throw; }$n", [rethrowFlag])
if (i < length) and (t.sons[i].kind == nkFinally):
genSimpleBlock(p, t.sons[i].sons[0])
proc genTryStmt(p: BProc, t: PNode) =
# code to generate:
#
# XXX: There should be a standard dispatch algorithm
# that's used both here and with multi-methods
#
# TSafePoint sp;
# pushSafePoint(&sp);
# sp.status = setjmp(sp.context);
@@ -618,50 +636,52 @@ proc genTryStmt(p: BProc, t: PNode) =
genLineDir(p, t)
var safePoint = getTempName()
discard cgsym(p.module, "E_Base")
appcg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
appcg(p, cpsStmts, "#pushSafePoint(&$1);$n" &
"$1.status = setjmp($1.context);$n", [safePoint])
if optStackTrace in p.Options:
appcg(p, cpsStmts, "#setFrame((TFrame*)&F);$n")
lineCg(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
lineCg(p, cpsStmts, "#pushSafePoint(&$1);$n", [safePoint])
lineF(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
startBlock(p, "if ($1.status == 0) {$n", [safePoint])
var length = sonsLen(t)
add(p.nestedTryStmts, t)
genStmts(p, t.sons[0])
endBlock(p, ropecg(p.module, "#popSafePoint();$n } else {$n#popSafePoint();$n"))
discard pop(p.nestedTryStmts)
linecg(p, cpsStmts, "#popSafePoint();$n")
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
while (i < length) and (t.sons[i].kind == nkExceptBranch):
while (i < length) and (t.sons[i].kind == nkExceptBranch):
var blen = sonsLen(t.sons[i])
if blen == 1:
if blen == 1:
# general except section:
if i > 1: appf(p.s(cpsStmts), "else")
if i > 1: lineF(p, cpsStmts, "else")
startBlock(p)
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
inc p.popCurrExc
lineCg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
genStmts(p, t.sons[i].sons[0])
dec p.popCurrExc
appcg(p, cpsStmts, "#popCurrentException();$n", [])
lineCg(p, cpsStmts, "#popCurrentException();$n")
endBlock(p)
else:
inc p.popCurrExc
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)
if orExpr != nil: app(orExpr, "||")
appcg(p.module, orExpr,
"#isObj(#getCurrentException()->Sup.m_type, $1)",
appcg(p.module, orExpr,
"#isObj(#getCurrentException()->Sup.m_type, $1)",
[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])
appcg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
lineCg(p, cpsStmts, "$1.status = 0;$n", [safePoint])
genStmts(p, t.sons[i].sons[blen-1])
dec p.popCurrExc
endBlock(p, ropecg(p.module, "#popCurrentException();}$n"))
lineCg(p, cpsStmts, "#popCurrentException();$n")
endBlock(p)
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:
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 =
for i in countup(0, sonsLen(t) - 1):
@@ -688,7 +708,7 @@ proc genAsmStmt(p: BProc, t: PNode) =
assert(t.kind == nkAsmStmt)
genLineDir(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) =
genLineDir(p, t)
@@ -697,7 +717,7 @@ proc genEmit(p: BProc, t: PNode) =
# top level emit pragma?
app(p.module.s[cfsProcHeaders], s)
else:
app(p.s(cpsStmts), s)
line(p, cpsStmts, s)
var
breakPointId: int = 0
@@ -723,7 +743,7 @@ proc genWatchpoint(p: BProc, n: PNode) =
var a: TLoc
initLocExpr(p, n.sons[1], a)
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])),
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):
appcg(p.module, cfsVars, "extern $1",
discriminatorTableDecl(p.module, t, field))
appcg(p, cpsStmts,
lineCg(p, cpsStmts,
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
intLiteral(L+1)])
@@ -820,9 +840,8 @@ proc genStmts(p: BProc, t: PNode) =
initLocExpr(p, t.sons[0], a)
of nkAsmStmt: genAsmStmt(p, t)
of nkTryStmt:
#if gCmd == cmdCompileToCpp: genTryStmtCpp(p, t)
#else:
genTryStmt(p, t)
if gCmd == cmdCompileToCpp: genTryStmtCpp(p, t)
else: genTryStmt(p, t)
of nkRaiseStmt: genRaiseStmt(p, t)
of nkTypeSection:
# we have to emit the type information for object types here to support

View File

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

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")
var p = c.p
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):
let branch = n.sons[i]
assert branch.kind in {nkOfBranch, nkElse}
if branch.kind == nkOfBranch:
genCaseRange(c.p, branch)
else:
p.s(cpsStmts).appf("default:$n")
lineF(p, cpsStmts, "default:$n")
genTraverseProc(c, accessor, lastSon(branch))
p.s(cpsStmts).appf("break;$n")
p.s(cpsStmts).appf("} $n")
lineF(p, cpsStmts, "break;$n")
lineF(p, cpsStmts, "} $n")
of nkSym:
let field = n.sym
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])
var i: TLoc
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)
genTraverseProc(c, ropef("$1[$2]", accessor, i.r), typ.sons[1])
appf(p.s(cpsStmts), "}$n")
lineF(p, cpsStmts, "}$n")
of tyObject:
for i in countup(0, sonsLen(typ) - 1):
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):
genTraverseProc(c, ropef("$1.Field$2", accessor, i.toRope), typ.sons[i])
of tyRef, tyString, tySequence:
appcg(p, cpsStmts, c.visitorFrmt, accessor)
lineCg(p, cpsStmts, c.visitorFrmt, accessor)
else:
# no marker procs for closures yet
nil
@@ -89,10 +89,10 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
assert typ.kind == tySequence
var i: TLoc
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"))
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 =
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 t = getTypeDesc(m, typ)
p.s(cpsLocals).appf("$1 a;$n", t)
p.s(cpsInit).appf("a = ($1)p;$n", t)
lineF(p, cpsLocals, "$1 a;$n", t)
lineF(p, cpsInit, "a = ($1)p;$n", t)
c.p = p
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 tyString: result = ctNimStr
of tyCString: result = ctCString
of tyInt..tyFloat128:
of tyInt..tyUInt64:
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
else: InternalError("mapType")
@@ -313,8 +313,10 @@ proc typeNameOrLiteral(t: PType, literal: string): PRope =
proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
const
NumericalTypeToStr: array[tyInt..tyFloat128, string] = ["NI", "NI8",
"NI16", "NI32", "NI64", "NF", "NF32", "NF64", "NF128"]
NumericalTypeToStr: array[tyInt..tyUInt64, string] = [
"NI", "NI8", "NI16", "NI32", "NI64",
"NF", "NF32", "NF64", "NF128",
"NU", "NU8", "NU16", "NU32", "NU64",]
case typ.Kind
of tyPointer:
result = typeNameOrLiteral(typ, "void*")
@@ -337,7 +339,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL")
of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR")
of tyNil: result = typeNameOrLiteral(typ, "0")
of tyInt..tyFloat128, tyUInt..tyUInt64:
of tyInt..tyUInt64:
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.Kind])
of tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
else: result = nil
@@ -871,7 +873,7 @@ proc genTypeInfo(m: BModule, typ: PType): PRope =
if dataGenerated: return
case t.kind
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")
of tyProc:
if t.callConv != ccClosure:

View File

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

View File

@@ -153,6 +153,34 @@ proc appcg(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: openarray[PRope]) =
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 =
result = toLinenumber(info)
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)
if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
(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 ==
{optLineTrace, optStackTrace}) and
(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)])
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):
app(r, ".Sup")
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:
# worst case for performance:
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
TAssignmentFlag = enum
@@ -238,16 +266,16 @@ proc resetLoc(p: BProc, loc: var TLoc) =
nilLoc.r = toRope("NIM_NIL")
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else:
appf(p.s(cpsStmts), "$1 = 0;$n", [rdLoc(loc)])
lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(loc)])
else:
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)])
# XXX: generated reset procs should not touch the m_type
# field, so disabling this should be safe:
genObjectInit(p, cpsStmts, loc.t, loc, true)
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)])
# XXX: We can be extra clever here and call memset only
# 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) =
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:
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)])
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))
else:
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.a = - 1
result.t = getUniqueType(t)
@@ -311,9 +339,9 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
result.flags = {}
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:
appcg(p, cpsStmts,
lineCg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
[addrLoc(result), addrLoc(toKeepAlive), rdLoc(result)])
@@ -355,7 +383,7 @@ proc allocParam(p: BProc, s: PSym) =
var tmp = con("%LOC", toRope(p.labels))
incl(s.loc.flags, lfParamCopy)
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)])
s.loc.r = tmp
@@ -365,7 +393,7 @@ proc localDebugInfo(p: BProc, s: PSym) =
if skipTypes(s.typ, abstractVar).kind == tyOpenArray: return
var a = con("&", 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",
[toRope(p.frameLen), makeCString(normalize(s.name.s)), a,
genTypeInfo(p.module, s.loc.t)])
@@ -378,13 +406,14 @@ proc assignLocalVar(p: BProc, s: PSym) =
if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
app(p.s(cpsLocals), getTypeDesc(p.module, s.loc.t))
if sfRegister in s.flags: app(p.s(cpsLocals), " register")
var decl = getTypeDesc(p.module, s.loc.t)
if sfRegister in s.flags: app(decl, " register")
#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):
app(p.s(cpsLocals), " volatile")
appf(p.s(cpsLocals), " $1;$n", [s.loc.r])
app(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r])
line(p, cpsLocals, decl)
localDebugInfo(p, s)
include ccgthreadvars
@@ -427,7 +456,7 @@ proc getLabel(p: BProc): TLabel =
result = con("LA", toRope(p.labels))
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 requestConstImpl(p: BProc, sym: PSym)
@@ -545,28 +574,28 @@ proc getFrameDecl(p: BProc) =
[toRope(p.frameLen)])
else:
slots = nil
appff(p.s(cpsLocals), "volatile struct {TFrame* prev;" &
"NCSTRING procname;NI line;NCSTRING filename;" &
"NI len;$n$1} F;$n",
lineFF(p, cpsLocals, "volatile struct {TFrame* prev;" &
"NCSTRING procname;NI line;NCSTRING filename;" &
"NI len;$1} F;$n",
"%TF = type {%TFrame*, i8*, %NI, %NI$1}$n" &
"%F = alloca %TF$n", [slots])
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" &
"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 =
result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
proc initFrame(p: BProc, procname, filename: PRope): PRope =
result = ropecg(p.module,
"F.procname = $1;$n" &
"F.filename = $2;$n" &
"F.line = 0;$n" &
"#pushFrame((TFrame*)&F);$n", [procname, filename])
"\tF.procname = $1;$n" &
"\tF.filename = $2;$n" &
"\tF.line = 0;$n" &
"\t#pushFrame((TFrame*)&F);$n", [procname, filename])
proc deinitFrame(p: BProc): PRope =
result = ropecg(p.module, "#popFrame();$n")
result = ropecg(p.module, "\t#popFrame();$n")
proc closureSetup(p: BProc, prc: PSym) =
if prc.typ.callConv != ccClosure: return
@@ -578,8 +607,8 @@ proc closureSetup(p: BProc, prc: PSym) =
#echo "created environment: ", env.id, " for ", prc.name.s
assignLocalVar(p, env)
# generate cast assignment:
appcg(p, cpsStmts, "$1 = ($2) ClEnv;$n", rdLoc(env.loc),
getTypeDesc(p.module, env.typ))
lineCg(p, cpsStmts, "$1 = ($2) ClEnv;$n", rdLoc(env.loc),
getTypeDesc(p.module, env.typ))
proc genProcAux(m: BModule, prc: PSym) =
var p = newProc(prc, m)
@@ -593,7 +622,7 @@ proc genProcAux(m: BModule, prc: PSym) =
# declare the result symbol:
assignLocalVar(p, res)
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)
else:
fillResult(res)
@@ -609,10 +638,10 @@ proc genProcAux(m: BModule, prc: PSym) =
genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
var generatedProc: PRope
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)])
else:
generatedProc = ropeff("$1 {$n", "define $1 {$n", [header])
generatedProc = ropeff("$N$1 {$N", "$Ndefine $1 {$N", [header])
app(generatedProc, initGCFrame(p))
if optStackTrace in prc.options:
getFrameDecl(p)
@@ -626,25 +655,25 @@ proc genProcAux(m: BModule, prc: PSym) =
if gProcProfile >= 64 * 1024:
InternalError(prc.info, "too many procedures for profiling")
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:
appf(m.s[cfsDebugInit], "profileData[$1].procname = $2;$n", [
appf(m.s[cfsDebugInit], "\tprofileData[$1].procname = $2;$n", [
toRope(gProcProfile),
makeCString(prc.name.s)])
prc.loc.a = 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(cpsStmts))
if p.beforeRetNeeded: appf(generatedProc, "BeforeRet: $n;")
if p.beforeRetNeeded: appf(generatedProc, "\tBeforeRet: ;$n")
app(generatedProc, deinitGCFrame(p))
if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM):
appf(generatedProc,
"profileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n",
"\tprofileData[$1].total += elapsed(getticks(), NIM_profilingStart);$n",
[toRope(prc.loc.a)])
app(generatedProc, returnStmt)
appf(generatedProc, "}$n")
appf(generatedProc, "}$N")
app(m.s[cfsProcs], generatedProc)
proc genProcPrototype(m: BModule, sym: PSym) =

View File

@@ -37,9 +37,11 @@ type
cfsDynLibDeinit # section for deinitialization of dynamic
# libraries
TCTypeKind* = enum # describes the type kind of a C type
ctVoid, ctChar, ctBool, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64,
ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString
ctVoid, ctChar, ctBool,
ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
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
TCProcSection* = enum # the sections a generated C proc consists of
cpsLocals, # section of local variables for C proc
@@ -62,8 +64,9 @@ type
ThreadVarAccessed*: bool # true if the proc already accessed some threadvar
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
# (the vars must be volatile then)
popCurrExc*: Natural # how often to emit 'popCurrentException()'
# before 'break'|'return'
inExceptBlock*: int # are we currently inside an except block?
# leaving such scopes by raise or by return must
# execute any applicable finally blocks
labels*: Natural # for generating unique labels in the C proc
blocks*: seq[TBlock] # nested blocks
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:
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
[toRope(esc(d.target, literal))])
of tkIntLit..tkInt64Lit:
of tkIntLit..tkUInt64Lit:
dispA(result, "<span class=\"DecNumber\">$1</span>",
"\\spanDecNumber{$1}", [toRope(esc(d.target, literal))])
of tkFloatLit..tkFloat64Lit:
of tkFloatLit..tkFloat128Lit:
dispA(result, "<span class=\"FloatNumber\">$1</span>",
"\\spanFloatNumber{$1}", [toRope(esc(d.target, literal))])
of tkSymbol:

View File

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

View File

@@ -597,7 +597,7 @@ proc CallCCompiler*(projectfile: string) =
proc genMappingFiles(list: TLinkedList): PRope =
var it = PStrEntry(list.head)
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)
proc writeMapping*(gSymbolMapping: PRope) =

View File

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

View File

@@ -53,9 +53,15 @@ proc getSysType(kind: TTypeKind): PType =
of tyInt16: result = sysTypeFromName("int16")
of tyInt32: result = sysTypeFromName("int32")
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 tyFloat32: result = sysTypeFromName("float32")
of tyFloat64: result = sysTypeFromName("float64")
of tyFloat128: result = sysTypeFromName("float128")
of tyBool: result = sysTypeFromName("bool")
of tyChar: result = sysTypeFromName("char")
of tyString: result = sysTypeFromName("string")

View File

@@ -416,6 +416,26 @@ proc identOrLiteral(p: var TParser): PNode =
result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p)
setBaseFlags(result, p.tok.base)
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:
result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p)
setBaseFlags(result, p.tok.base)
@@ -428,6 +448,10 @@ proc identOrLiteral(p: var TParser): PNode =
result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p)
of tkFloat128Lit:
result = newFloatNodeP(nkFloat128Lit, p.tok.fNumber, p)
setBaseFlags(result, p.tok.base)
getTok(p)
of tkStrLit:
result = newStrNodeP(nkStrLit, p.tok.literal, p)
getTok(p)

View File

@@ -23,7 +23,7 @@ const
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wNoStackFrame, wError, wDiscardable, wNoInit}
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor}
converterPragmas* = procPragmas
methodPragmas* = procPragmas
templatePragmas* = {wImmediate, wDeprecated, wError}
@@ -508,6 +508,11 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
incl(sym.loc.Flags, lfNoDecl)
# implies nodecl, because otherwise header would not make sense
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:
noVal(it)
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 nkInt32Lit: put(g, tkInt32Lit, 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 nkFloat32Lit: put(g, tkFloat32Lit, atom(n))
of nkFloat64Lit: put(g, tkFloat64Lit, atom(n))
of nkFloat128Lit: put(g, tkFloat128Lit, atom(n))
of nkStrLit: put(g, tkStrLit, atom(n))
of nkRStrLit: put(g, tkRStrLit, atom(n))
of nkCharLit: put(g, tkCharLit, atom(n))

View File

@@ -212,7 +212,11 @@ proc markUsed*(n: PNode, s: PSym) =
if {sfDeprecated, sfError} * s.flags != {}:
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, 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) =
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) =
const
IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyFloat128}
IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64}
if sameType(castDest, src) and castDest.sym == src.sym:
# 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))
return
var d = skipTypes(castDest, abstractVar)
@@ -143,7 +143,7 @@ proc checkConvertible(info: TLineInfo, castDest, src: PType) =
while (d != nil) and (d.Kind in {tyPtr, tyRef}) and (d.Kind == s.Kind):
d = base(d)
s = base(s)
if d == nil:
if d == nil:
GlobalError(info, errGenerated, msgKindToString(errIllegalConvFromXtoY) % [
src.typeToString, castDest.typeToString])
elif d.Kind == tyObject and s.Kind == tyObject:
@@ -1283,6 +1283,20 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
GlobalError(n.info, errInvalidExpressionX,
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 =
result = n
if gCmd == cmdIdeTools: suggestExpr(c, n)
@@ -1303,9 +1317,15 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ == nil:
let i = result.intVal
if i >= low(int32) and i <= high(int32):
result.typ = getSysType(tyInt)
if i >= 0:
result.typ = uniIntType(tyInt).memoize
else:
result.typ = getSysType(tyInt)
else:
result.typ = getSysType(tyInt64)
if i >= 0:
result.typ = uniIntType(tyInt64).memoize
else:
result.typ = getSysType(tyInt64)
of nkInt8Lit:
if result.typ == nil: result.typ = getSysType(tyInt8)
of nkInt16Lit:
@@ -1314,12 +1334,24 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.typ == nil: result.typ = getSysType(tyInt32)
of nkInt64Lit:
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:
if result.typ == nil: result.typ = getSysType(tyFloat)
of nkFloat32Lit:
if result.typ == nil: result.typ = getSysType(tyFloat32)
of nkFloat64Lit:
if result.typ == nil: result.typ = getSysType(tyFloat64)
of nkFloat128Lit:
if result.typ == nil: result.typ = getSysType(tyFloat128)
of nkStrLit..nkTripleStrLit:
if result.typ == nil: result.typ = getSysType(tyString)
of nkCharLit:

View File

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

View File

@@ -681,7 +681,9 @@ proc semLambda(c: PContext, n: PNode): PNode =
closeScope(c.tab) # close scope for parameters
popOwner()
result.typ = s.typ
proc instantiateDestructor*(c: PContext, typ: PType): bool
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
validPragmas: TSpecialWords): PNode =
result = n
@@ -743,6 +745,19 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
popOwner()
pushOwner(s)
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:
# for DLL generation it is annoying to check for sfImportc!
if sfBorrow in s.flags:
@@ -772,10 +787,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
incl(s.flags, sfForward)
elif sfBorrow in s.flags: semBorrow(c, n, 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:
localError(s.info, errXCannotBeClosure, s.name.s)
closeScope(c.tab) # close scope for parameters
@@ -864,6 +875,134 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
if result.isNil:
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):
tuple[outer: PNode, inner: PNode] =
# Accepts a var or let section.
@@ -889,7 +1028,7 @@ proc insertDestructors(c: PContext, varSection: PNode):
varTyp = varId.sym.typ
info = varId.info
if varTyp != nil and instantiateDestructor(varTyp):
if varTyp != nil and instantiateDestructor(c, varTyp):
var tryStmt = newNodeI(nkTryStmt, info)
if j < totalVars - 1:
@@ -910,8 +1049,8 @@ proc insertDestructors(c: PContext, varSection: PNode):
tryStmt.addSon(
newNode(nkFinally, info, @[
semStmt(c, newNode(nkCall, info, @[
semSym(c, varId, varTyp.destructor, {}),
semSym(c, varId, varId.sym, {})]))]))
useSym(varTyp.destructor),
useSym(varId.sym)]))]))
result.outer = newNodeI(nkStmtList, info)
varSection.sons.setLen(j+1)

View File

@@ -306,7 +306,9 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
covered: var biggestInt) =
for i in countup(0, sonsLen(branch) - 2):
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)
else:
var r = semConstExpr(c, b)
@@ -825,9 +827,15 @@ proc processMagicType(c: PContext, m: PSym) =
of mInt16: setMagicType(m, tyInt16, 2)
of mInt32: setMagicType(m, tyInt32, 4)
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 mFloat32: setMagicType(m, tyFloat32, 4)
of mFloat64: setMagicType(m, tyFloat64, 8)
of mFloat128: setMagicType(m, tyFloat128, 16)
of mBool: setMagicType(m, tyBool, 1)
of mChar: setMagicType(m, tyChar, 1)
of mString:

View File

@@ -163,6 +163,9 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
var k = skipTypes(a, {tyRange}).kind
if k == f.kind: result = isSubtype
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
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 tyInt32: result = handleRange(f, a, tyInt, tyInt32)
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 tyFloat32: 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 =
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
isOrdinalType(t.sons[0])
@@ -386,10 +386,11 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
"GenericInvokation", "GenericBody", "GenericInst", "GenericParam",
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
"pointer", "OpenArray[$1]", "string", "CString", "Forward", "int", "int8",
"int16", "int32", "int64", "float", "float32", "float64", "float128",
"uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ",
"pointer", "OpenArray[$1]", "string", "CString", "Forward",
"int", "int8", "int16", "int32", "int64",
"float", "float32", "float64", "float128",
"uint", "uint8", "uint16", "uint32", "uint64",
"bignum", "const ",
"!", "varargs[$1]", "iter[$1]", "proxy[$1]", "TypeClass" ]
var t = typ
result = ""
@@ -494,6 +495,7 @@ proc firstOrd(t: PType): biggestInt =
of tyInt16: result = - 32768
of tyInt32: result = - 2147483646 - 2
of tyInt64: result = 0x8000000000000000'i64
of tyUInt..tyUInt64: result = 0
of tyEnum:
# if basetype <> nil then return firstOrd of basetype
if (sonsLen(t) > 0) and (t.sons[0] != nil):
@@ -524,6 +526,13 @@ proc lastOrd(t: PType): biggestInt =
of tyInt16: result = 0x00007FFF
of tyInt32: result = 0x7FFFFFFF
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:
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
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:
result = 8
a = result
of tyFloat128:
result = 16
a = result
of tyFloat:
result = floatSize
a = result
@@ -1062,10 +1074,3 @@ proc getSize(typ: PType): biggestInt =
result = computeSize(typ)
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,
wImmediate, wImportCpp, wImportObjC,
wImmediate, wDestructor, wImportCpp, wImportObjC,
wImportCompilerProc,
wImportc, wExportc, wIncompleteStruct,
wAlign, wNodecl, wPure, wSideeffect, wHeader,
@@ -117,7 +117,7 @@ const
"destroy",
"immediate", "importcpp", "importobjc",
"immediate", "destructor", "importcpp", "importobjc",
"importcompilerproc", "importc", "exportc", "incompletestruct",
"align", "nodecl", "pure", "sideeffect",
"header", "nosideeffect", "noreturn", "merge", "lib", "dynlib",

View File

@@ -62,6 +62,7 @@ hint[LineTooLong]=off
@if not bsd:
# -fopenmp
gcc.options.linker = "-ldl"
gpp.options.linker = "-ldl"
clang.options.linker = "-ldl"
tcc.options.linker = "-ldl"
@else:
@@ -83,24 +84,23 @@ icc.options.linker = "-cxxlib"
tlsEmulation:on
@end
@end
gcc.options.debug = "-g3 -O0"
@if macosx:
tlsEmulation:on
@if not release:
gcc.options.always = "-w -fasm-blocks -O1"
@else:
gcc.options.always = "-w -fasm-blocks"
@end
gcc.options.always = "-w -fasm-blocks"
gpp.options.always = "-w -fasm-blocks"
@else:
@if not release:
gcc.options.always = "-w"
@else:
gcc.options.always = "-w"
@end
gcc.options.always = "-w"
gpp.options.always = "-w"
@end
gcc.options.speed = "-O3 -fno-strict-aliasing"
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"
# 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
nnkNone, nnkEmpty, nnkIdent, nnkSym,
nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkFloatLit,
nnkFloat32Lit, nnkFloat64Lit, nnkStrLit, nnkRStrLit,
nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall,
nnkCommand, nnkCall, nnkCallStrLit, nnkExprEqExpr,
nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkInfix,

View File

@@ -43,8 +43,13 @@ type
akFloat = 36, ## any represents a float
akFloat32 = 37, ## any represents a float32
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
## value can be modified with its wrapper! This means
## that ``TAny`` keeps a non-traced pointer to its

View File

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

View File

@@ -192,7 +192,7 @@ __clang__
** 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? */
# define HAVE_LRINT
# define HAVE_LRINTF
@@ -281,6 +281,13 @@ static unsigned long nimInf[2]={0xffffffff, 0x7fffffff};
# endif
# define NIM_BOOL bool
# 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
# ifdef bool
# define NIM_BOOL bool

View File

@@ -42,6 +42,14 @@
## body.add("--xyz--")
##
## 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
@@ -79,10 +87,11 @@ proc charAt(d: var string, i: var int, s: TSocket): char {.inline.} =
i = 0
result = d[i]
proc parseChunks(d: var string, start: int, s: TSocket): string =
proc parseChunks(s: TSocket): string =
# get chunks:
var i = start
var i = 0
result = ""
var d = s.recv().string
while true:
var chunkSize = 0
var digitFound = false
@@ -128,88 +137,87 @@ proc parseChunks(d: var string, start: int, s: TSocket): string =
# skip trailing CR-LF:
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 =
result = ""
if headers["Transfer-Encoding"] == "chunked":
result = parseChunks(d, start, s)
result = parseChunks(s)
else:
result = substr(d, start)
# -REGION- Content-Length
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
var contentLengthHeader = headers["Content-Length"]
if contentLengthHeader != "":
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:
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO
# -REGION- Connection: Close
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5
if headers["Connection"] == "close":
var buf = ""
while True:
var moreData = recv(s).string
if moreData.len == 0: break
result.add(moreData)
buf = newString(4000)
let r = s.recv(addr(buf[0]), 4000)
if r == 0: break
buf.setLen(r)
result.add(buf)
proc parseResponse(s: TSocket): TResponse =
var d = s.recv.string
var i = 0
# Parse the version
# 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
proc parseResponse(s: TSocket, getBody: bool): TResponse =
var parsedStatus = false
var linei = 0
var fullyRead = false
var line = ""
result.headers = newStringTable(modeCaseInsensitive)
while true:
var key = ""
while d[i] != ':':
if d[i] == '\0': httpError("invalid HTTP header, ':' expected")
key.add(d[i])
inc(i)
inc(i) # skip ':'
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
result.body = parseBody(d, i, s, result.headers)
while True:
line = ""
linei = 0
if s.recvLine(line):
if line == "": break # We've been disconnected.
if line == "\c\L":
fullyRead = true
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.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
THttpMethod* = enum ## the requested HttpMethod
@@ -238,6 +246,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
var headers = substr($httpMethod, len("http"))
headers.add(" /" & r.path & r.query)
headers.add(" HTTP/1.1\c\L")
add(headers, "Host: " & r.hostname & "\c\L")
@@ -245,12 +254,21 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
add(headers, "\c\L")
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)
if body != "":
s.send(body)
result = parseResponse(s)
result = parseResponse(s, httpMethod != httpHEAD)
s.close()
proc redirection(status: string): bool =

View File

@@ -8,25 +8,25 @@
#
## This module contains procs for serialization and deseralization of
## arbitrary Nimrod data structures. The serialization format uses JSON.
##
## **Restriction**: For objects their type is **not** serialized. This means
## essentially that it does not work if the object has some other runtime
## type than its compiletime type:
##
## .. code-block:: nimrod
##
## type
## TA = object
## TB = object of TA
## f: int
##
## var
## a: ref TA
## b: ref TB
##
## new(b)
## a = b
## arbitrary Nimrod data structures. The serialization format uses JSON.
##
## **Restriction**: For objects their type is **not** serialized. This means
## essentially that it does not work if the object has some other runtime
## type than its compiletime type:
##
## .. code-block:: nimrod
##
## type
## TA = object
## TB = object of TA
## f: int
##
## var
## a: ref TA
## b: ref TB
##
## new(b)
## a = b
## echo($$a[]) # produces "{}", not "{f: 0}"
import streams, typeinfo, json, intsets, tables
@@ -86,7 +86,7 @@ proc storeAny(s: PStream, a: TAny, stored: var TIntSet) =
var x = getString(a)
if IsNil(x): s.write("null")
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))
proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) =
@@ -128,18 +128,18 @@ proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) =
next(p)
of jsonArrayStart:
next(p)
invokeNewSeq(a, 0)
var i = 0
invokeNewSeq(a, 0)
var i = 0
while p.kind != jsonArrayEnd and p.kind != jsonEof:
extendSeq(a)
extendSeq(a)
loadAny(p, a[i], t)
inc(i)
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "")
else:
else:
raiseParseErr(p, "'[' expected for a seq")
of akObject, akTuple:
if a.kind == akObject: setObjectRuntimeType(a)
if a.kind == akObject: setObjectRuntimeType(a)
if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
next(p)
while p.kind != jsonObjectEnd and p.kind != jsonEof:
@@ -169,13 +169,13 @@ proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) =
next(p)
of jsonArrayStart:
next(p)
if a.kind == akRef: invokeNew(a)
else: setPointer(a, alloc0(a.baseTypeSize))
if p.kind == jsonInt:
t[p.getInt] = getPointer(a)
next(p)
else: raiseParseErr(p, "index for ref type expected")
loadAny(p, a[], t)
if a.kind == akRef: invokeNew(a)
else: setPointer(a, alloc0(a.baseTypeSize))
if p.kind == jsonInt:
t[p.getInt] = getPointer(a)
next(p)
else: raiseParseErr(p, "index for ref type expected")
loadAny(p, a[], t)
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "']' end of ref-address pair expected")
else: raiseParseErr(p, "int for pointer type expected")
@@ -197,7 +197,7 @@ proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) =
setString(a, p.str)
next(p)
else: raiseParseErr(p, "string expected")
of akInt..akInt64:
of akInt..akInt64, akUInt..akUInt64:
if p.kind == jsonInt:
setBiggestInt(a, getInt(p))
next(p)
@@ -208,7 +208,7 @@ proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) =
setBiggestFloat(a, getFloat(p))
next(p)
return
raiseParseErr(p, "float expected")
raiseParseErr(p, "float expected")
of akRange: loadAny(p, a.skipRange, t)
proc loadAny(s: PStream, a: TAny, t: var TTable[biggestInt, pointer]) =
@@ -220,7 +220,7 @@ proc loadAny(s: PStream, a: TAny, t: var TTable[biggestInt, pointer]) =
proc load*[T](s: PStream, data: var T) =
## loads `data` from the stream `s`. Raises `EIO` in case of an error.
var tab = initTable[biggestInt, pointer]()
var tab = initTable[biggestInt, pointer]()
loadAny(s, toAny(data), tab)
proc store*[T](s: PStream, data: T) =
@@ -229,91 +229,91 @@ proc store*[T](s: PStream, data: T) =
var d: T
shallowCopy(d, data)
storeAny(s, toAny(d), stored)
proc `$$`*[T](x: T): string =
## returns a string representation of `x`.
proc `$$`*[T](x: T): string =
## returns a string representation of `x`.
var stored = initIntSet()
var d: T
shallowCopy(d, x)
var s = newStringStream()
var s = newStringStream()
storeAny(s, toAny(d), stored)
result = s.data
proc to*[T](data: string): T =
## reads data and transforms it to a ``T``.
var tab = initTable[biggestInt, pointer]()
result = s.data
proc to*[T](data: string): T =
## reads data and transforms it to a ``T``.
var tab = initTable[biggestInt, pointer]()
loadAny(newStringStream(data), toAny(result), tab)
when isMainModule:
template testit(x: expr) = echo($$to[type(x)]($$x))
when isMainModule:
template testit(x: expr) = echo($$to[type(x)]($$x))
var x: array[0..4, array[0..4, string]] = [
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
["test", "1", "2", "3", "4"]]
testit(x)
var test2: tuple[name: string, s: int] = ("tuple test", 56)
testit(test2)
type
TE = enum
blah, blah2
TestObj = object
test, asd: int
case test2: TE
of blah:
help: string
else:
nil
PNode = ref TNode
TNode = object
next, prev: PNode
data: string
proc buildList(): PNode =
new(result)
new(result.next)
new(result.prev)
result.data = "middle"
result.next.data = "next"
result.prev.data = "prev"
result.next.next = result.prev
result.next.prev = result
result.prev.next = result
result.prev.prev = result.next
var test3: TestObj
test3.test = 42
test3.test2 = blah
testit(test3)
var test4: ref tuple[a, b: string]
new(test4)
test4.a = "ref string test: A"
test4.b = "ref string test: B"
testit(test4)
var test5 = @[(0,1),(2,3),(4,5)]
testit(test5)
var test6: set[char] = {'A'..'Z', '_'}
testit(test6)
var test7 = buildList()
echo($$test7)
testit(test7)
type
TA = object
TB = object of TA
f: int
var
a: ref TA
b: ref TB
new(b)
a = b
var test2: tuple[name: string, s: int] = ("tuple test", 56)
testit(test2)
type
TE = enum
blah, blah2
TestObj = object
test, asd: int
case test2: TE
of blah:
help: string
else:
nil
PNode = ref TNode
TNode = object
next, prev: PNode
data: string
proc buildList(): PNode =
new(result)
new(result.next)
new(result.prev)
result.data = "middle"
result.next.data = "next"
result.prev.data = "prev"
result.next.next = result.prev
result.next.prev = result
result.prev.next = result
result.prev.prev = result.next
var test3: TestObj
test3.test = 42
test3.test2 = blah
testit(test3)
var test4: ref tuple[a, b: string]
new(test4)
test4.a = "ref string test: A"
test4.b = "ref string test: B"
testit(test4)
var test5 = @[(0,1),(2,3),(4,5)]
testit(test5)
var test6: set[char] = {'A'..'Z', '_'}
testit(test6)
var test7 = buildList()
echo($$test7)
testit(test7)
type
TA = object
TB = object of TA
f: int
var
a: ref TA
b: ref TB
new(b)
a = b
echo($$a[]) # produces "{}", not "{f: 0}"

View File

@@ -186,10 +186,12 @@ when not defined(ECMAScript):
proc trunc*(x: float): float {.importc: "trunc", nodecl.}
proc floor*(x: float): float {.importc: "floor", nodecl.}
proc ceil*(x: float): float {.importc: "ceil", nodecl.}
else:
proc mathrandom(): float {.importc: "Math.random", 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 randomize*() = nil

View File

@@ -1346,11 +1346,15 @@ when defined(linux) or defined(solaris) or defined(bsd) or defined(aix):
setlen(result, len)
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
# 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>".}
proc getExecPath2(c: cstring, size: var int32): bool {.
proc getExecPath2(c: cstring, size: var cuint32): bool {.
importc: "_NSGetExecutablePath", header: "<mach-o/dyld.h>".}
proc getAppFilename*(): string {.rtl, extern: "nos$1".} =
@@ -1379,7 +1383,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1".} =
elif defined(bsd):
result = getApplAux("/proc/" & $getpid() & "/file")
elif defined(macosx):
var size: int32
var size: cuint32
getExecPath1(nil, size)
result = newString(int(size))
if getExecPath2(result, size):

View File

@@ -123,7 +123,7 @@ when defined(macosx) or defined(bsd):
HW_AVAILCPU = 25
HW_NCPU = 3
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>".}
proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
@@ -135,7 +135,8 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
elif defined(macosx) or defined(bsd):
var
mib: array[0..3, cint]
len, numCPU: int
numCPU: int
len: csize
mib[0] = CTL_HW
mib[1] = HW_AVAILCPU
len = sizeof(numCPU)

View File

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

View File

@@ -10,11 +10,16 @@
## This module implements a simple portable type-safe sockets layer.
##
## 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
from times import epochTime
when defined(ssl):
import openssl
when defined(Windows):
import winlean
else:
@@ -22,8 +27,40 @@ else:
# Note: The enumerations are mapped to Window's constants.
when defined(ssl):
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
TSocket* = distinct cint ## socket 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
TDomain* = enum ## domain, which specifies the protocol family of the
@@ -65,11 +102,15 @@ type
ETimeout* = object of ESynch
const
InvalidSocket* = TSocket(-1'i32) ## invalid socket number
proc newTSocket(fd: int32, isBuff: bool): TSocket =
new(result)
result.fd = fd
result.isBuffered = isBuff
if isBuff:
result.currPos = 0
proc `==`*(a, b: TSocket): bool {.borrow.}
## ``==`` for sockets.
let
InvalidSocket*: TSocket = nil ## invalid socket
proc `==`*(a, b: TPort): bool {.borrow.}
## ``==`` for ports.
@@ -144,18 +185,111 @@ else:
result = cint(ord(p))
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.
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:
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) =
## Marks ``socket`` as accepting connections.
## ``Backlog`` specifies the maximum length of the
## 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.} =
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_port = sockets.htons(int16(port))
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:
OSError()
else:
@@ -218,7 +352,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") =
hints.ai_socktype = toInt(SOCK_STREAM)
hints.ai_protocol = toInt(IPPROTO_TCP)
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()
when false:
@@ -245,22 +379,29 @@ proc getSockName*(socket: TSocket): TPort =
#name.sin_port = htons(cint16(port))
#name.sin_addr.s_addr = htonl(INADDR_ANY)
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:
OSError()
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
## 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 there are no connections queued the returned socket will be
## ``InvalidSocket``.
## This function will raise EOS if an error occurs.
var address: Tsockaddr_in
var addrLen: cint = sizeof(address)
var sock = accept(cint(server), cast[ptr TSockAddr](addr(address)),
##
## **Warning:** This function might block even if socket is non-blocking
## when using SSL.
var sockAddress: Tsockaddr_in
var addrLen: cint = sizeof(sockAddress)
var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
addr(addrLen))
if sock < 0:
# TODO: Test on Windows.
when defined(windows):
@@ -272,20 +413,54 @@ proc acceptAddr*(server: TSocket): tuple[sock: TSocket, address: string] =
if errno == EAGAIN or errno == EWOULDBLOCK:
return (InvalidSocket, "")
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 =
## Equivalent to ``acceptAddr`` but doesn't return the address, only the
## socket.
var (client, a) = acceptAddr(server)
let (client, a) = acceptAddr(server)
return client
proc close*(socket: TSocket) =
## closes a socket.
when defined(windows):
discard winlean.closeSocket(cint(socket))
discard winlean.closeSocket(socket.fd)
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 =
## well-known getservbyname proc.
@@ -365,7 +540,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int =
## getsockopt for integer options.
var res: cint
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:
OSError()
result = int(res)
@@ -373,7 +548,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int =
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) =
## setsockopt for integer options.
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:
OSError()
@@ -395,7 +570,7 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
var success = false
var it = aiList
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
break
it = it.ai_next
@@ -403,6 +578,24 @@ proc connect*(socket: TSocket, name: string, port = TPort(0),
freeaddrinfo(aiList)
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:
var s: TSockAddrIn
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_INET6: s.sin_family = posix.AF_INET6
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()
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 it = aiList
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:
success = true
break
@@ -453,6 +646,26 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
freeaddrinfo(aiList)
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 =
if timeout != -1:
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) =
FD_ZERO(fd)
for i in items(s):
m = max(m, int(i))
FD_SET(cint(i), fd)
m = max(m, int(i.fd))
FD_SET(i.fd, fd)
proc pruneSocketSet(s: var seq[TSocket], fd: var TFdSet) =
var i = 0
var L = s.len
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]
dec(L)
else:
@@ -552,34 +765,117 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int =
result = int(select(cint(m+1), addr(rd), nil, nil, nil))
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 =
## receives data from a socket
result = recv(cint(socket), data, size, 0'i32)
if socket.isBuffered:
if socket.bufLen == 0:
retRead(0'i32, 0)
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)
template waitFor(): stmt =
if timeout - int(waited * 1000.0) < 1:
raise newException(ETimeout, "Call to recv() timed out.")
var s = @[socket]
var startTime = epochTime()
if select(s, timeout - int(waited * 1000.0)) != 1:
raise newException(ETimeout, "Call to recv() timed out.")
waited += (epochTime() - startTime)
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:
raise newException(ETimeout, "Call to recv() timed out.")
var s = @[socket]
var startTime = epochTime()
if select(s, timeout - int(waited * 1000.0)) != 1:
raise newException(ETimeout, "Call to recv() timed out.")
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.
var waited = 0.0 # number of seconds already waited
var read = 0
while read < size:
waitFor()
result = recv(cint(socket), addr(data[read]), 1, 0'i32)
let avail = waitFor(socket, waited, timeout)
var d = cast[cstring](data)
result = recv(socket, addr(d[read]), avail)
if result == 0: break
if result < 0:
return
inc(read)
return result
inc(read, result)
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 =
## 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``
@@ -590,6 +886,9 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
##
## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
## will be returned.
##
## **Warning:** Using this function on a unbuffered ssl socket will result
## in an error.
template addNLIfEmpty(): stmt =
if line.len == 0:
line.add("\c\L")
@@ -597,13 +896,13 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool =
setLen(line.string, 0)
while true:
var c: char
var n = recv(cint(socket), addr(c), 1, 0'i32)
var n = recv(socket, addr(c), 1)
if n < 0: return
elif n == 0: return true
if c == '\r':
n = recv(cint(socket), addr(c), 1, MSG_PEEK)
n = peekChar(socket, c)
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
addNlIfEmpty()
return true
@@ -624,15 +923,15 @@ proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool =
setLen(line.string, 0)
while true:
var c: char
waitFor()
var n = recv(cint(socket), addr(c), 1, 0'i32)
discard waitFor(socket, waited, timeout)
var n = recv(socket, addr(c), 1)
if n < 0: return
elif n == 0: return true
if c == '\r':
waitFor()
n = recv(cint(socket), addr(c), 1, MSG_PEEK)
discard waitFor(socket, waited, timeout)
n = peekChar(socket, c)
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
addNlIfEmpty()
return true
@@ -651,15 +950,15 @@ proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult =
setLen(line.string, 0)
while true:
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 line.len == 0: RecvFail else: RecvPartialLine)
elif n == 0:
return (if line.len == 0: RecvDisconnected else: RecvPartialLine)
if c == '\r':
n = recv(cint(socket), addr(c), 1, MSG_PEEK)
n = peekChar(socket, c)
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 (if line.len == 0: RecvFail else: RecvPartialLine)
return RecvFullLine
@@ -671,7 +970,7 @@ proc recv*(socket: TSocket): TaintedString =
## Socket errors will result in an ``EOS`` error.
## If socket is not a connectionless socket and socket is not connected
## ``""`` will be returned.
const bufSize = 1000
const bufSize = 4000
result = newStringOfCap(bufSize).TaintedString
var pos = 0
while true:
@@ -699,9 +998,10 @@ proc recvTimeout*(socket: TSocket, timeout: int): TaintedString =
## overloaded variant to support a ``timeout`` parameter, the ``timeout``
## parameter specifies the amount of miliseconds to wait for data on the
## socket.
var s = @[socket]
if s.select(timeout) != 1:
raise newException(ETimeout, "Call to recv() timed out.")
if socket.bufLen == 0:
var s = @[socket]
if s.select(timeout) != 1:
raise newException(ETimeout, "Call to recv() timed out.")
return socket.recv
@@ -718,7 +1018,24 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool =
var pos = 0
while true:
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):
# TODO: Test on Windows
var err = WSAGetLastError()
@@ -746,19 +1063,46 @@ proc skip*(socket: TSocket) =
proc send*(socket: TSocket, data: pointer, size: int): int =
## 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):
result = send(cint(socket), data, size, 0'i32)
result = send(socket.fd, data, size, 0'i32)
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) =
## 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 =
## sends data to a non-blocking socket. Returns whether ``data`` was sent.
result = true
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:
when defined(windows):
var err = WSAGetLastError()
@@ -792,15 +1136,15 @@ proc setBlocking*(s: TSocket, blocking: bool) =
## sets blocking mode on socket
when defined(Windows):
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()
else: # BSD sockets
var x: int = fcntl(cint(s), F_GETFL, 0)
var x: int = fcntl(s.fd, F_GETFL, 0)
if x == -1:
OSError()
else:
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()
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($info.monthday)
of "ddd":
result.add(($info.monthday)[0 .. 2])
result.add(($info.weekday)[0 .. 2])
of "dddd":
result.add($info.monthday)
result.add($info.weekday)
of "h":
result.add($(info.hour - 12))
of "hh":

View File

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

View File

@@ -21,9 +21,15 @@ type
int16* {.magic: Int16.} ## signed 16 bit integer type
int32* {.magic: Int32.} ## signed 32 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
float32* {.magic: Float32.} ## 32 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
bool* {.magic: Bool.} = enum ## built-in boolean type
false = 0, true = 1
@@ -49,14 +55,23 @@ type
## a type description (for templates)
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
TOrdinal* = TInteger|bool|enum
TOrdinal* = distinct TInteger|bool|enum
## type class matching all ordinal types; however this includes enums with
## holes.
TReal* = distinct float|float32|float64
## type class matching all floating point number types
TNumber* = TInteger|float|float32|float64
TNumber* = distinct TInteger|TReal
## type class matching all number types
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
## checking is turned on).
proc `+%` *(x, y: int): int {.magic: "AddU", noSideEffect.}
proc `+%` *(x, y: int8): int8 {.magic: "AddU", noSideEffect.}
proc `+%` *(x, y: int16): int16 {.magic: "AddU", noSideEffect.}
proc `+%` *(x, y: int32): int32 {.magic: "AddU", noSideEffect.}
proc `+%` *(x, y: int64): int64 {.magic: "AddU64", noSideEffect.}
type
UIntMax32 = distinct uint|uint8|uint16|uint32
IntMax32 = distinct int|int8|int16|int32
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
## fit into the result. This implements modulo arithmetic. No overflow
## errors are possible.
proc `-%` *(x, y: int): int {.magic: "SubU", noSideEffect.}
proc `-%` *(x, y: int8): int8 {.magic: "SubU", noSideEffect.}
proc `-%` *(x, y: int16): int16 {.magic: "SubU", noSideEffect.}
proc `-%` *(x, y: int32): int32 {.magic: "SubU", noSideEffect.}
proc `-%` *(x, y: int64): int64 {.magic: "SubU64", noSideEffect.}
proc `-` *(x, y: UIntMax32): UIntMax32 {.magic: "SubU", noSideEffect.}
proc `-` *(x, y: UInt64): UInt64 {.magic: "SubU64", noSideEffect.}
## Binary `-` operator for unsigned integers.
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
## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible.
proc `*%` *(x, y: int): int {.magic: "MulU", noSideEffect.}
proc `*%` *(x, y: int8): int8 {.magic: "MulU", noSideEffect.}
proc `*%` *(x, y: int16): int16 {.magic: "MulU", noSideEffect.}
proc `*%` *(x, y: int32): int32 {.magic: "MulU", noSideEffect.}
proc `*%` *(x, y: int64): int64 {.magic: "MulU64", noSideEffect.}
proc `*` *(x, y: UIntMax32): UIntMax32 {.magic: "MulU", noSideEffect.}
proc `*` *(x, y: UInt64): UInt64 {.magic: "MulU64", noSideEffect.}
## Binary `*` operator for unsigned integers.
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
## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible.
proc `/%` *(x, y: int): int {.magic: "DivU", noSideEffect.}
proc `/%` *(x, y: int8): int8 {.magic: "DivU", noSideEffect.}
proc `/%` *(x, y: int16): int16 {.magic: "DivU", noSideEffect.}
proc `/%` *(x, y: int32): int32 {.magic: "DivU", noSideEffect.}
proc `/%` *(x, y: int64): int64 {.magic: "DivU64", noSideEffect.}
proc `div` *(x, y: UIntMax32): UIntMax32 {.magic: "DivU", noSideEffect.}
proc `div` *(x, y: UInt64): UInt64 {.magic: "DivU64", noSideEffect.}
## computes the integer division. This is roughly the same as
## ``floor(x/y)``.
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
## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible.
proc `%%` *(x, y: int): int {.magic: "ModU", noSideEffect.}
proc `%%` *(x, y: int8): int8 {.magic: "ModU", noSideEffect.}
proc `%%` *(x, y: int16): int16 {.magic: "ModU", noSideEffect.}
proc `%%` *(x, y: int32): int32 {.magic: "ModU", noSideEffect.}
proc `%%` *(x, y: int64): int64 {.magic: "ModU64", noSideEffect.}
proc `%` *(x, y: UIntMax32): UIntMax32 {.magic: "DivU", noSideEffect.}
proc `%` *(x, y: UInt64): UInt64 {.magic: "DivU64", noSideEffect.}
## computes the integer modulo operation. This is the same as
## ``x - (x div y) * y``.
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`.
## The result is truncated to fit into the result.
## This implements modulo arithmetic.
## No overflow errors are possible.
proc `<=%` *(x, y: int): bool {.magic: "LeU", noSideEffect.}
proc `<=%` *(x, y: int8): bool {.magic: "LeU", noSideEffect.}
proc `<=%` *(x, y: int16): bool {.magic: "LeU", noSideEffect.}
proc `<=%` *(x, y: int32): bool {.magic: "LeU", noSideEffect.}
proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
proc `<=` *(x, y: UIntMax32): bool {.magic: "LeU", noSideEffect.}
proc `<=` *(x, y: UInt64): bool {.magic: "LeU64", noSideEffect.}
## Returns true iff ``x <= y``.
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.
## Returns true iff ``unsigned(x) <= unsigned(y)``.
proc `<%` *(x, y: int): bool {.magic: "LtU", noSideEffect.}
proc `<%` *(x, y: int8): bool {.magic: "LtU", noSideEffect.}
proc `<%` *(x, y: int16): bool {.magic: "LtU", noSideEffect.}
proc `<%` *(x, y: int32): bool {.magic: "LtU", noSideEffect.}
proc `<%` *(x, y: int64): bool {.magic: "LtU64", noSideEffect.}
proc `<` *(x, y: UIntMax32): bool {.magic: "LtU", noSideEffect.}
proc `<` *(x, y: UInt64): bool {.magic: "LtU64", noSideEffect.}
## Returns true iff ``unsigned(x) < unsigned(y)``.
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.
## 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*.
cint* {.importc: "int", nodecl.} = int32
## 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
## This is the same as the type ``long`` in *C*.
clonglong* {.importc: "long long", nodecl.} = int64
@@ -951,7 +991,7 @@ type # these work for most platforms:
## This is binary compatible to the type ``char**`` in *C*. The array's
## high value is large enough to disable bounds checking in practice.
## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
PFloat32* = ptr Float32 ## an alias for ``ptr float32``
PFloat64* = ptr Float64 ## an alias for ``ptr float64``
PInt64* = ptr Int64 ## an alias for ``ptr int64``

View File

@@ -139,6 +139,10 @@ proc objectInit(dest: Pointer, typ: PNimType) =
# ---------------------- 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 genericResetAux(dest: Pointer, n: ptr TNimNode) =
var d = cast[TAddress](dest)

View File

@@ -37,7 +37,9 @@ type # This should be he same as ast.TTypeKind
tyPointer, tyOpenArray,
tyString, tyCString, tyForward,
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
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
# Give here only the bare minimum, to be expanded as needs arise
UINT8* = int8
UINT16* = int16
UINT32* = int32
UINT64* = int64
LONG32* = int32
ULONG32* = int32
DWORD32* = int32
@@ -95,7 +91,6 @@ type # WinDef.h -- Basic Windows Type Definitions
LPCVOID* = pointer
# INT* = int # Cannot work and not necessary anyway
UINT* = int
PUINT* = ptr int
WPARAM* = LONG_PTR
@@ -18518,9 +18513,9 @@ proc DisableThreadLibraryCalls*(hLibModule: HMODULE): WINBOOL{.stdcall,
proc GetProcAddress*(hModule: HINST, lpProcName: LPCSTR): FARPROC{.stdcall,
dynlib: "kernel32", importc: "GetProcAddress".}
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".}
proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: UINT): HGLOBAL{.
proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: INT): HGLOBAL{.
stdcall, dynlib: "kernel32", importc: "GlobalReAlloc".}
proc GlobalSize*(hMem: HGLOBAL): DWORD{.stdcall, dynlib: "kernel32",
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 =
var gnu_lvi: LV_ITEM
gnu_lvi.stateMask = mask
gnu_lvi.state = data
gnu_lvi.stateMask = uint(mask)
gnu_lvi.state = uint(data)
result = SendMessage(hwndLV, LVM_SETITEMSTATE, WPARAM(i),
cast[LPARAM](addr(gnu_lvi)))

View File

@@ -192,19 +192,44 @@ const
BIO_C_DO_STATE_MACHINE = 101
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 ERR_load_BIO_strings*(){.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,
dynlib: DLLSSLName, importc.}
proc SSL_CTX_load_verify_locations*(ctx: PSSL_CTX, CAfile: cstring,
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,
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,
dynlib: DLLSSLName, importc.}
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_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:
nil
else:
proc SslGetError*(s: PSSL, ret_code: cInt): cInt{.cdecl, dynlib: DLLSSLName,
importc.}
proc SslCtxSetCipherList*(arg0: PSSL_CTX, str: cstring): cInt{.cdecl,
dynlib: DLLSSLName, importc.}
proc SslCtxNew*(meth: PSSL_METHOD): PSSL_CTX{.cdecl,
dynlib: DLLSSLName, importc.}
proc SslCtxFree*(arg0: PSSL_CTX){.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,
dynlib: DLLSSLName, importc.}
@@ -255,19 +291,15 @@ else:
dynlib: DLLSSLName, importc.}
proc SslCtxUsePrivateKeyASN1*(pk: cInt, ctx: PSSL_CTX,
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,
dynlib: DLLSSLName, importc.}
proc SslCtxUseCertificateASN1*(ctx: PSSL_CTX, length: int, d: cstring): cInt{.
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;
proc SslCtxUseCertificateChainFile*(ctx: PSSL_CTX, filename: cstring): cInt{.
cdecl, dynlib: DLLSSLName, importc.}
proc SslCtxCheckPrivateKeyFile*(ctx: PSSL_CTX): cInt{.cdecl, dynlib: DLLSSLName,
importc.}
proc SslCtxSetDefaultPasswdCb*(ctx: PSSL_CTX, cb: PPasswdCb){.cdecl,
dynlib: DLLSSLName, importc.}
proc SslCtxSetDefaultPasswdCbUserdata*(ctx: PSSL_CTX, u: SslPtr){.cdecl,
@@ -276,10 +308,10 @@ else:
proc SslCtxLoadVerifyLocations*(ctx: PSSL_CTX, CAfile: cstring, CApath: cstring): cInt{.
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 SslShutdown*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
proc SslRead*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl,
dynlib: DLLSSLName, importc.}
proc SslPeek*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl,
@@ -339,9 +371,7 @@ else:
proc EVPcleanup*(){.cdecl, dynlib: DLLUtilName, importc.}
# function ErrErrorString(e: cInt; buf: PChar): PChar;
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 ErrFreeStrings*(){.cdecl, dynlib: DLLUtilName, importc.}
proc ErrRemoveState*(pid: cInt){.cdecl, dynlib: DLLUtilName, importc.}

View File

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

View File

@@ -1,6 +1,6 @@
discard """
file: "system.nim"
line: 640
line: 678
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)
createDir(dir)
var cmd = ("nimrod compile -f --symbolfiles:off --compileonly " &
"--gen_mapping --cc:gcc" &
"--gen_mapping --cc:gcc --skipUserCfg" &
" --os:$# --cpu:$# $# $#") %
[c.oses[osA-1], c.cpus[cpuA-1], c.nimrodArgs,
changeFileExt(c.infile, "nim")]

View File

@@ -51,7 +51,11 @@ Library Additions
- Added ``system.||`` for parallel for loop support.
- The GC supports (soft) realtime systems via ``GC_setMaxPause``
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
-----------------------------------------
@@ -77,7 +81,7 @@ Changes affecting backwards compatibility
- 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
produced consistent results.
- Deprecated the ``ssl`` module.
Compiler Additions
------------------