mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-20 22:35:24 +00:00
renamed optional to discardable
This commit is contained in:
@@ -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]
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
##
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
5
todo.txt
5
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user