summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim2
-rwxr-xr-xcompiler/pragmas.nim10
-rwxr-xr-xcompiler/semexprs.nim2
-rwxr-xr-xcompiler/wordrecg.nim4
-rwxr-xr-xdoc/manual.txt4
-rwxr-xr-xlib/pure/parseopt.nim28
-rwxr-xr-xlib/pure/sockets.nim20
-rwxr-xr-xlib/pure/streams.nim14
-rwxr-xr-xlib/pure/strtabs.nim3
-rwxr-xr-xlib/system.nim4
-rwxr-xr-xlib/system/sysio.nim19
-rw-r--r--tests/accept/compile/tdiscardable.nim (renamed from tests/accept/compile/toptional_pragma.nim)6
-rwxr-xr-xtodo.txt5
-rwxr-xr-xtools/niminst.nim10
-rwxr-xr-xweb/news.txt4
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