beginning of a taint mode; type system enhancements
This commit is contained in:
parent
2359b8b107
commit
6023e994fb
18 changed files with 265 additions and 283 deletions
|
|
@ -143,6 +143,7 @@ type
|
||||||
nkWhileStmt, # a while statement
|
nkWhileStmt, # a while statement
|
||||||
nkCaseStmt, # a case statement
|
nkCaseStmt, # a case statement
|
||||||
nkVarSection, # a var section
|
nkVarSection, # a var section
|
||||||
|
nkLetSection, # a let section
|
||||||
nkConstSection, # a const section
|
nkConstSection, # a const section
|
||||||
nkConstDef, # a const definition
|
nkConstDef, # a const definition
|
||||||
nkTypeSection, # a type section (consists of type definitions)
|
nkTypeSection, # a type section (consists of type definitions)
|
||||||
|
|
@ -178,6 +179,8 @@ type
|
||||||
nkRefTy,
|
nkRefTy,
|
||||||
nkPtrTy,
|
nkPtrTy,
|
||||||
nkVarTy,
|
nkVarTy,
|
||||||
|
nkConstTy, # ``const T``
|
||||||
|
nkMutableTy, # ``mutable T``
|
||||||
nkDistinctTy, # distinct type
|
nkDistinctTy, # distinct type
|
||||||
nkProcTy,
|
nkProcTy,
|
||||||
nkEnumTy,
|
nkEnumTy,
|
||||||
|
|
@ -186,7 +189,7 @@ type
|
||||||
TNodeKinds* = set[TNodeKind]
|
TNodeKinds* = set[TNodeKind]
|
||||||
|
|
||||||
type
|
type
|
||||||
TSymFlag* = enum # already 29 flags!
|
TSymFlag* = enum # already 30 flags!
|
||||||
sfUsed, # read access of sym (for warnings) or simply used
|
sfUsed, # read access of sym (for warnings) or simply used
|
||||||
sfExported, # symbol is exported from module
|
sfExported, # symbol is exported from module
|
||||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||||
|
|
@ -212,6 +215,7 @@ type
|
||||||
sfProcvar, # proc can be passed to a proc var
|
sfProcvar, # proc can be passed to a proc var
|
||||||
sfDiscriminant, # field is a discriminant in a record/object
|
sfDiscriminant, # field is a discriminant in a record/object
|
||||||
sfDeprecated, # symbol is deprecated
|
sfDeprecated, # symbol is deprecated
|
||||||
|
sfError, # usage of symbol should trigger a compile-time error
|
||||||
sfInClosure, # variable is accessed by a closure
|
sfInClosure, # variable is accessed by a closure
|
||||||
sfThread, # proc will run as a thread
|
sfThread, # proc will run as a thread
|
||||||
sfCompileTime, # proc can be evaluated at compile time
|
sfCompileTime, # proc can be evaluated at compile time
|
||||||
|
|
@ -254,7 +258,12 @@ type
|
||||||
tyPointer, tyOpenArray,
|
tyPointer, tyOpenArray,
|
||||||
tyString, tyCString, tyForward,
|
tyString, tyCString, tyForward,
|
||||||
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
|
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
|
||||||
tyFloat, tyFloat32, tyFloat64, tyFloat128
|
tyFloat, tyFloat32, tyFloat64, tyFloat128,
|
||||||
|
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
|
||||||
|
tyBigNum,
|
||||||
|
tyConst, tyMutable, tyVarargs,
|
||||||
|
tyIter, # unused
|
||||||
|
tyProxy # currently unused
|
||||||
|
|
||||||
TTypeKinds* = set[TTypeKind]
|
TTypeKinds* = set[TTypeKind]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,94 +30,8 @@ const
|
||||||
"Copyright (c) 2004-2011 by Andreas Rumpf\n"
|
"Copyright (c) 2004-2011 by Andreas Rumpf\n"
|
||||||
|
|
||||||
const
|
const
|
||||||
Usage = """
|
Usage = slurp"doc/basicopt.txt".replace("//", "")
|
||||||
Usage:
|
AdvancedUsage = slurp"doc/advopt.txt".replace("//", "")
|
||||||
nimrod command [options] [projectfile] [arguments]
|
|
||||||
Command:
|
|
||||||
compile, c compile project with default code generator (C)
|
|
||||||
doc generate the documentation for inputfile
|
|
||||||
i start Nimrod in interactive mode (limited)
|
|
||||||
Arguments:
|
|
||||||
arguments are passed to the program being run (if --run option is selected)
|
|
||||||
Options:
|
|
||||||
-p, --path:PATH add path to search paths
|
|
||||||
-d, --define:SYMBOL define a conditional symbol
|
|
||||||
-u, --undef:SYMBOL undefine a conditional symbol
|
|
||||||
-f, --forceBuild force rebuilding of all modules
|
|
||||||
--stackTrace:on|off turn stack tracing on|off
|
|
||||||
--lineTrace:on|off turn line tracing on|off
|
|
||||||
--threads:on|off turn support for multi-threading on|off
|
|
||||||
-x, --checks:on|off turn all runtime checks on|off
|
|
||||||
--objChecks:on|off turn obj conversion checks on|off
|
|
||||||
--fieldChecks:on|off turn case variant field checks on|off
|
|
||||||
--rangeChecks:on|off turn range checks on|off
|
|
||||||
--boundChecks:on|off turn bound checks on|off
|
|
||||||
--overflowChecks:on|off turn int over-/underflow checks on|off
|
|
||||||
-a, --assertions:on|off turn assertions on|off
|
|
||||||
--floatChecks:on|off turn all floating point (NaN/Inf) checks on|off
|
|
||||||
--nanChecks:on|off turn NaN checks on|off
|
|
||||||
--infChecks:on|off turn Inf checks on|off
|
|
||||||
--deadCodeElim:on|off whole program dead code elimination on|off
|
|
||||||
--opt:none|speed|size optimize not at all or for speed|size
|
|
||||||
--app:console|gui|lib generate a console|GUI application|dynamic library
|
|
||||||
-r, --run run the compiled program with given arguments
|
|
||||||
--advanced show advanced command line switches
|
|
||||||
-h, --help show this help
|
|
||||||
"""
|
|
||||||
|
|
||||||
AdvancedUsage = """
|
|
||||||
Advanced commands:
|
|
||||||
compileToC, cc compile project with C code generator
|
|
||||||
compileToCpp, cpp compile project to C++ code
|
|
||||||
compileToOC, objc compile project to Objective C code
|
|
||||||
rst2html convert a reStructuredText file to HTML
|
|
||||||
rst2tex convert a reStructuredText file to TeX
|
|
||||||
run run the project (with Tiny C backend; buggy!)
|
|
||||||
pretty pretty print the inputfile
|
|
||||||
genDepend generate a DOT file containing the
|
|
||||||
module dependency graph
|
|
||||||
dump dump all defined conditionals and search paths
|
|
||||||
check checks the project for syntax and semantic
|
|
||||||
idetools compiler support for IDEs: possible options:
|
|
||||||
--track:FILE,LINE,COL track a file/cursor position
|
|
||||||
--suggest suggest all possible symbols at position
|
|
||||||
--def list all possible symbols at position
|
|
||||||
--context list possible invokation context
|
|
||||||
Advanced options:
|
|
||||||
-o, --out:FILE set the output filename
|
|
||||||
--stdout output to stdout
|
|
||||||
-w, --warnings:on|off turn all warnings on|off
|
|
||||||
--warning[X]:on|off turn specific warning X on|off
|
|
||||||
--hints:on|off turn all hints on|off
|
|
||||||
--hint[X]:on|off turn specific hint X on|off
|
|
||||||
--lib:PATH set the system library path
|
|
||||||
--nimcache:PATH set the path used for generated files
|
|
||||||
-c, --compileOnly compile only; do not assemble or link
|
|
||||||
--noLinking compile but do not link
|
|
||||||
--noMain do not generate a main procedure
|
|
||||||
--genScript generate a compile script (in the 'nimcache'
|
|
||||||
subdirectory named 'compile_$project$scriptext')
|
|
||||||
--os:SYMBOL set the target operating system (cross-compilation)
|
|
||||||
--cpu:SYMBOL set the target processor (cross-compilation)
|
|
||||||
--debuginfo enables debug information
|
|
||||||
--debugger:on|off turn Embedded Nimrod Debugger on|off
|
|
||||||
-t, --passc:OPTION pass an option to the C compiler
|
|
||||||
-l, --passl:OPTION pass an option to the linker
|
|
||||||
--genMapping generate a mapping file containing
|
|
||||||
(Nimrod, mangled) identifier pairs
|
|
||||||
--lineDir:on|off generation of #line directive on|off
|
|
||||||
--threadanalysis:on|off turn thread analysis on|off
|
|
||||||
--skipCfg do not read the general configuration file
|
|
||||||
--skipProjCfg do not read the project's configuration file
|
|
||||||
--gc:refc|boehm|none use Nimrod's native GC|Boehm GC|no GC
|
|
||||||
--index:FILE use FILE to generate a documentation index file
|
|
||||||
--putenv:key=value set an environment variable
|
|
||||||
--listCmd list the commands used to execute external programs
|
|
||||||
--parallelBuild=0|1|... perform a parallel build
|
|
||||||
value = number of processors (0 for auto-detect)
|
|
||||||
--verbosity:0|1|2|3 set Nimrod's verbosity level (0 is default)
|
|
||||||
-v, --version show detailed version information
|
|
||||||
"""
|
|
||||||
|
|
||||||
proc getCommandLineDesc(): string =
|
proc getCommandLineDesc(): string =
|
||||||
result = `%`(HelpMessage, [VersionAsString, platform.os[platform.hostOS].name,
|
result = `%`(HelpMessage, [VersionAsString, platform.os[platform.hostOS].name,
|
||||||
|
|
@ -276,6 +190,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||||
of "symbolfiles": result = contains(gGlobalOptions, optSymbolFiles)
|
of "symbolfiles": result = contains(gGlobalOptions, optSymbolFiles)
|
||||||
of "genscript": result = contains(gGlobalOptions, optGenScript)
|
of "genscript": result = contains(gGlobalOptions, optGenScript)
|
||||||
of "threads": result = contains(gGlobalOptions, optThreads)
|
of "threads": result = contains(gGlobalOptions, optThreads)
|
||||||
|
of "taintmode": result = contains(gGlobalOptions, optTaintMode)
|
||||||
else: InvalidCmdLineOption(passCmd1, switch, info)
|
else: InvalidCmdLineOption(passCmd1, switch, info)
|
||||||
|
|
||||||
proc processPath(path: string): string =
|
proc processPath(path: string): string =
|
||||||
|
|
@ -399,6 +314,7 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
|
||||||
of "assertions", "a": ProcessOnOffSwitch({optAssert}, arg, pass, info)
|
of "assertions", "a": ProcessOnOffSwitch({optAssert}, arg, pass, info)
|
||||||
of "deadcodeelim": ProcessOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
|
of "deadcodeelim": ProcessOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
|
||||||
of "threads": ProcessOnOffSwitchG({optThreads}, arg, pass, info)
|
of "threads": ProcessOnOffSwitchG({optThreads}, arg, pass, info)
|
||||||
|
of "taintmode": ProcessOnOffSwitchG({optTaintMode}, arg, pass, info)
|
||||||
of "opt":
|
of "opt":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ type
|
||||||
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
|
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
|
||||||
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
|
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
|
||||||
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
|
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
|
||||||
errXhasSideEffects, errIteratorExpected,
|
errXhasSideEffects, errIteratorExpected, errWrongSymbolX,
|
||||||
errUser,
|
errUser,
|
||||||
warnCannotOpenFile,
|
warnCannotOpenFile,
|
||||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||||
|
|
@ -315,6 +315,7 @@ const
|
||||||
errXisNoMacroOrTemplate: "\'$1\' is no macro or template",
|
errXisNoMacroOrTemplate: "\'$1\' is no macro or template",
|
||||||
errXhasSideEffects: "\'$1\' can have side effects",
|
errXhasSideEffects: "\'$1\' can have side effects",
|
||||||
errIteratorExpected: "iterator within for loop context expected",
|
errIteratorExpected: "iterator within for loop context expected",
|
||||||
|
errWrongSymbolX: "usage of \'$1\' is a user-defined error",
|
||||||
errUser: "$1",
|
errUser: "$1",
|
||||||
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
||||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
|
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,8 @@ type # please make sure we have under 32 options
|
||||||
optSuggest, # ideTools: 'suggest'
|
optSuggest, # ideTools: 'suggest'
|
||||||
optContext, # ideTools: 'context'
|
optContext, # ideTools: 'context'
|
||||||
optDef, # ideTools: 'def'
|
optDef, # ideTools: 'def'
|
||||||
optThreadAnalysis # thread analysis pass
|
optThreadAnalysis, # thread analysis pass
|
||||||
|
optTaintMode # taint mode turned on
|
||||||
|
|
||||||
TGlobalOptions* = set[TGlobalOption]
|
TGlobalOptions* = set[TGlobalOption]
|
||||||
TCommands* = enum # Nimrod's commands
|
TCommands* = enum # Nimrod's commands
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,15 @@ const
|
||||||
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
|
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
|
||||||
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
|
||||||
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
|
||||||
wNoStackFrame}
|
wNoStackFrame, wError}
|
||||||
converterPragmas* = procPragmas
|
converterPragmas* = procPragmas
|
||||||
methodPragmas* = procPragmas
|
methodPragmas* = procPragmas
|
||||||
macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||||
wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
|
wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern,
|
||||||
wImportcpp, wImportobjc}
|
wImportcpp, wImportobjc, wError}
|
||||||
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
|
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
|
||||||
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
|
||||||
wImportcpp, wImportobjc}
|
wImportcpp, wImportobjc, wError}
|
||||||
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
|
||||||
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir,
|
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir,
|
||||||
wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal,
|
wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal,
|
||||||
|
|
@ -43,14 +43,14 @@ const
|
||||||
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame}
|
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame}
|
||||||
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
|
||||||
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow,
|
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow,
|
||||||
wImportcpp, wImportobjc}
|
wImportcpp, wImportobjc, wError}
|
||||||
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
|
||||||
wImportcpp, wImportobjc}
|
wImportcpp, wImportobjc, wError}
|
||||||
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
|
||||||
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern,
|
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern,
|
||||||
wImportcpp, wImportobjc}
|
wImportcpp, wImportobjc, wError}
|
||||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||||
wExtern, wImportcpp, wImportobjc}
|
wExtern, wImportcpp, wImportobjc, wError}
|
||||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
|
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
|
||||||
wThread}
|
wThread}
|
||||||
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
|
||||||
|
|
@ -530,7 +530,12 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
if sym.typ != nil: incl(sym.typ.flags, tfThread)
|
if sym.typ != nil: incl(sym.typ.flags, tfThread)
|
||||||
of wHint: Message(it.info, hintUser, expectStrLit(c, it))
|
of wHint: Message(it.info, hintUser, expectStrLit(c, it))
|
||||||
of wWarning: Message(it.info, warnUser, expectStrLit(c, it))
|
of wWarning: Message(it.info, warnUser, expectStrLit(c, it))
|
||||||
of wError: LocalError(it.info, errUser, expectStrLit(c, it))
|
of wError:
|
||||||
|
if sym != nil:
|
||||||
|
noVal(it)
|
||||||
|
incl(sym.flags, sfError)
|
||||||
|
else:
|
||||||
|
LocalError(it.info, errUser, expectStrLit(c, it))
|
||||||
of wFatal: Fatal(it.info, errUser, expectStrLit(c, it))
|
of wFatal: Fatal(it.info, errUser, expectStrLit(c, it))
|
||||||
of wDefine: processDefine(c, it)
|
of wDefine: processDefine(c, it)
|
||||||
of wUndef: processUndef(c, it)
|
of wUndef: processUndef(c, it)
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,9 @@ proc makeRangeType(c: PContext, first, last: biggestInt,
|
||||||
|
|
||||||
proc markUsed*(n: PNode, s: PSym) =
|
proc markUsed*(n: PNode, s: PSym) =
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
|
if {sfDeprecated, sfError} * s.flags != {}:
|
||||||
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
|
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
|
||||||
|
if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s)
|
||||||
|
|
||||||
proc illFormedAst*(n: PNode) =
|
proc illFormedAst*(n: PNode) =
|
||||||
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
GlobalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
|
||||||
proc checkConvertible(info: TLineInfo, castDest, src: PType) =
|
proc checkConvertible(info: TLineInfo, castDest, src: PType) =
|
||||||
const
|
const
|
||||||
IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyFloat128}
|
IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyFloat128}
|
||||||
if sameType(castDest, src):
|
if sameType(castDest, src) and castDest.sym == src.sym:
|
||||||
# don't annoy conversions that may be needed on another processor:
|
# don't annoy conversions that may be needed on another processor:
|
||||||
if not (castDest.kind in {tyInt..tyFloat128, tyNil}):
|
if not (castDest.kind in {tyInt..tyFloat128, tyNil}):
|
||||||
Message(info, hintConvFromXtoItselfNotNeeded, typeToString(castDest))
|
Message(info, hintConvFromXtoItselfNotNeeded, typeToString(castDest))
|
||||||
|
|
|
||||||
|
|
@ -50,16 +50,19 @@ proc equalParams*(a, b: PNode): TParamsEquality
|
||||||
proc isOrdinalType*(t: PType): bool
|
proc isOrdinalType*(t: PType): bool
|
||||||
proc enumHasHoles*(t: PType): bool
|
proc enumHasHoles*(t: PType): bool
|
||||||
const
|
const
|
||||||
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal}
|
abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
|
||||||
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal}
|
tyConst, tyMutable}
|
||||||
abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal}
|
abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
|
||||||
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal}
|
tyConst, tyMutable}
|
||||||
abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal}
|
abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal,
|
||||||
|
tyConst, tyMutable}
|
||||||
|
abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
|
||||||
|
tyConst, tyMutable}
|
||||||
|
abstractInst* = {tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable}
|
||||||
|
|
||||||
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst}
|
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable}
|
||||||
|
|
||||||
proc skipTypes*(t: PType, kinds: TTypeKinds): PType
|
proc skipTypes*(t: PType, kinds: TTypeKinds): PType
|
||||||
proc elemType*(t: PType): PType
|
|
||||||
proc containsObject*(t: PType): bool
|
proc containsObject*(t: PType): bool
|
||||||
proc containsGarbageCollectedRef*(typ: PType): bool
|
proc containsGarbageCollectedRef*(typ: PType): bool
|
||||||
proc containsHiddenPointer*(typ: PType): bool
|
proc containsHiddenPointer*(typ: PType): bool
|
||||||
|
|
@ -122,10 +125,11 @@ proc getOrdValue(n: PNode): biggestInt =
|
||||||
result = 0
|
result = 0
|
||||||
|
|
||||||
proc isCompatibleToCString(a: PType): bool =
|
proc isCompatibleToCString(a: PType): bool =
|
||||||
result = false
|
|
||||||
if a.kind == tyArray:
|
if a.kind == tyArray:
|
||||||
if (firstOrd(a.sons[0]) == 0) and
|
if (firstOrd(a.sons[0]) == 0) and
|
||||||
(skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and
|
(skipTypes(a.sons[0], {tyRange, tyConst,
|
||||||
|
tyMutable, tyGenericInst}).kind in
|
||||||
|
{tyInt..tyInt64, tyUInt..tyUInt64}) and
|
||||||
(a.sons[1].kind == tyChar):
|
(a.sons[1].kind == tyChar):
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
|
@ -142,7 +146,7 @@ proc getProcHeader(sym: PSym): string =
|
||||||
add(result, ')')
|
add(result, ')')
|
||||||
if n.sons[0].typ != nil: result.add(": " & typeToString(n.sons[0].typ))
|
if n.sons[0].typ != nil: result.add(": " & typeToString(n.sons[0].typ))
|
||||||
|
|
||||||
proc elemType(t: PType): PType =
|
proc elemType*(t: PType): PType =
|
||||||
assert(t != nil)
|
assert(t != nil)
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyGenericInst, tyDistinct: result = elemType(lastSon(t))
|
of tyGenericInst, tyDistinct: result = elemType(lastSon(t))
|
||||||
|
|
@ -154,35 +158,6 @@ proc skipGeneric(t: PType): PType =
|
||||||
result = t
|
result = t
|
||||||
while result.kind == tyGenericInst: result = lastSon(result)
|
while result.kind == tyGenericInst: result = lastSon(result)
|
||||||
|
|
||||||
proc skipRange(t: PType): PType =
|
|
||||||
result = t
|
|
||||||
while result.kind == tyRange: result = base(result)
|
|
||||||
|
|
||||||
proc skipAbstract(t: PType): PType =
|
|
||||||
result = t
|
|
||||||
while result.kind in {tyRange, tyGenericInst}: result = lastSon(result)
|
|
||||||
|
|
||||||
proc skipVar(t: PType): PType =
|
|
||||||
result = t
|
|
||||||
while result.kind == tyVar: result = result.sons[0]
|
|
||||||
|
|
||||||
proc skipVarGeneric(t: PType): PType =
|
|
||||||
result = t
|
|
||||||
while result.kind in {tyGenericInst, tyVar}: result = lastSon(result)
|
|
||||||
|
|
||||||
proc skipPtrsGeneric(t: PType): PType =
|
|
||||||
result = t
|
|
||||||
while result.kind in {tyGenericInst, tyVar, tyPtr, tyRef}:
|
|
||||||
result = lastSon(result)
|
|
||||||
|
|
||||||
proc skipVarGenericRange(t: PType): PType =
|
|
||||||
result = t
|
|
||||||
while result.kind in {tyGenericInst, tyVar, tyRange}: result = lastSon(result)
|
|
||||||
|
|
||||||
proc skipGenericRange(t: PType): PType =
|
|
||||||
result = t
|
|
||||||
while result.kind in {tyGenericInst, tyVar, tyRange}: result = lastSon(result)
|
|
||||||
|
|
||||||
proc skipTypes(t: PType, kinds: TTypeKinds): PType =
|
proc skipTypes(t: PType, kinds: TTypeKinds): PType =
|
||||||
result = t
|
result = t
|
||||||
while result.kind in kinds: result = lastSon(result)
|
while result.kind in kinds: result = lastSon(result)
|
||||||
|
|
@ -190,18 +165,18 @@ proc skipTypes(t: PType, kinds: TTypeKinds): PType =
|
||||||
proc isOrdinalType(t: PType): bool =
|
proc isOrdinalType(t: PType): bool =
|
||||||
assert(t != nil)
|
assert(t != nil)
|
||||||
result = (t.Kind in {tyChar, tyInt..tyInt64, tyBool, tyEnum}) or
|
result = (t.Kind in {tyChar, tyInt..tyInt64, tyBool, tyEnum}) or
|
||||||
(t.Kind in {tyRange, tyOrdinal}) and isOrdinalType(t.sons[0])
|
(t.Kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and
|
||||||
|
isOrdinalType(t.sons[0])
|
||||||
|
|
||||||
proc enumHasHoles(t: PType): bool =
|
proc enumHasHoles(t: PType): bool =
|
||||||
var b = t
|
var b = t
|
||||||
while b.kind == tyRange: b = b.sons[0]
|
while b.kind in {tyConst, tyMutable, tyRange, tyGenericInst}: b = b.sons[0]
|
||||||
result = b.Kind == tyEnum and tfEnumHasHoles in b.flags
|
result = b.Kind == tyEnum and tfEnumHasHoles in b.flags
|
||||||
|
|
||||||
proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter,
|
proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter,
|
||||||
closure: PObject): bool
|
closure: PObject): bool
|
||||||
proc iterOverNode(marker: var TIntSet, n: PNode, iter: TTypeIter,
|
proc iterOverNode(marker: var TIntSet, n: PNode, iter: TTypeIter,
|
||||||
closure: PObject): bool =
|
closure: PObject): bool =
|
||||||
result = false
|
|
||||||
if n != nil:
|
if n != nil:
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkNone..nkNilLit:
|
of nkNone..nkNilLit:
|
||||||
|
|
@ -289,9 +264,9 @@ proc containsObject(t: PType): bool =
|
||||||
result = searchTypeFor(t, isObjectPredicate)
|
result = searchTypeFor(t, isObjectPredicate)
|
||||||
|
|
||||||
proc isObjectWithTypeFieldPredicate(t: PType): bool =
|
proc isObjectWithTypeFieldPredicate(t: PType): bool =
|
||||||
result = (t.kind == tyObject) and (t.sons[0] == nil) and
|
result = t.kind == tyObject and t.sons[0] == nil and
|
||||||
not ((t.sym != nil) and (sfPure in t.sym.flags)) and
|
not (t.sym != nil and sfPure in t.sym.flags) and
|
||||||
not (tfFinal in t.flags)
|
tfFinal notin t.flags
|
||||||
|
|
||||||
proc analyseObjectWithTypeFieldAux(t: PType,
|
proc analyseObjectWithTypeFieldAux(t: PType,
|
||||||
marker: var TIntSet): TTypeFieldResult =
|
marker: var TIntSet): TTypeFieldResult =
|
||||||
|
|
@ -310,7 +285,7 @@ proc analyseObjectWithTypeFieldAux(t: PType,
|
||||||
if res == frHeader: result = frHeader
|
if res == frHeader: result = frHeader
|
||||||
if result == frNone:
|
if result == frNone:
|
||||||
if isObjectWithTypeFieldPredicate(t): result = frHeader
|
if isObjectWithTypeFieldPredicate(t): result = frHeader
|
||||||
of tyGenericInst, tyDistinct:
|
of tyGenericInst, tyDistinct, tyConst, tyMutable:
|
||||||
result = analyseObjectWithTypeFieldAux(lastSon(t), marker)
|
result = analyseObjectWithTypeFieldAux(lastSon(t), marker)
|
||||||
of tyArray, tyArrayConstr, tyTuple:
|
of tyArray, tyArrayConstr, tyTuple:
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
|
|
@ -406,8 +381,6 @@ proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator,
|
||||||
if not ContainsOrIncl(marker, t.id):
|
if not ContainsOrIncl(marker, t.id):
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure)
|
result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure)
|
||||||
if (result.sons[i] == nil) and (result.kind == tyGenericInst):
|
|
||||||
assert(false)
|
|
||||||
if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure)
|
if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure)
|
||||||
assert(result != nil)
|
assert(result != nil)
|
||||||
|
|
||||||
|
|
@ -427,7 +400,10 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
|
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
|
||||||
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
|
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
|
||||||
"pointer", "OpenArray[$1]", "string", "CString", "Forward", "int", "int8",
|
"pointer", "OpenArray[$1]", "string", "CString", "Forward", "int", "int8",
|
||||||
"int16", "int32", "int64", "float", "float32", "float64", "float128"]
|
"int16", "int32", "int64", "float", "float32", "float64", "float128",
|
||||||
|
|
||||||
|
"uint", "uint8", "uint16", "uint32", "uint64", "bignum", "const ",
|
||||||
|
"!", "varargs[$1]", "iter[$1]", "proxy[$1]"]
|
||||||
var t = typ
|
var t = typ
|
||||||
result = ""
|
result = ""
|
||||||
if t == nil: return
|
if t == nil: return
|
||||||
|
|
@ -474,7 +450,7 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
add(result, typeToString(t.sons[i]))
|
add(result, typeToString(t.sons[i]))
|
||||||
if i < sonsLen(t) - 1: add(result, ", ")
|
if i < sonsLen(t) - 1: add(result, ", ")
|
||||||
add(result, ']')
|
add(result, ']')
|
||||||
of tyPtr, tyRef, tyVar:
|
of tyPtr, tyRef, tyVar, tyMutable, tyConst:
|
||||||
result = typeToStr[t.kind] & typeToString(t.sons[0])
|
result = typeToStr[t.kind] & typeToString(t.sons[0])
|
||||||
of tyRange:
|
of tyRange:
|
||||||
result = "range " & rangeToStr(t.n)
|
result = "range " & rangeToStr(t.n)
|
||||||
|
|
@ -495,6 +471,8 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||||
addSep(prag)
|
addSep(prag)
|
||||||
add(prag, "thread")
|
add(prag, "thread")
|
||||||
if len(prag) != 0: add(result, "{." & prag & ".}")
|
if len(prag) != 0: add(result, "{." & prag & ".}")
|
||||||
|
of tyVarargs, tyIter, tyProxy:
|
||||||
|
result = typeToStr[t.kind] % typeToString(t.sons[0])
|
||||||
else:
|
else:
|
||||||
result = typeToStr[t.kind]
|
result = typeToStr[t.kind]
|
||||||
|
|
||||||
|
|
@ -528,7 +506,8 @@ proc firstOrd(t: PType): biggestInt =
|
||||||
else:
|
else:
|
||||||
assert(t.n.sons[0].kind == nkSym)
|
assert(t.n.sons[0].kind == nkSym)
|
||||||
result = t.n.sons[0].sym.position
|
result = t.n.sons[0].sym.position
|
||||||
of tyGenericInst, tyDistinct: result = firstOrd(lastSon(t))
|
of tyGenericInst, tyDistinct, tyConst, tyMutable:
|
||||||
|
result = firstOrd(lastSon(t))
|
||||||
else:
|
else:
|
||||||
InternalError("invalid kind for first(" & $t.kind & ')')
|
InternalError("invalid kind for first(" & $t.kind & ')')
|
||||||
result = 0
|
result = 0
|
||||||
|
|
@ -553,7 +532,8 @@ proc lastOrd(t: PType): biggestInt =
|
||||||
of tyEnum:
|
of tyEnum:
|
||||||
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
||||||
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
||||||
of tyGenericInst, tyDistinct: result = lastOrd(lastSon(t))
|
of tyGenericInst, tyDistinct, tyConst, tyMutable:
|
||||||
|
result = lastOrd(lastSon(t))
|
||||||
else:
|
else:
|
||||||
InternalError("invalid kind for last(" & $t.kind & ')')
|
InternalError("invalid kind for last(" & $t.kind & ')')
|
||||||
result = 0
|
result = 0
|
||||||
|
|
@ -561,19 +541,19 @@ proc lastOrd(t: PType): biggestInt =
|
||||||
proc lengthOrd(t: PType): biggestInt =
|
proc lengthOrd(t: PType): biggestInt =
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyInt64, tyInt32, tyInt: result = lastOrd(t)
|
of tyInt64, tyInt32, tyInt: result = lastOrd(t)
|
||||||
of tyDistinct: result = lengthOrd(t.sons[0])
|
of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0])
|
||||||
else: result = lastOrd(t) - firstOrd(t) + 1
|
else: result = lastOrd(t) - firstOrd(t) + 1
|
||||||
|
|
||||||
proc equalParam(a, b: PSym): TParamsEquality =
|
proc equalParam(a, b: PSym): TParamsEquality =
|
||||||
if SameTypeOrNil(a.typ, b.typ):
|
if SameTypeOrNil(a.typ, b.typ):
|
||||||
if (a.ast == b.ast):
|
if a.ast == b.ast:
|
||||||
result = paramsEqual
|
result = paramsEqual
|
||||||
elif (a.ast != nil) and (b.ast != nil):
|
elif a.ast != nil and b.ast != nil:
|
||||||
if ExprStructuralEquivalent(a.ast, b.ast): result = paramsEqual
|
if ExprStructuralEquivalent(a.ast, b.ast): result = paramsEqual
|
||||||
else: result = paramsIncompatible
|
else: result = paramsIncompatible
|
||||||
elif (a.ast != nil):
|
elif a.ast != nil:
|
||||||
result = paramsEqual
|
result = paramsEqual
|
||||||
elif (b.ast != nil):
|
elif b.ast != nil:
|
||||||
result = paramsIncompatible
|
result = paramsIncompatible
|
||||||
else:
|
else:
|
||||||
result = paramsNotEqual
|
result = paramsNotEqual
|
||||||
|
|
@ -611,11 +591,10 @@ proc SameTypeOrNil(a, b: PType): bool =
|
||||||
if a == b:
|
if a == b:
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
if (a == nil) or (b == nil): result = false
|
if a == nil or b == nil: result = false
|
||||||
else: result = SameType(a, b)
|
else: result = SameType(a, b)
|
||||||
|
|
||||||
proc SameLiteral(x, y: PNode): bool =
|
proc SameLiteral(x, y: PNode): bool =
|
||||||
result = false
|
|
||||||
if x.kind == y.kind:
|
if x.kind == y.kind:
|
||||||
case x.kind
|
case x.kind
|
||||||
of nkCharLit..nkInt64Lit: result = x.intVal == y.intVal
|
of nkCharLit..nkInt64Lit: result = x.intVal == y.intVal
|
||||||
|
|
@ -637,7 +616,7 @@ proc sameTuple(a, b: PType, DistinctOf: bool): bool =
|
||||||
if DistinctOf: result = equalOrDistinctOf(a.sons[i], b.sons[i])
|
if DistinctOf: result = equalOrDistinctOf(a.sons[i], b.sons[i])
|
||||||
else: result = SameType(a.sons[i], b.sons[i])
|
else: result = SameType(a.sons[i], b.sons[i])
|
||||||
if not result: return
|
if not result: return
|
||||||
if (a.n != nil) and (b.n != nil):
|
if a.n != nil and b.n != nil:
|
||||||
for i in countup(0, sonsLen(a.n) - 1):
|
for i in countup(0, sonsLen(a.n) - 1):
|
||||||
# check field names:
|
# check field names:
|
||||||
if a.n.sons[i].kind != nkSym: InternalError(a.n.info, "sameTuple")
|
if a.n.sons[i].kind != nkSym: InternalError(a.n.info, "sameTuple")
|
||||||
|
|
@ -659,13 +638,14 @@ proc SameType(x, y: PType): bool =
|
||||||
return false
|
return false
|
||||||
case a.Kind
|
case a.Kind
|
||||||
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
||||||
tyInt..tyFloat128, tyExpr, tyStmt, tyTypeDesc:
|
tyInt..tyBigNum, tyExpr, tyStmt, tyTypeDesc:
|
||||||
result = true
|
result = true
|
||||||
of tyEnum, tyForward, tyObject, tyDistinct: result = (a.id == b.id)
|
of tyEnum, tyForward, tyObject, tyDistinct, tyProxy: result = (a.id == b.id)
|
||||||
of tyTuple: result = sameTuple(a, b, false)
|
of tyTuple: result = sameTuple(a, b, false)
|
||||||
of tyGenericInst: result = sameType(lastSon(a), lastSon(b))
|
of tyGenericInst: result = sameType(lastSon(a), lastSon(b))
|
||||||
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, tyOrdinal,
|
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, tyOrdinal,
|
||||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc:
|
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc,
|
||||||
|
tyConst, tyMutable, tyVarargs, tyIter:
|
||||||
if sonsLen(a) == sonsLen(b):
|
if sonsLen(a) == sonsLen(b):
|
||||||
result = true
|
result = true
|
||||||
for i in countup(0, sonsLen(a) - 1):
|
for i in countup(0, sonsLen(a) - 1):
|
||||||
|
|
@ -694,13 +674,14 @@ proc equalOrDistinctOf(x, y: PType): bool =
|
||||||
return false
|
return false
|
||||||
case a.Kind
|
case a.Kind
|
||||||
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
|
||||||
tyInt..tyFloat128, tyExpr, tyStmt, tyTypeDesc:
|
tyInt..tyBigNum, tyExpr, tyStmt, tyTypeDesc:
|
||||||
result = true
|
result = true
|
||||||
of tyEnum, tyForward, tyObject, tyDistinct: result = (a.id == b.id)
|
of tyEnum, tyForward, tyObject, tyDistinct, tyProxy: result = (a.id == b.id)
|
||||||
of tyTuple: result = sameTuple(a, b, true)
|
of tyTuple: result = sameTuple(a, b, true)
|
||||||
of tyGenericInst: result = equalOrDistinctOf(lastSon(a), lastSon(b))
|
of tyGenericInst: result = equalOrDistinctOf(lastSon(a), lastSon(b))
|
||||||
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, tyOrdinal,
|
of tyGenericParam, tyGenericInvokation, tyGenericBody, tySequence, tyOrdinal,
|
||||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc:
|
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc,
|
||||||
|
tyConst, tyMutable, tyVarargs, tyIter:
|
||||||
if sonsLen(a) == sonsLen(b):
|
if sonsLen(a) == sonsLen(b):
|
||||||
result = true
|
result = true
|
||||||
for i in countup(0, sonsLen(a) - 1):
|
for i in countup(0, sonsLen(a) - 1):
|
||||||
|
|
@ -769,7 +750,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||||
result = false #InternalError('shit found');
|
result = false #InternalError('shit found');
|
||||||
of tyEmpty, tyNil:
|
of tyEmpty, tyNil:
|
||||||
result = kind == skConst
|
result = kind == skConst
|
||||||
of tyString, tyBool, tyChar, tyEnum, tyInt..tyFloat128, tyCString, tyPointer:
|
of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:
|
||||||
result = true
|
result = true
|
||||||
of tyOrdinal:
|
of tyOrdinal:
|
||||||
result = kind == skParam
|
result = kind == skParam
|
||||||
|
|
@ -778,7 +759,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||||
of tyRange:
|
of tyRange:
|
||||||
result = skipTypes(t.sons[0], abstractInst).kind in
|
result = skipTypes(t.sons[0], abstractInst).kind in
|
||||||
{tyChar, tyEnum, tyInt..tyFloat128}
|
{tyChar, tyEnum, tyInt..tyFloat128}
|
||||||
of tyOpenArray:
|
of tyOpenArray, tyVarargs:
|
||||||
result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar)
|
result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
result = (kind != skConst) and typeAllowedAux(marker, t.sons[0], skVar) or
|
result = (kind != skConst) and typeAllowedAux(marker, t.sons[0], skVar) or
|
||||||
|
|
@ -788,7 +769,7 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
|
||||||
t.sons[1].kind == tyEmpty
|
t.sons[1].kind == tyEmpty
|
||||||
of tyPtr, tyRef:
|
of tyPtr, tyRef:
|
||||||
result = typeAllowedAux(marker, t.sons[0], skVar)
|
result = typeAllowedAux(marker, t.sons[0], skVar)
|
||||||
of tyArrayConstr, tyTuple, tySet:
|
of tyArrayConstr, tyTuple, tySet, tyConst, tyMutable, tyIter, tyProxy:
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
result = typeAllowedAux(marker, t.sons[i], kind)
|
result = typeAllowedAux(marker, t.sons[i], kind)
|
||||||
if not result: break
|
if not result: break
|
||||||
|
|
@ -856,19 +837,19 @@ proc computeSizeAux(typ: PType, a: var biggestInt): biggestInt =
|
||||||
return
|
return
|
||||||
typ.size = - 2 # mark as being computed
|
typ.size = - 2 # mark as being computed
|
||||||
case typ.kind
|
case typ.kind
|
||||||
of tyInt:
|
of tyInt, tyUInt:
|
||||||
result = IntSize
|
result = IntSize
|
||||||
a = result
|
a = result
|
||||||
of tyInt8, tyBool, tyChar:
|
of tyInt8, tyUInt8, tyBool, tyChar:
|
||||||
result = 1
|
result = 1
|
||||||
a = result
|
a = result
|
||||||
of tyInt16:
|
of tyInt16, tyUInt16:
|
||||||
result = 2
|
result = 2
|
||||||
a = result
|
a = result
|
||||||
of tyInt32, tyFloat32:
|
of tyInt32, tyUInt32, tyFloat32:
|
||||||
result = 4
|
result = 4
|
||||||
a = result
|
a = result
|
||||||
of tyInt64, tyFloat64:
|
of tyInt64, tyUInt64, tyFloat64:
|
||||||
result = 8
|
result = 8
|
||||||
a = result
|
a = result
|
||||||
of tyFloat:
|
of tyFloat:
|
||||||
|
|
@ -878,7 +859,8 @@ proc computeSizeAux(typ: PType, a: var biggestInt): biggestInt =
|
||||||
if typ.callConv == ccClosure: result = 2 * ptrSize
|
if typ.callConv == ccClosure: result = 2 * ptrSize
|
||||||
else: result = ptrSize
|
else: result = ptrSize
|
||||||
a = ptrSize
|
a = ptrSize
|
||||||
of tyNil, tyCString, tyString, tySequence, tyPtr, tyRef, tyVar, tyOpenArray:
|
of tyNil, tyCString, tyString, tySequence, tyPtr, tyRef, tyVar, tyOpenArray,
|
||||||
|
tyBigNum:
|
||||||
result = ptrSize
|
result = ptrSize
|
||||||
a = result
|
a = result
|
||||||
of tyArray, tyArrayConstr:
|
of tyArray, tyArrayConstr:
|
||||||
|
|
@ -930,7 +912,8 @@ proc computeSizeAux(typ: PType, a: var biggestInt): biggestInt =
|
||||||
if result < 0: return
|
if result < 0: return
|
||||||
if a < maxAlign: a = maxAlign
|
if a < maxAlign: a = maxAlign
|
||||||
result = align(result, a)
|
result = align(result, a)
|
||||||
of tyGenericInst, tyDistinct, tyGenericBody:
|
of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter,
|
||||||
|
tyProxy:
|
||||||
result = computeSizeAux(lastSon(typ), a)
|
result = computeSizeAux(lastSon(typ), a)
|
||||||
else:
|
else:
|
||||||
#internalError("computeSizeAux()")
|
#internalError("computeSizeAux()")
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ Advanced options:
|
||||||
(Nimrod, mangled) identifier pairs
|
(Nimrod, mangled) identifier pairs
|
||||||
--lineDir:on|off generation of #line directive on|off
|
--lineDir:on|off generation of #line directive on|off
|
||||||
--threadanalysis:on|off turn thread analysis on|off
|
--threadanalysis:on|off turn thread analysis on|off
|
||||||
|
--taintMode:on|off turn taint mode on|off
|
||||||
--skipCfg do not read the general configuration file
|
--skipCfg do not read the general configuration file
|
||||||
--skipProjCfg do not read the project's configuration file
|
--skipProjCfg do not read the project's configuration file
|
||||||
--gc:refc|boehm|none use Nimrod's native GC|Boehm GC|no GC
|
--gc:refc|boehm|none use Nimrod's native GC|Boehm GC|no GC
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,8 @@ have no side-effect can be used in constant expressions too:
|
||||||
The rules for compile-time computability are:
|
The rules for compile-time computability are:
|
||||||
|
|
||||||
1. Literals are compile-time computable.
|
1. Literals are compile-time computable.
|
||||||
2. Procedure calls of the form ``p(X)`` are compile-time computable if
|
2. Type conversions are compile-time computable.
|
||||||
|
3. Procedure calls of the form ``p(X)`` are compile-time computable if
|
||||||
``p`` is a proc without side-effects (see the `noSideEffect pragma`_
|
``p`` is a proc without side-effects (see the `noSideEffect pragma`_
|
||||||
for details) and if ``X`` is a (possibly empty) list of compile-time
|
for details) and if ``X`` is a (possibly empty) list of compile-time
|
||||||
computable arguments.
|
computable arguments.
|
||||||
|
|
@ -1207,7 +1208,7 @@ Void type
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
The `void`:idx: type denotes the absense of any type. Parameters of
|
The `void`:idx: type denotes the absense of any type. Parameters of
|
||||||
type ``void`` are treated as non-existent, a result ``void`` type means that
|
type ``void`` are treated as non-existent, ``void`` as a return type means that
|
||||||
the procedure does not return a value:
|
the procedure does not return a value:
|
||||||
|
|
||||||
.. code-block:: nimrod
|
.. code-block:: nimrod
|
||||||
|
|
@ -1295,6 +1296,48 @@ Since types are graphs which can have cycles, the above algorithm needs an
|
||||||
auxiliary set ``s`` to detect this case.
|
auxiliary set ``s`` to detect this case.
|
||||||
|
|
||||||
|
|
||||||
|
Type equality modulo type distinction
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The following algorithm (in pseudo-code) determines whether two types
|
||||||
|
are equal with no respect to ``distinct`` types. For brevity the cycle check
|
||||||
|
with an auxiliary set ``s`` is omitted:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
proc typeEqualsOrDistinct(a, b: PType): bool =
|
||||||
|
if a.kind == b.kind:
|
||||||
|
case a.kind
|
||||||
|
of int, intXX, float, floatXX, char, string, cstring, pointer,
|
||||||
|
bool, nil, void:
|
||||||
|
# leaf type: kinds identical; nothing more to check
|
||||||
|
result = true
|
||||||
|
of ref, ptr, var, set, seq, openarray:
|
||||||
|
result = typeEqualsOrDistinct(a.baseType, b.baseType)
|
||||||
|
of range:
|
||||||
|
result = typeEqualsOrDistinct(a.baseType, b.baseType) and
|
||||||
|
(a.rangeA == b.rangeA) and (a.rangeB == b.rangeB)
|
||||||
|
of array:
|
||||||
|
result = typeEqualsOrDistinct(a.baseType, b.baseType) and
|
||||||
|
typeEqualsOrDistinct(a.indexType, b.indexType)
|
||||||
|
of tuple:
|
||||||
|
if a.tupleLen == b.tupleLen:
|
||||||
|
for i in 0..a.tupleLen-1:
|
||||||
|
if not typeEqualsOrDistinct(a[i], b[i]): return false
|
||||||
|
result = true
|
||||||
|
of distinct:
|
||||||
|
result = typeEqualsOrDistinct(a.baseType, b.baseType)
|
||||||
|
of object, enum:
|
||||||
|
result = a == b
|
||||||
|
of proc:
|
||||||
|
result = typeEqualsOrDistinct(a.parameterTuple, b.parameterTuple) and
|
||||||
|
typeEqualsOrDistinct(a.resultType, b.resultType) and
|
||||||
|
a.callingConvention == b.callingConvention
|
||||||
|
elif a.kind == distinct:
|
||||||
|
result = typeEqualsOrDistinct(a.baseType, b)
|
||||||
|
elif b.kind == distinct:
|
||||||
|
result = typeEqualsOrDistinct(a, b.baseType)
|
||||||
|
|
||||||
|
|
||||||
Subtype relation
|
Subtype relation
|
||||||
~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~
|
||||||
If object ``a`` inherits from ``b``, ``a`` is a subtype of ``b``. This subtype
|
If object ``a`` inherits from ``b``, ``a`` is a subtype of ``b``. This subtype
|
||||||
|
|
@ -1323,14 +1366,6 @@ algorithm returns true:
|
||||||
# XXX range types?
|
# XXX range types?
|
||||||
proc isImplicitlyConvertible(a, b: PType): bool =
|
proc isImplicitlyConvertible(a, b: PType): bool =
|
||||||
case a.kind
|
case a.kind
|
||||||
of proc:
|
|
||||||
if b.kind == proc:
|
|
||||||
var x = a.parameterTuple
|
|
||||||
var y = b.parameterTuple
|
|
||||||
if x.tupleLen == y.tupleLen:
|
|
||||||
for i in 0.. x.tupleLen-1:
|
|
||||||
if not isSubtype(x[i], y[i]): return false
|
|
||||||
result = isSubType(b.resultType, a.resultType)
|
|
||||||
of int8: result = b.kind in {int16, int32, int64, int}
|
of int8: result = b.kind in {int16, int32, int64, int}
|
||||||
of int16: result = b.kind in {int32, int64, int}
|
of int16: result = b.kind in {int32, int64, int}
|
||||||
of int32: result = b.kind in {int64, int}
|
of int32: result = b.kind in {int64, int}
|
||||||
|
|
@ -1357,10 +1392,9 @@ algorithm returns true:
|
||||||
|
|
||||||
proc isExplicitlyConvertible(a, b: PType): bool =
|
proc isExplicitlyConvertible(a, b: PType): bool =
|
||||||
if isImplicitlyConvertible(a, b): return true
|
if isImplicitlyConvertible(a, b): return true
|
||||||
|
if typeEqualsOrDistinct(a, b): return true
|
||||||
if isIntegralType(a) and isIntegralType(b): return true
|
if isIntegralType(a) and isIntegralType(b): return true
|
||||||
if isSubtype(a, b) or isSubtype(b, a): return true
|
if isSubtype(a, b) or isSubtype(b, a): return true
|
||||||
if a.kind == distinct and typeEquals(a.baseType, b): return true
|
|
||||||
if b.kind == distinct and typeEquals(b.baseType, a): return true
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
The convertible relation can be relaxed by a user-defined type
|
The convertible relation can be relaxed by a user-defined type
|
||||||
|
|
@ -1380,6 +1414,9 @@ The convertible relation can be relaxed by a user-defined type
|
||||||
x = chr.toInt
|
x = chr.toInt
|
||||||
echo x # => 97
|
echo x # => 97
|
||||||
|
|
||||||
|
The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and
|
||||||
|
``typeEqualsOrDistinct(T, type(a))`` holds.
|
||||||
|
|
||||||
|
|
||||||
Assignment compatibility
|
Assignment compatibility
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
@ -2852,7 +2889,7 @@ as helpers for macros.
|
||||||
|
|
||||||
noReturn pragma
|
noReturn pragma
|
||||||
---------------
|
---------------
|
||||||
The `noreturn`:idx: pragma is used to mark a proc that it never returns.
|
The `noreturn`:idx: pragma is used to mark a proc that never returns.
|
||||||
|
|
||||||
|
|
||||||
Acyclic pragma
|
Acyclic pragma
|
||||||
|
|
@ -2930,8 +2967,17 @@ only consist of an assembler statement.
|
||||||
error pragma
|
error pragma
|
||||||
------------
|
------------
|
||||||
The `error`:idx: pragma is used to make the compiler output an error message
|
The `error`:idx: pragma is used to make the compiler output an error message
|
||||||
with the given content. Compilation currently aborts after an error, but this
|
with the given content. Compilation does not necessarily abort after an error
|
||||||
may be changed in later versions.
|
though.
|
||||||
|
|
||||||
|
The ``error`` pragma can also be used to
|
||||||
|
annotate a symbol (like an iterator or proc). The *usage* of the symbol then
|
||||||
|
triggers a compile-time error. This is especially useful to rule out that some
|
||||||
|
operation is valid due to overloading and type conversions:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
## check that underlying int values are compared and not the pointers:
|
||||||
|
proc `==`(x, y: ptr int): bool {.error.}
|
||||||
|
|
||||||
|
|
||||||
fatal pragma
|
fatal pragma
|
||||||
|
|
@ -3238,7 +3284,7 @@ Even though Nimrod's `thread`:idx: support and semantics are preliminary,
|
||||||
they should be quite usable already. To enable thread support
|
they should be quite usable already. To enable thread support
|
||||||
the ``--threads:on`` command line switch needs to be used. The ``system``
|
the ``--threads:on`` command line switch needs to be used. The ``system``
|
||||||
module then contains several threading primitives.
|
module then contains several threading primitives.
|
||||||
See the `threads <threads.html>`_ and `inboxes <inboxes.html>`_ modules
|
See the `threads <threads.html>`_ and `channels <channels.html>`_ modules
|
||||||
for the thread API.
|
for the thread API.
|
||||||
|
|
||||||
Nimrod's memory model for threads is quite different than that of other common
|
Nimrod's memory model for threads is quite different than that of other common
|
||||||
|
|
@ -3259,7 +3305,7 @@ violations of the `no heap sharing restriction`:idx:\: This restriction implies
|
||||||
that it is invalid to construct a data structure that consists of memory
|
that it is invalid to construct a data structure that consists of memory
|
||||||
allocated from different (thread local) heaps.
|
allocated from different (thread local) heaps.
|
||||||
|
|
||||||
Since the semantic checking of threads requires a whole program analysis,
|
Since the semantic checking of threads requires whole program analysis,
|
||||||
it is quite expensive and can be turned off with ``--threadanalysis:off`` to
|
it is quite expensive and can be turned off with ``--threadanalysis:off`` to
|
||||||
improve compile times.
|
improve compile times.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,15 +36,18 @@ type
|
||||||
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
|
||||||
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt,
|
||||||
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
|
nnkAsmStmt, nnkPragma, nnkIfStmt, nnkWhenStmt,
|
||||||
nnkForStmt, nnkWhileStmt, nnkCaseStmt, nnkVarSection,
|
nnkForStmt, nnkWhileStmt, nnkCaseStmt,
|
||||||
nnkConstSection, nnkConstDef, nnkTypeSection, nnkTypeDef,
|
nnkVarSection, nnkLetSection, nnkConstSection,
|
||||||
|
nnkConstDef, nnkTypeSection, nnkTypeDef,
|
||||||
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt,
|
||||||
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
|
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt,
|
||||||
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt,
|
||||||
nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
nnkIncludeStmt, nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
|
||||||
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
|
||||||
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen,
|
||||||
nnkRefTy, nnkPtrTy, nnkVarTy, nnkDistinctTy,
|
nnkRefTy, nnkPtrTy, nnkVarTy,
|
||||||
|
nnkConstTy, nnkMutableTy,
|
||||||
|
nnkDistinctTy,
|
||||||
nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
|
nnkProcTy, nnkEnumTy, nnkEnumFieldDef, nnkReturnToken
|
||||||
TNimNodeKinds* = set[TNimrodNodeKind]
|
TNimNodeKinds* = set[TNimrodNodeKind]
|
||||||
TNimrodTypeKind* = enum
|
TNimrodTypeKind* = enum
|
||||||
|
|
@ -184,7 +187,7 @@ proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
|
||||||
## in a string literal node
|
## in a string literal node
|
||||||
return newStrLitNode(repr(n))
|
return newStrLitNode(repr(n))
|
||||||
|
|
||||||
proc prettyPrint*(n: PNimrodNode): string {.compileTime.} =
|
proc toLisp*(n: PNimrodNode): string {.compileTime.} =
|
||||||
## Convert the AST `n` to a human-readable string
|
## Convert the AST `n` to a human-readable string
|
||||||
##
|
##
|
||||||
## You can use this as a tool to explore the Nimrod's abstract syntax
|
## You can use this as a tool to explore the Nimrod's abstract syntax
|
||||||
|
|
@ -204,10 +207,10 @@ proc prettyPrint*(n: PNimrodNode): string {.compileTime.} =
|
||||||
of nnkIdent: add(result, $n.ident)
|
of nnkIdent: add(result, $n.ident)
|
||||||
of nnkSym, nnkNone: assert false
|
of nnkSym, nnkNone: assert false
|
||||||
else:
|
else:
|
||||||
add(result, prettyPrint(n[0]))
|
add(result, toLisp(n[0]))
|
||||||
for j in 1..n.len-1:
|
for j in 1..n.len-1:
|
||||||
add(result, ", ")
|
add(result, ", ")
|
||||||
add(result, prettyPrint(n[j]))
|
add(result, toLisp(n[j]))
|
||||||
|
|
||||||
add(result, ")")
|
add(result, ")")
|
||||||
|
|
||||||
|
|
@ -215,7 +218,7 @@ proc toYaml*(n: PNimrodNode): string {.magic: "AstToYaml".}
|
||||||
## Converts the AST `n` to an YAML string
|
## Converts the AST `n` to an YAML string
|
||||||
##
|
##
|
||||||
## Provides more detailed, potentially harder to digest information
|
## Provides more detailed, potentially harder to digest information
|
||||||
## than `prettyPrint`
|
## than `toLisp`
|
||||||
|
|
||||||
proc parseExpr*(s: string) : expr {.magic: "ParseExprToAst".}
|
proc parseExpr*(s: string) : expr {.magic: "ParseExprToAst".}
|
||||||
## Compiles the passed string to its AST representation
|
## Compiles the passed string to its AST representation
|
||||||
|
|
@ -226,8 +229,11 @@ proc parseStmt*(s: string) : stmt {.magic: "ParseStmtToAst".}
|
||||||
## Expects one or more statements
|
## Expects one or more statements
|
||||||
|
|
||||||
proc getAst*(macroOrTemplate: expr): expr {.magic: "ExpandMacroToAst".}
|
proc getAst*(macroOrTemplate: expr): expr {.magic: "ExpandMacroToAst".}
|
||||||
## Obtains the AST nodes returned from a macro or template invocation
|
## Obtains the AST nodes returned from a macro or template invocation.
|
||||||
## example:
|
## Example:
|
||||||
|
##
|
||||||
|
## .. code-block:: nimrod
|
||||||
|
##
|
||||||
## macro FooMacro() =
|
## macro FooMacro() =
|
||||||
## var ast = getAst(BarTemplate())
|
## var ast = getAst(BarTemplate())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ proc cgiError*(msg: string) {.noreturn.} =
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
proc getEncodedData(allowedMethods: set[TRequestMethod]): string =
|
proc getEncodedData(allowedMethods: set[TRequestMethod]): string =
|
||||||
case getenv("REQUEST_METHOD")
|
case getenv("REQUEST_METHOD").string
|
||||||
of "POST":
|
of "POST":
|
||||||
if methodPost notin allowedMethods:
|
if methodPost notin allowedMethods:
|
||||||
cgiError("'REQUEST_METHOD' 'POST' is not supported")
|
cgiError("'REQUEST_METHOD' 'POST' is not supported")
|
||||||
|
|
@ -192,131 +192,131 @@ proc validateData*(data: PStringTable, validKeys: openarray[string]) =
|
||||||
|
|
||||||
proc getContentLength*(): string =
|
proc getContentLength*(): string =
|
||||||
## returns contents of the ``CONTENT_LENGTH`` environment variable
|
## returns contents of the ``CONTENT_LENGTH`` environment variable
|
||||||
return getenv("CONTENT_LENGTH")
|
return getenv("CONTENT_LENGTH").string
|
||||||
|
|
||||||
proc getContentType*(): string =
|
proc getContentType*(): string =
|
||||||
## returns contents of the ``CONTENT_TYPE`` environment variable
|
## returns contents of the ``CONTENT_TYPE`` environment variable
|
||||||
return getenv("CONTENT_Type")
|
return getenv("CONTENT_Type").string
|
||||||
|
|
||||||
proc getDocumentRoot*(): string =
|
proc getDocumentRoot*(): string =
|
||||||
## returns contents of the ``DOCUMENT_ROOT`` environment variable
|
## returns contents of the ``DOCUMENT_ROOT`` environment variable
|
||||||
return getenv("DOCUMENT_ROOT")
|
return getenv("DOCUMENT_ROOT").string
|
||||||
|
|
||||||
proc getGatewayInterface*(): string =
|
proc getGatewayInterface*(): string =
|
||||||
## returns contents of the ``GATEWAY_INTERFACE`` environment variable
|
## returns contents of the ``GATEWAY_INTERFACE`` environment variable
|
||||||
return getenv("GATEWAY_INTERFACE")
|
return getenv("GATEWAY_INTERFACE").string
|
||||||
|
|
||||||
proc getHttpAccept*(): string =
|
proc getHttpAccept*(): string =
|
||||||
## returns contents of the ``HTTP_ACCEPT`` environment variable
|
## returns contents of the ``HTTP_ACCEPT`` environment variable
|
||||||
return getenv("HTTP_ACCEPT")
|
return getenv("HTTP_ACCEPT").string
|
||||||
|
|
||||||
proc getHttpAcceptCharset*(): string =
|
proc getHttpAcceptCharset*(): string =
|
||||||
## returns contents of the ``HTTP_ACCEPT_CHARSET`` environment variable
|
## returns contents of the ``HTTP_ACCEPT_CHARSET`` environment variable
|
||||||
return getenv("HTTP_ACCEPT_CHARSET")
|
return getenv("HTTP_ACCEPT_CHARSET").string
|
||||||
|
|
||||||
proc getHttpAcceptEncoding*(): string =
|
proc getHttpAcceptEncoding*(): string =
|
||||||
## returns contents of the ``HTTP_ACCEPT_ENCODING`` environment variable
|
## returns contents of the ``HTTP_ACCEPT_ENCODING`` environment variable
|
||||||
return getenv("HTTP_ACCEPT_ENCODING")
|
return getenv("HTTP_ACCEPT_ENCODING").string
|
||||||
|
|
||||||
proc getHttpAcceptLanguage*(): string =
|
proc getHttpAcceptLanguage*(): string =
|
||||||
## returns contents of the ``HTTP_ACCEPT_LANGUAGE`` environment variable
|
## returns contents of the ``HTTP_ACCEPT_LANGUAGE`` environment variable
|
||||||
return getenv("HTTP_ACCEPT_LANGUAGE")
|
return getenv("HTTP_ACCEPT_LANGUAGE").string
|
||||||
|
|
||||||
proc getHttpConnection*(): string =
|
proc getHttpConnection*(): string =
|
||||||
## returns contents of the ``HTTP_CONNECTION`` environment variable
|
## returns contents of the ``HTTP_CONNECTION`` environment variable
|
||||||
return getenv("HTTP_CONNECTION")
|
return getenv("HTTP_CONNECTION").string
|
||||||
|
|
||||||
proc getHttpCookie*(): string =
|
proc getHttpCookie*(): string =
|
||||||
## returns contents of the ``HTTP_COOKIE`` environment variable
|
## returns contents of the ``HTTP_COOKIE`` environment variable
|
||||||
return getenv("HTTP_COOKIE")
|
return getenv("HTTP_COOKIE").string
|
||||||
|
|
||||||
proc getHttpHost*(): string =
|
proc getHttpHost*(): string =
|
||||||
## returns contents of the ``HTTP_HOST`` environment variable
|
## returns contents of the ``HTTP_HOST`` environment variable
|
||||||
return getenv("HTTP_HOST")
|
return getenv("HTTP_HOST").string
|
||||||
|
|
||||||
proc getHttpReferer*(): string =
|
proc getHttpReferer*(): string =
|
||||||
## returns contents of the ``HTTP_REFERER`` environment variable
|
## returns contents of the ``HTTP_REFERER`` environment variable
|
||||||
return getenv("HTTP_REFERER")
|
return getenv("HTTP_REFERER").string
|
||||||
|
|
||||||
proc getHttpUserAgent*(): string =
|
proc getHttpUserAgent*(): string =
|
||||||
## returns contents of the ``HTTP_USER_AGENT`` environment variable
|
## returns contents of the ``HTTP_USER_AGENT`` environment variable
|
||||||
return getenv("HTTP_USER_AGENT")
|
return getenv("HTTP_USER_AGENT").string
|
||||||
|
|
||||||
proc getPathInfo*(): string =
|
proc getPathInfo*(): string =
|
||||||
## returns contents of the ``PATH_INFO`` environment variable
|
## returns contents of the ``PATH_INFO`` environment variable
|
||||||
return getenv("PATH_INFO")
|
return getenv("PATH_INFO").string
|
||||||
|
|
||||||
proc getPathTranslated*(): string =
|
proc getPathTranslated*(): string =
|
||||||
## returns contents of the ``PATH_TRANSLATED`` environment variable
|
## returns contents of the ``PATH_TRANSLATED`` environment variable
|
||||||
return getenv("PATH_TRANSLATED")
|
return getenv("PATH_TRANSLATED").string
|
||||||
|
|
||||||
proc getQueryString*(): string =
|
proc getQueryString*(): string =
|
||||||
## returns contents of the ``QUERY_STRING`` environment variable
|
## returns contents of the ``QUERY_STRING`` environment variable
|
||||||
return getenv("QUERY_STRING")
|
return getenv("QUERY_STRING").string
|
||||||
|
|
||||||
proc getRemoteAddr*(): string =
|
proc getRemoteAddr*(): string =
|
||||||
## returns contents of the ``REMOTE_ADDR`` environment variable
|
## returns contents of the ``REMOTE_ADDR`` environment variable
|
||||||
return getenv("REMOTE_ADDR")
|
return getenv("REMOTE_ADDR").string
|
||||||
|
|
||||||
proc getRemoteHost*(): string =
|
proc getRemoteHost*(): string =
|
||||||
## returns contents of the ``REMOTE_HOST`` environment variable
|
## returns contents of the ``REMOTE_HOST`` environment variable
|
||||||
return getenv("REMOTE_HOST")
|
return getenv("REMOTE_HOST").string
|
||||||
|
|
||||||
proc getRemoteIdent*(): string =
|
proc getRemoteIdent*(): string =
|
||||||
## returns contents of the ``REMOTE_IDENT`` environment variable
|
## returns contents of the ``REMOTE_IDENT`` environment variable
|
||||||
return getenv("REMOTE_IDENT")
|
return getenv("REMOTE_IDENT").string
|
||||||
|
|
||||||
proc getRemotePort*(): string =
|
proc getRemotePort*(): string =
|
||||||
## returns contents of the ``REMOTE_PORT`` environment variable
|
## returns contents of the ``REMOTE_PORT`` environment variable
|
||||||
return getenv("REMOTE_PORT")
|
return getenv("REMOTE_PORT").string
|
||||||
|
|
||||||
proc getRemoteUser*(): string =
|
proc getRemoteUser*(): string =
|
||||||
## returns contents of the ``REMOTE_USER`` environment variable
|
## returns contents of the ``REMOTE_USER`` environment variable
|
||||||
return getenv("REMOTE_USER")
|
return getenv("REMOTE_USER").string
|
||||||
|
|
||||||
proc getRequestMethod*(): string =
|
proc getRequestMethod*(): string =
|
||||||
## returns contents of the ``REQUEST_METHOD`` environment variable
|
## returns contents of the ``REQUEST_METHOD`` environment variable
|
||||||
return getenv("REQUEST_METHOD")
|
return getenv("REQUEST_METHOD").string
|
||||||
|
|
||||||
proc getRequestURI*(): string =
|
proc getRequestURI*(): string =
|
||||||
## returns contents of the ``REQUEST_URI`` environment variable
|
## returns contents of the ``REQUEST_URI`` environment variable
|
||||||
return getenv("REQUEST_URI")
|
return getenv("REQUEST_URI").string
|
||||||
|
|
||||||
proc getScriptFilename*(): string =
|
proc getScriptFilename*(): string =
|
||||||
## returns contents of the ``SCRIPT_FILENAME`` environment variable
|
## returns contents of the ``SCRIPT_FILENAME`` environment variable
|
||||||
return getenv("SCRIPT_FILENAME")
|
return getenv("SCRIPT_FILENAME").string
|
||||||
|
|
||||||
proc getScriptName*(): string =
|
proc getScriptName*(): string =
|
||||||
## returns contents of the ``SCRIPT_NAME`` environment variable
|
## returns contents of the ``SCRIPT_NAME`` environment variable
|
||||||
return getenv("SCRIPT_NAME")
|
return getenv("SCRIPT_NAME").string
|
||||||
|
|
||||||
proc getServerAddr*(): string =
|
proc getServerAddr*(): string =
|
||||||
## returns contents of the ``SERVER_ADDR`` environment variable
|
## returns contents of the ``SERVER_ADDR`` environment variable
|
||||||
return getenv("SERVER_ADDR")
|
return getenv("SERVER_ADDR").string
|
||||||
|
|
||||||
proc getServerAdmin*(): string =
|
proc getServerAdmin*(): string =
|
||||||
## returns contents of the ``SERVER_ADMIN`` environment variable
|
## returns contents of the ``SERVER_ADMIN`` environment variable
|
||||||
return getenv("SERVER_ADMIN")
|
return getenv("SERVER_ADMIN").string
|
||||||
|
|
||||||
proc getServerName*(): string =
|
proc getServerName*(): string =
|
||||||
## returns contents of the ``SERVER_NAME`` environment variable
|
## returns contents of the ``SERVER_NAME`` environment variable
|
||||||
return getenv("SERVER_NAME")
|
return getenv("SERVER_NAME").string
|
||||||
|
|
||||||
proc getServerPort*(): string =
|
proc getServerPort*(): string =
|
||||||
## returns contents of the ``SERVER_PORT`` environment variable
|
## returns contents of the ``SERVER_PORT`` environment variable
|
||||||
return getenv("SERVER_PORT")
|
return getenv("SERVER_PORT").string
|
||||||
|
|
||||||
proc getServerProtocol*(): string =
|
proc getServerProtocol*(): string =
|
||||||
## returns contents of the ``SERVER_PROTOCOL`` environment variable
|
## returns contents of the ``SERVER_PROTOCOL`` environment variable
|
||||||
return getenv("SERVER_PROTOCOL")
|
return getenv("SERVER_PROTOCOL").string
|
||||||
|
|
||||||
proc getServerSignature*(): string =
|
proc getServerSignature*(): string =
|
||||||
## returns contents of the ``SERVER_SIGNATURE`` environment variable
|
## returns contents of the ``SERVER_SIGNATURE`` environment variable
|
||||||
return getenv("SERVER_SIGNATURE")
|
return getenv("SERVER_SIGNATURE").string
|
||||||
|
|
||||||
proc getServerSoftware*(): string =
|
proc getServerSoftware*(): string =
|
||||||
## returns contents of the ``SERVER_SOFTWARE`` environment variable
|
## returns contents of the ``SERVER_SOFTWARE`` environment variable
|
||||||
return getenv("SERVER_SOFTWARE")
|
return getenv("SERVER_SOFTWARE").string
|
||||||
|
|
||||||
proc setTestData*(keysvalues: openarray[string]) =
|
proc setTestData*(keysvalues: openarray[string]) =
|
||||||
## fills the appropriate environment variables to test your CGI application.
|
## fills the appropriate environment variables to test your CGI application.
|
||||||
|
|
@ -360,10 +360,10 @@ proc setCookie*(name, value: string) =
|
||||||
var
|
var
|
||||||
gcookies: PStringTable = nil
|
gcookies: PStringTable = nil
|
||||||
|
|
||||||
proc getCookie*(name: string): string =
|
proc getCookie*(name: string): TaintedString =
|
||||||
## Gets a cookie. If no cookie of `name` exists, "" is returned.
|
## Gets a cookie. If no cookie of `name` exists, "" is returned.
|
||||||
if gcookies == nil: gcookies = parseCookies(getHttpCookie())
|
if gcookies == nil: gcookies = parseCookies(getHttpCookie())
|
||||||
result = gcookies[name]
|
result = TaintedString(gcookies[name])
|
||||||
|
|
||||||
proc existsCookie*(name: string): bool =
|
proc existsCookie*(name: string): bool =
|
||||||
## Checks if a cookie of `name` exists.
|
## Checks if a cookie of `name` exists.
|
||||||
|
|
|
||||||
|
|
@ -692,7 +692,7 @@ proc findEnvVar(key: string): int =
|
||||||
if startsWith(environment[i], temp): return i
|
if startsWith(environment[i], temp): return i
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
proc getEnv*(key: string): string =
|
proc getEnv*(key: string): TaintedString =
|
||||||
## Returns the value of the `environment variable`:idx: named `key`.
|
## Returns the value of the `environment variable`:idx: named `key`.
|
||||||
##
|
##
|
||||||
## If the variable does not exist, "" is returned. To distinguish
|
## If the variable does not exist, "" is returned. To distinguish
|
||||||
|
|
@ -700,11 +700,11 @@ proc getEnv*(key: string): string =
|
||||||
## `existsEnv(key)`.
|
## `existsEnv(key)`.
|
||||||
var i = findEnvVar(key)
|
var i = findEnvVar(key)
|
||||||
if i >= 0:
|
if i >= 0:
|
||||||
return substr(environment[i], find(environment[i], '=')+1)
|
return TaintedString(substr(environment[i], find(environment[i], '=')+1))
|
||||||
else:
|
else:
|
||||||
var env = cgetenv(key)
|
var env = cgetenv(key)
|
||||||
if env == nil: return ""
|
if env == nil: return TaintedString("")
|
||||||
result = $env
|
result = TaintedString($env)
|
||||||
|
|
||||||
proc existsEnv*(key: string): bool =
|
proc existsEnv*(key: string): bool =
|
||||||
## Checks whether the environment variable named `key` exists.
|
## Checks whether the environment variable named `key` exists.
|
||||||
|
|
@ -733,14 +733,15 @@ proc putEnv*(key, val: string) =
|
||||||
if SetEnvironmentVariableA(key, val) == 0'i32:
|
if SetEnvironmentVariableA(key, val) == 0'i32:
|
||||||
OSError()
|
OSError()
|
||||||
|
|
||||||
iterator envPairs*(): tuple[key, value: string] =
|
iterator envPairs*(): tuple[key, value: TaintedString] =
|
||||||
## Iterate over all `environments variables`:idx:. In the first component
|
## Iterate over all `environments variables`:idx:. In the first component
|
||||||
## of the tuple is the name of the current variable stored, in the second
|
## of the tuple is the name of the current variable stored, in the second
|
||||||
## its value.
|
## its value.
|
||||||
getEnvVarsC()
|
getEnvVarsC()
|
||||||
for i in 0..high(environment):
|
for i in 0..high(environment):
|
||||||
var p = find(environment[i], '=')
|
var p = find(environment[i], '=')
|
||||||
yield (substr(environment[i], 0, p-1), substr(environment[i], p+1))
|
yield (TaintedString(substr(environment[i], 0, p-1)),
|
||||||
|
TaintedString(substr(environment[i], p+1)))
|
||||||
|
|
||||||
iterator walkFiles*(pattern: string): string =
|
iterator walkFiles*(pattern: string): string =
|
||||||
## Iterate over all the files that match the `pattern`. On POSIX this uses
|
## Iterate over all the files that match the `pattern`. On POSIX this uses
|
||||||
|
|
@ -1078,18 +1079,18 @@ proc exclFilePermissions*(filename: string,
|
||||||
|
|
||||||
proc getHomeDir*(): string {.rtl, extern: "nos$1".} =
|
proc getHomeDir*(): string {.rtl, extern: "nos$1".} =
|
||||||
## Returns the home directory of the current user.
|
## Returns the home directory of the current user.
|
||||||
when defined(windows): return getEnv("USERPROFILE") & "\\"
|
when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
|
||||||
else: return getEnv("HOME") & "/"
|
else: return string(getEnv("HOME")) & "/"
|
||||||
|
|
||||||
proc getConfigDir*(): string {.rtl, extern: "nos$1".} =
|
proc getConfigDir*(): string {.rtl, extern: "nos$1".} =
|
||||||
## Returns the config directory of the current user for applications.
|
## Returns the config directory of the current user for applications.
|
||||||
when defined(windows): return getEnv("APPDATA") & "\\"
|
when defined(windows): return string(getEnv("APPDATA")) & "\\"
|
||||||
else: return getEnv("HOME") & "/.config/"
|
else: return string(getEnv("HOME")) & "/.config/"
|
||||||
|
|
||||||
proc getTempDir*(): string {.rtl, extern: "nos$1".} =
|
proc getTempDir*(): string {.rtl, extern: "nos$1".} =
|
||||||
## Returns the temporary directory of the current user for applications to
|
## Returns the temporary directory of the current user for applications to
|
||||||
## save temporary files in.
|
## save temporary files in.
|
||||||
when defined(windows): return getEnv("TEMP") & "\\"
|
when defined(windows): return string(getEnv("TEMP")) & "\\"
|
||||||
else: return "/tmp/"
|
else: return "/tmp/"
|
||||||
|
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -1107,14 +1108,14 @@ when defined(windows):
|
||||||
if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLineA())
|
if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLineA())
|
||||||
result = ownArgv.len-1
|
result = ownArgv.len-1
|
||||||
|
|
||||||
proc paramStr*(i: int): string {.rtl, extern: "nos$1".} =
|
proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1".} =
|
||||||
## Returns the `i`-th `command line argument`:idx: given to the
|
## Returns the `i`-th `command line argument`:idx: given to the
|
||||||
## application.
|
## application.
|
||||||
##
|
##
|
||||||
## `i` should be in the range `1..paramCount()`, else
|
## `i` should be in the range `1..paramCount()`, else
|
||||||
## the `EOutOfIndex` exception is raised.
|
## the `EOutOfIndex` exception is raised.
|
||||||
if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLineA())
|
if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLineA())
|
||||||
return ownArgv[i]
|
return TaintedString(ownArgv[i])
|
||||||
|
|
||||||
elif not defined(createNimRtl):
|
elif not defined(createNimRtl):
|
||||||
# On Posix, there is no portable way to get the command line from a DLL.
|
# On Posix, there is no portable way to get the command line from a DLL.
|
||||||
|
|
@ -1122,8 +1123,8 @@ elif not defined(createNimRtl):
|
||||||
cmdCount {.importc: "cmdCount".}: cint
|
cmdCount {.importc: "cmdCount".}: cint
|
||||||
cmdLine {.importc: "cmdLine".}: cstringArray
|
cmdLine {.importc: "cmdLine".}: cstringArray
|
||||||
|
|
||||||
proc paramStr*(i: int): string =
|
proc paramStr*(i: int): TaintedString =
|
||||||
if i < cmdCount and i >= 0: return $cmdLine[i]
|
if i < cmdCount and i >= 0: return TaintedString($cmdLine[i])
|
||||||
raise newException(EInvalidIndex, "invalid index")
|
raise newException(EInvalidIndex, "invalid index")
|
||||||
|
|
||||||
proc paramCount*(): int = return cmdCount-1
|
proc paramCount*(): int = return cmdCount-1
|
||||||
|
|
@ -1172,13 +1173,14 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1".} =
|
||||||
result = "" # error!
|
result = "" # error!
|
||||||
else:
|
else:
|
||||||
# little heuristic that may work on other POSIX-like systems:
|
# little heuristic that may work on other POSIX-like systems:
|
||||||
result = getEnv("_")
|
result = string(getEnv("_"))
|
||||||
if len(result) == 0:
|
if len(result) == 0:
|
||||||
result = ParamStr(0) # POSIX guaranties that this contains the executable
|
result = string(ParamStr(0))
|
||||||
|
# POSIX guaranties that this contains the executable
|
||||||
# as it has been executed by the calling process
|
# as it has been executed by the calling process
|
||||||
if len(result) > 0 and result[0] != DirSep: # not an absolute path?
|
if len(result) > 0 and result[0] != DirSep: # not an absolute path?
|
||||||
# iterate over any path in the $PATH environment variable
|
# iterate over any path in the $PATH environment variable
|
||||||
for p in split(getEnv("PATH"), {PathSep}):
|
for p in split(string(getEnv("PATH")), {PathSep}):
|
||||||
var x = joinPath(p, result)
|
var x = joinPath(p, result)
|
||||||
if ExistsFile(x): return x
|
if ExistsFile(x): return x
|
||||||
|
|
||||||
|
|
@ -1230,7 +1232,7 @@ proc findExe*(exe: string): string =
|
||||||
## is added an ``.exe`` file extension if it has no extension.
|
## is added an ``.exe`` file extension if it has no extension.
|
||||||
result = addFileExt(exe, os.exeExt)
|
result = addFileExt(exe, os.exeExt)
|
||||||
if ExistsFile(result): return
|
if ExistsFile(result): return
|
||||||
var path = os.getEnv("PATH")
|
var path = string(os.getEnv("PATH"))
|
||||||
for candidate in split(path, pathSep):
|
for candidate in split(path, pathSep):
|
||||||
var x = candidate / result
|
var x = candidate / result
|
||||||
if ExistsFile(x): return x
|
if ExistsFile(x): return x
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ when defined(os.ParamCount):
|
||||||
else:
|
else:
|
||||||
result.cmd = ""
|
result.cmd = ""
|
||||||
for i in countup(1, ParamCount()):
|
for i in countup(1, ParamCount()):
|
||||||
result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i)) & ' '
|
result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i).string) & ' '
|
||||||
result.kind = cmdEnd
|
result.kind = cmdEnd
|
||||||
result.key = ""
|
result.key = ""
|
||||||
result.val = ""
|
result.val = ""
|
||||||
|
|
|
||||||
|
|
@ -787,6 +787,19 @@ proc compileOption*(option, arg: string): bool {.
|
||||||
const
|
const
|
||||||
hasThreadSupport = compileOption("threads")
|
hasThreadSupport = compileOption("threads")
|
||||||
hasSharedHeap = defined(boehmgc) # don't share heaps; every thread has its own
|
hasSharedHeap = defined(boehmgc) # don't share heaps; every thread has its own
|
||||||
|
# taintMode = compileOption("taintmode")
|
||||||
|
|
||||||
|
when defined(taintMode):
|
||||||
|
# XXX use a compile time option for it!
|
||||||
|
type TaintedString* = distinct string ## a distinct string type that
|
||||||
|
## is `tainted`:idx:. It is an alias for
|
||||||
|
## ``string`` if the taint mode is not
|
||||||
|
## turned on. Use the ``-d:taintMode``
|
||||||
|
## command line switch to turn the taint
|
||||||
|
## mode on.
|
||||||
|
else:
|
||||||
|
type TaintedString* = string
|
||||||
|
|
||||||
|
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
{.pragma: rtlThreadVar, threadvar.}
|
{.pragma: rtlThreadVar, threadvar.}
|
||||||
|
|
@ -896,11 +909,6 @@ type # these work for most platforms:
|
||||||
PInt64* = ptr Int64 ## an alias for ``ptr int64``
|
PInt64* = ptr Int64 ## an alias for ``ptr int64``
|
||||||
PInt32* = ptr Int32 ## an alias for ``ptr int32``
|
PInt32* = ptr Int32 ## an alias for ``ptr int32``
|
||||||
|
|
||||||
type TOptional*[T] = object
|
|
||||||
case hasValue* : bool
|
|
||||||
of true: value*: T
|
|
||||||
of false: nil
|
|
||||||
|
|
||||||
proc toFloat*(i: int): float {.
|
proc toFloat*(i: int): float {.
|
||||||
magic: "ToFloat", noSideEffect, importc: "toFloat".}
|
magic: "ToFloat", noSideEffect, importc: "toFloat".}
|
||||||
## converts an integer `i` into a ``float``. If the conversion
|
## converts an integer `i` into a ``float``. If the conversion
|
||||||
|
|
@ -1653,7 +1661,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
|
proc FlushFile*(f: TFile) {.importc: "fflush", noDecl.}
|
||||||
## Flushes `f`'s buffer.
|
## Flushes `f`'s buffer.
|
||||||
|
|
||||||
proc readFile*(filename: string): string
|
proc readFile*(filename: string): TaintedString
|
||||||
## Opens a file named `filename` for reading. Then reads the
|
## Opens a file named `filename` for reading. Then reads the
|
||||||
## file's content completely into a string and
|
## file's content completely into a string and
|
||||||
## closes the file afterwards. Returns the string.
|
## closes the file afterwards. Returns the string.
|
||||||
|
|
@ -1675,7 +1683,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
proc write*(f: TFile, a: openArray[string])
|
proc write*(f: TFile, a: openArray[string])
|
||||||
## Writes a value to the file `f`. May throw an IO exception.
|
## Writes a value to the file `f`. May throw an IO exception.
|
||||||
|
|
||||||
proc readLine*(f: TFile): string
|
proc readLine*(f: TFile): TaintedString
|
||||||
## reads a line of text from the file `f`. May throw an IO exception.
|
## reads a line of text from the file `f`. May throw an IO exception.
|
||||||
## A line of text may be delimited by ``CR``, ``LF`` or
|
## A line of text may be delimited by ``CR``, ``LF`` or
|
||||||
## ``CRLF``. The newline character(s) are not part of the returned string.
|
## ``CRLF``. The newline character(s) are not part of the returned string.
|
||||||
|
|
@ -1814,22 +1822,22 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
include "system/channels"
|
include "system/channels"
|
||||||
|
|
||||||
iterator lines*(filename: string): string =
|
iterator lines*(filename: string): TaintedString =
|
||||||
## Iterate over any line in the file named `filename`.
|
## Iterate over any line in the file named `filename`.
|
||||||
## If the file does not exist `EIO` is raised.
|
## If the file does not exist `EIO` is raised.
|
||||||
var f = open(filename)
|
var f = open(filename)
|
||||||
var res = ""
|
var res = ""
|
||||||
while not endOfFile(f):
|
while not endOfFile(f):
|
||||||
rawReadLine(f, res)
|
rawReadLine(f, res)
|
||||||
yield res
|
yield TaintedString(res)
|
||||||
Close(f)
|
Close(f)
|
||||||
|
|
||||||
iterator lines*(f: TFile): string =
|
iterator lines*(f: TFile): TaintedString =
|
||||||
## Iterate over any line in the file `f`.
|
## Iterate over any line in the file `f`.
|
||||||
var res = ""
|
var res = ""
|
||||||
while not endOfFile(f):
|
while not endOfFile(f):
|
||||||
rawReadLine(f, res)
|
rawReadLine(f, res)
|
||||||
yield res
|
yield TaintedString(res)
|
||||||
|
|
||||||
include "system/assign"
|
include "system/assign"
|
||||||
include "system/repr"
|
include "system/repr"
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,8 @@ proc rawReadLine(f: TFile, result: var string) =
|
||||||
break
|
break
|
||||||
add result, chr(int(c))
|
add result, chr(int(c))
|
||||||
|
|
||||||
proc readLine(f: TFile): string =
|
proc readLine(f: TFile): TaintedString =
|
||||||
result = ""
|
result = TaintedString("")
|
||||||
rawReadLine(f, result)
|
rawReadLine(f, result)
|
||||||
|
|
||||||
proc write(f: TFile, i: int) =
|
proc write(f: TFile, i: int) =
|
||||||
|
|
@ -81,7 +81,7 @@ proc write(f: TFile, c: Char) = putc(c, f)
|
||||||
proc write(f: TFile, a: openArray[string]) =
|
proc write(f: TFile, a: openArray[string]) =
|
||||||
for x in items(a): write(f, x)
|
for x in items(a): write(f, x)
|
||||||
|
|
||||||
proc readFile(filename: string): string =
|
proc readFile(filename: string): TaintedString =
|
||||||
var f = open(filename)
|
var f = open(filename)
|
||||||
try:
|
try:
|
||||||
var len = getFileSize(f)
|
var len = getFileSize(f)
|
||||||
|
|
|
||||||
4
todo.txt
4
todo.txt
|
|
@ -2,14 +2,14 @@ Version 0.8.14
|
||||||
==============
|
==============
|
||||||
|
|
||||||
- 'let x = y'
|
- 'let x = y'
|
||||||
- threads should not have an inbox per default
|
- T(x) as l-value
|
||||||
|
- fix actors.nim
|
||||||
- make threadvar efficient again on linux after testing
|
- make threadvar efficient again on linux after testing
|
||||||
- fix the 'const' issues
|
- fix the 'const' issues
|
||||||
- test the sort implementation again
|
- test the sort implementation again
|
||||||
- optional indentation for 'case' statement
|
- optional indentation for 'case' statement
|
||||||
- taint mode
|
- taint mode
|
||||||
- const ptr/ref
|
- const ptr/ref
|
||||||
- {.error.} pragma for proc headers
|
|
||||||
|
|
||||||
|
|
||||||
version 0.9.0
|
version 0.9.0
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ Language Additions
|
||||||
- The built-in type ``void`` can be used to denote the absense of any type.
|
- The built-in type ``void`` can be used to denote the absense of any type.
|
||||||
This is useful in generic code.
|
This is useful in generic code.
|
||||||
- Return types may be of the type ``var T`` to return an l-value.
|
- Return types may be of the type ``var T`` to return an l-value.
|
||||||
|
- The error pragma can now be used to mark symbols whose *usage* should trigger
|
||||||
|
a compile-time error.
|
||||||
|
|
||||||
|
|
||||||
Compiler Additions
|
Compiler Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue