renamed optional to discardable

This commit is contained in:
Araq
2011-09-24 19:18:08 +02:00
parent 72ceda98cb
commit 485c371942
15 changed files with 72 additions and 63 deletions

View File

@@ -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]

View File

@@ -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,

View File

@@ -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:

View File

@@ -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",

View File

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

View File

@@ -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:
##

View File

@@ -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)

View File

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

View File

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

View File

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

View File

@@ -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:

View File

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

View File

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

View File

@@ -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)

View File

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