diff options
-rwxr-xr-x | compiler/ast.nim | 2 | ||||
-rwxr-xr-x | compiler/pragmas.nim | 10 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 2 | ||||
-rwxr-xr-x | compiler/wordrecg.nim | 4 | ||||
-rwxr-xr-x | doc/manual.txt | 4 | ||||
-rwxr-xr-x | lib/pure/parseopt.nim | 28 | ||||
-rwxr-xr-x | lib/pure/sockets.nim | 20 | ||||
-rwxr-xr-x | lib/pure/streams.nim | 14 | ||||
-rwxr-xr-x | lib/pure/strtabs.nim | 3 | ||||
-rwxr-xr-x | lib/system.nim | 4 | ||||
-rwxr-xr-x | lib/system/sysio.nim | 19 | ||||
-rw-r--r-- | tests/accept/compile/tdiscardable.nim (renamed from tests/accept/compile/toptional_pragma.nim) | 6 | ||||
-rwxr-xr-x | todo.txt | 5 | ||||
-rwxr-xr-x | tools/niminst.nim | 10 | ||||
-rwxr-xr-x | web/news.txt | 4 |
15 files changed, 72 insertions, 63 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index fc2348a77..775f679df 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -227,7 +227,7 @@ type # for interfacing with C++, JS sfNamedParamCall, # symbol needs named parameter call syntax in target # language; for interfacing with Objective C - sfOptional # returned value may be discarded implicitely + sfDiscardable # returned value may be discarded implicitely TSymFlags* = set[TSymFlag] diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index dc120ef1d..6c3a7ba67 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -23,15 +23,15 @@ const wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, - wNoStackFrame, wError, wOptional} + wNoStackFrame, wError, wDiscardable} converterPragmas* = procPragmas methodPragmas* = procPragmas macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, wMagic, wNosideEffect, wCompilerProc, wDeprecated, wExtern, - wImportcpp, wImportobjc, wError, wOptional} + wImportcpp, wImportobjc, wError, wDiscardable} iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, - wImportcpp, wImportobjc, wError, wOptional} + wImportcpp, wImportobjc, wError, wDiscardable} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal, @@ -553,9 +553,9 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = of wPragma: processPragma(c, n, i) break - of wOptional: + of wDiscardable: noVal(it) - if sym != nil: incl(sym.flags, sfOptional) + if sym != nil: incl(sym.flags, sfDiscardable) of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir, wStacktrace, wLinetrace, wOptimization, wByRef, diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 5e9f9e28d..b042a6436 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -550,7 +550,7 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode = proc semExprNoType(c: PContext, n: PNode): PNode = proc ImplicitelyDiscardable(n: PNode): bool {.inline.} = result = isCallExpr(n) and n.sons[0].kind == nkSym and - sfOptional in n.sons[0].sym.flags + sfDiscardable in n.sons[0].sym.flags result = semExpr(c, n) if result.typ != nil and result.typ.kind != tyStmt: if gCmd == cmdInteractive: diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 0389439dd..9e4e13797 100755 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -51,7 +51,7 @@ type wDeadCodeElim, wSafecode, wPragma, wCompileTime, - wPassc, wPassl, wBorrow, wOptional, + wPassc, wPassl, wBorrow, wDiscardable, wFieldChecks, wCheckPoint, wSubsChar, wAcyclic, wShallow, wUnroll, wLinearScanEnd, @@ -96,7 +96,7 @@ const "deadcodeelim", "safecode", "pragma", "compiletime", - "passc", "passl", "borrow", "optional", "fieldchecks", + "passc", "passl", "borrow", "discardable", "fieldchecks", "checkpoint", "subschar", "acyclic", "shallow", "unroll", "linearscanend", "write", "putenv", "prependenv", "appendenv", "threadvar", "emit", diff --git a/doc/manual.txt b/doc/manual.txt index 55a008632..6b73c0960 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -1486,10 +1486,10 @@ Ignoring the return value of a procedure without using a discard statement is a static error. The return value can be ignored implicitely if the called proc/iterator has -been declared with the `optional`:idx: pragma: +been declared with the `discardable`:idx: pragma: .. code-block:: nimrod - proc p(x, y: int): int {.optional.} = + proc p(x, y: int): int {.discardable.} = return x + y p(3, 4) # now valid diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index 347871bac..35f29ad2c 100755 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -30,7 +30,7 @@ type pos: int inShortState: bool kind*: TCmdLineKind ## the dected command line token - key*, val*: string ## key and value pair; ``key`` is the option + key*, val*: TaintedString ## key and value pair; ``key`` is the option ## or the argument, ``value`` is not "" if ## the option was given a value @@ -50,8 +50,8 @@ when defined(os.ParamCount): for i in countup(1, ParamCount()): result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i).string) & ' ' result.kind = cmdEnd - result.key = "" - result.val = "" + result.key = TaintedString"" + result.val = TaintedString"" proc parseWord(s: string, i: int, w: var string, delim: TCharSet = {'\x09', ' ', '\0'}): int = @@ -70,7 +70,7 @@ proc parseWord(s: string, i: int, w: var string, proc handleShortOption(p: var TOptParser) = var i = p.pos p.kind = cmdShortOption - add(p.key, p.cmd[i]) + add(p.key.string, p.cmd[i]) inc(i) p.inShortState = true while p.cmd[i] in {'\x09', ' '}: @@ -80,7 +80,7 @@ proc handleShortOption(p: var TOptParser) = inc(i) p.inShortState = false while p.cmd[i] in {'\x09', ' '}: inc(i) - i = parseWord(p.cmd, i, p.val) + i = parseWord(p.cmd, i, p.val.string) if p.cmd[i] == '\0': p.inShortState = false p.pos = i @@ -91,8 +91,8 @@ proc next*(p: var TOptParser) {. var i = p.pos while p.cmd[i] in {'\x09', ' '}: inc(i) p.pos = i - setlen(p.key, 0) - setlen(p.val, 0) + setlen(p.key.string, 0) + setlen(p.val.string, 0) if p.inShortState: handleShortOption(p) return @@ -104,29 +104,29 @@ proc next*(p: var TOptParser) {. if p.cmd[i] == '-': p.kind = cmdLongOption inc(i) - i = parseWord(p.cmd, i, p.key, {'\0', ' ', '\x09', ':', '='}) + i = parseWord(p.cmd, i, p.key.string, {'\0', ' ', '\x09', ':', '='}) while p.cmd[i] in {'\x09', ' '}: inc(i) if p.cmd[i] in {':', '='}: inc(i) while p.cmd[i] in {'\x09', ' '}: inc(i) - p.pos = parseWord(p.cmd, i, p.val) + p.pos = parseWord(p.cmd, i, p.val.string) else: p.pos = i else: p.pos = i handleShortOption(p) - else: + else: p.kind = cmdArgument - p.pos = parseWord(p.cmd, i, p.key) + p.pos = parseWord(p.cmd, i, p.key.string) -proc cmdLineRest*(p: TOptParser): string {. +proc cmdLineRest*(p: TOptParser): TaintedString {. rtl, extern: "npo$1".} = ## retrieves the rest of the command line that has not been parsed yet. - result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)) + result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString when defined(initOptParser): - iterator getopt*(): tuple[kind: TCmdLineKind, key, val: string] = + iterator getopt*(): tuple[kind: TCmdLineKind, key, val: TaintedString] = ## This is an convenience iterator for iterating over the command line. ## This uses the TOptParser object. Example: ## diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index f18cf2ba8..c07974897 100755 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -525,11 +525,11 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int = pruneSocketSet(readfds, (rd)) -proc recvLine*(socket: TSocket, line: var string): bool = +proc recvLine*(socket: TSocket, line: var TaintedString): bool = ## returns false if no further data is available. `Line` must be initialized ## and not nil! This does not throw an EOS exception, therefore ## it can be used in both blocking and non-blocking sockets. - setLen(line, 0) + setLen(line.string, 0) while true: var c: char var n = recv(cint(socket), addr(c), 1, 0'i32) @@ -541,20 +541,20 @@ proc recvLine*(socket: TSocket, line: var string): bool = elif n <= 0: return false return true elif c == '\L': return true - add(line, c) + add(line.string, c) proc recv*(socket: TSocket, data: pointer, size: int): int = ## receives data from a socket result = recv(cint(socket), data, size, 0'i32) -proc recv*(socket: TSocket): string = +proc recv*(socket: TSocket): TaintedString = ## receives all the data from the socket. ## 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 = 200 + const bufSize = 1000 var buf = newString(bufSize) - result = "" + result = TaintedString"" while true: var bytesRead = recv(socket, cstring(buf), bufSize-1) # Error @@ -562,16 +562,16 @@ proc recv*(socket: TSocket): string = buf[bytesRead] = '\0' # might not be necessary setLen(buf, bytesRead) - add(result, buf) + add(result.string, buf) if bytesRead != bufSize-1: break -proc recvAsync*(socket: TSocket, s: var string): bool = +proc recvAsync*(socket: TSocket, s: var TaintedString): bool = ## receives all the data from a non-blocking socket. If socket is non-blocking ## and there are no messages available, `False` will be returned. ## Other socket errors will result in an ``EOS`` error. ## If socket is not a connectionless socket and socket is not connected ## ``s`` will be set to ``""``. - const bufSize = 200 + const bufSize = 1000 var buf = newString(bufSize) s = "" while true: @@ -597,7 +597,7 @@ proc recvAsync*(socket: TSocket, s: var string): bool = proc skip*(socket: TSocket) = ## skips all the data that is pending for the socket - const bufSize = 200 + const bufSize = 1000 var buf = alloc(bufSize) while recv(socket, buf, bufSize) == bufSize: nil dealloc(buf) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 62cb385d4..dc76bd95f 100755 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -80,24 +80,24 @@ proc readFloat64*(s: PStream): float64 = ## reads a float64 from the stream `s`. Raises `EIO` if an error occured. read(s, result) -proc readStr*(s: PStream, length: int): string = +proc readStr*(s: PStream, length: int): TaintedString = ## reads a string of length `length` from the stream `s`. Raises `EIO` if ## an error occured. - result = newString(length) - var L = s.readData(s, addr(result[0]), length) - if L != length: setLen(result, L) + result = newString(length).TaintedString + var L = s.readData(s, addr(string(result)[0]), length) + if L != length: setLen(result.string, L) -proc readLine*(s: PStream): string = +proc readLine*(s: PStream): TaintedString = ## Reads a line from a stream `s`. Note: This is not very efficient. Raises ## `EIO` if an error occured. - result = "" + result = TaintedString"" while not s.atEnd(s): var c = readChar(s) if c == '\c': c = readChar(s) break elif c == '\L' or c == '\0': break - result.add(c) + result.string.add(c) type PStringStream* = ref TStringStream ## a stream that encapsulates a string diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index a9ce9016c..15ff5a079 100755 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -136,7 +136,8 @@ proc RaiseFormatException(s: string) = proc getValue(t: PStringTable, flags: set[TFormatFlag], key: string): string = if hasKey(t, key): return t[key] - if useEnvironment in flags: result = os.getEnv(key) + # hm difficult: assume safety in taint mode here. XXX This is dangerous! + if useEnvironment in flags: result = os.getEnv(key).string else: result = "" if result.len == 0: if useKey in flags: result = '$' & key diff --git a/lib/system.nim b/lib/system.nim index 1ce7a4d60..226642771 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -787,9 +787,9 @@ proc compileOption*(option, arg: string): bool {. const hasThreadSupport = compileOption("threads") hasSharedHeap = defined(boehmgc) # don't share heaps; every thread has its own -# taintMode = compileOption("taintmode") + taintMode = compileOption("taintmode") -when defined(taintMode): +when 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 diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 56815c0c5..313d9fd95 100755 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -56,8 +56,12 @@ proc rawReadLine(f: TFile, result: var string) = add result, chr(int(c)) proc readLine(f: TFile): TaintedString = - result = TaintedString("") - rawReadLine(f, result) + when taintMode: + result = TaintedString"" + rawReadLine(f, result.string) + else: + result = "" + rawReadLine(f, result) proc write(f: TFile, i: int) = when sizeof(int) == 8: @@ -86,9 +90,14 @@ proc readFile(filename: string): TaintedString = try: var len = getFileSize(f) if len < high(int): - result = newString(int(len)) - if readBuffer(f, addr(result[0]), int(len)) != len: - raiseEIO("error while reading from file") + when taintMode: + result = newString(int(len)).TaintedString + if readBuffer(f, addr(string(result)[0]), int(len)) != len: + raiseEIO("error while reading from file") + else: + result = newString(int(len)) + if readBuffer(f, addr(result[0]), int(len)) != len: + raiseEIO("error while reading from file") else: raiseEIO("file too big to fit in memory") finally: diff --git a/tests/accept/compile/toptional_pragma.nim b/tests/accept/compile/tdiscardable.nim index 80ebe68a3..c0551ba2f 100644 --- a/tests/accept/compile/toptional_pragma.nim +++ b/tests/accept/compile/tdiscardable.nim @@ -1,10 +1,10 @@ -# Test the optional pragma +# Test the discardable pragma -proc p(x, y: int): int {.optional.} = +proc p(x, y: int): int {.discardable.} = return x + y # test that it is inherited from generic procs too: -proc q[T](x, y: T): T {.optional.} = +proc q[T](x, y: T): T {.discardable.} = return x + y diff --git a/todo.txt b/todo.txt index 19abdb298..cde83e210 100755 --- a/todo.txt +++ b/todo.txt @@ -1,14 +1,13 @@ Version 0.8.14 ============== -- 'let x = y' +- taint mode +- 'let x = y'; const ptr/ref - fix actors.nim - make threadvar efficient again on linux after testing - fix the 'const' issues - test the sort implementation again - optional indentation for 'case' statement -- taint mode -- const ptr/ref version 0.9.0 diff --git a/tools/niminst.nim b/tools/niminst.nim index c58fa38af..2a1041e17 100755 --- a/tools/niminst.nim +++ b/tools/niminst.nim @@ -126,22 +126,22 @@ proc parseCmdLine(c: var TConfigData) = next(p) var kind = p.kind var key = p.key - var val = p.val + var val = p.val.string case kind of cmdArgument: if c.actions == {}: - for a in split(normalize(key), {';', ','}): + for a in split(normalize(key.string), {';', ','}): case a of "csource": incl(c.actions, actionCSource) of "zip": incl(c.actions, actionZip) of "inno": incl(c.actions, actionInno) else: quit(Usage) else: - c.infile = addFileExt(key, "ini") - c.nimrodArgs = cmdLineRest(p) + c.infile = addFileExt(key.string, "ini") + c.nimrodArgs = cmdLineRest(p).string break of cmdLongOption, cmdShortOption: - case normalize(key) + case normalize(key.string) of "help", "h": stdout.write(Usage) quit(0) diff --git a/web/news.txt b/web/news.txt index a531f0334..7fdfd5628 100755 --- a/web/news.txt +++ b/web/news.txt @@ -47,8 +47,8 @@ Language Additions - 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. -- There is a new ``optional`` pragma that can be used to mark a routine so that - its result can be discarded implicitely. +- There is a new ``discardable`` pragma that can be used to mark a routine + so that its result can be discarded implicitely. Compiler Additions |