Merge branch 'araq-stringify-array' into devel

This commit is contained in:
Andreas Rumpf 2017-10-10 13:18:32 +02:00
commit 13f974336e
24 changed files with 247 additions and 130 deletions

View file

@ -5,3 +5,6 @@
- Removed basic2d/basic3d out of the stdlib and into Nimble packages. - Removed basic2d/basic3d out of the stdlib and into Nimble packages.
These packages deprecated however, use the ``glm``, ``arraymancer``, ``neo`` These packages deprecated however, use the ``glm``, ``arraymancer``, ``neo``
or another package. or another package.
- Arrays of char cannot be converted to ``cstring`` anymore, pointers to
arrays of char can! This means ``$`` for arrays can finally exist
in ``system.nim`` and do the right thing.

View file

@ -108,3 +108,4 @@ proc initDefines*() =
defineSymbol("nimHasCppDefine") defineSymbol("nimHasCppDefine")
defineSymbol("nimGenericInOutFlags") defineSymbol("nimGenericInOutFlags")
when false: defineSymbol("nimHasOpt") when false: defineSymbol("nimHasOpt")
defineSymbol("nimNoArrayToCstringConversion")

View file

@ -39,6 +39,9 @@
## x = y where y is read only once ## x = y where y is read only once
## is the same as: move(x, y) ## is the same as: move(x, y)
## ##
## Actually the more general rule is: The *last* read of ``y``
## can become a move if ``y`` is the result of a construction.
##
## We also need to keep in mind here that the number of reads is ## We also need to keep in mind here that the number of reads is
## control flow dependent: ## control flow dependent:
## let x = foo() ## let x = foo()
@ -183,10 +186,67 @@ when false:
of nkVarSection, nkLetSection: collectVarSection(c, n) of nkVarSection, nkLetSection: collectVarSection(c, n)
else: discard else: discard
type
Con = object
owner: PSym
g: ControlFlowGraph
tmps: PType
proc isHarmlessVar*(s: PSym; c: Con): bool =
# 's' is harmless if it used only once and its
# definition/usage are not split by any labels:
#
# let s = foo()
# while true:
# a[i] = s
#
# produces:
#
# def s
# L1:
# use s
# goto L1
#
# let s = foo()
# if cond:
# a[i] = s
# else:
# a[j] = s
#
# produces:
#
# def s
# fork L2
# use s
# goto L3
# L2:
# use s
# L3
#
# So this analysis is for now overly conservative, but correct.
discard
template interestingSym(s: PSym): bool =
s.owner == owner and s.kind in InterestingSyms and hasDestructor(s.typ)
proc p(n, parent: PNode; c: var Con) =
case n.kind
of nkVarSection, nkLetSection:
discard "transform; var x = y to var x; x op y where op is a move or copy"
of nkCallKinds:
if n.typ != nil and hasDestructor(n.typ):
discard "produce temp creation"
of nkAsgn, nkFastAsgn:
if n[0].kind == nkSym and interestingSym(n[0].sym):
discard "use move or assignment"
else:
for i in 0..<n.len:
p(n[i], n, c)
proc injectDestructorCalls*(owner: PSym; n: PNode; proc injectDestructorCalls*(owner: PSym; n: PNode;
disableExceptions = false): PNode = disableExceptions = false): PNode =
when false: when false:
var c = Con(t: initTable[int, VarInfo](), owner: owner) var c = Con(t: initTable[int, VarInfo](), owner: owner)
collectData(c, n) collectData(c, n)
var allTemps = createObj(owner, n.info) var allTemps = createObj(owner, n.info)
let cfg = constructCfg(owner, n)

View file

@ -1011,7 +1011,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkPrefix: of nkPrefix:
gsub(g, n, 0) gsub(g, n, 0)
if n.len > 1: if n.len > 1:
if n[1].kind == nkPrefix: let opr = if n[0].kind == nkIdent: n[0].ident
elif n[0].kind == nkSym: n[0].sym.name
else: nil
if n[1].kind == nkPrefix or (opr != nil and renderer.isKeyword(opr)):
put(g, tkSpaces, Space) put(g, tkSpaces, Space)
if n.sons[1].kind == nkInfix: if n.sons[1].kind == nkInfix:
put(g, tkParLe, "(") put(g, tkParLe, "(")

View file

@ -10,7 +10,7 @@
## Serialization utilities for the compiler. ## Serialization utilities for the compiler.
import strutils import strutils
proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", header: "<stdio.h>", nodecl, varargs.} proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "<stdio.h>", nodecl, varargs.}
proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
if f != f: if f != f:
@ -20,10 +20,15 @@ proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
elif f == 0.5 * f: elif f == 0.5 * f:
if f > 0.0: result = "INF" if f > 0.0: result = "INF"
else: result = "-INF" else: result = "-INF"
else:
when defined(nimNoArrayToCstringConversion):
result = newString(81)
let n = c_snprintf(result.cstring, result.len.uint, "%#.16e%s", f, literalPostfix.cstring)
setLen(result, n)
else: else:
var buf: array[0..80, char] var buf: array[0..80, char]
c_sprintf(buf, "%#.16e" & literalPostfix, f) discard c_snprintf(buf.cstring, buf.len.uint, "%#.16e%s", f, literalPostfix.cstring)
result = $buf result = $buf.cstring
proc encodeStr*(s: string, result: var string) = proc encodeStr*(s: string, result: var string) =
for i in countup(0, len(s) - 1): for i in countup(0, len(s) - 1):
@ -133,4 +138,3 @@ iterator decodeStrArray*(s: cstring): string =
while s[i] != '\0': while s[i] != '\0':
yield decodeStr(s, i) yield decodeStr(s, i)
if s[i] == ' ': inc i if s[i] == ' ': inc i

View file

@ -1288,11 +1288,12 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
of tyString: result = isConvertible of tyString: result = isConvertible
of tyPtr: of tyPtr:
# ptr[Tag, char] is not convertible to 'cstring' for now: # ptr[Tag, char] is not convertible to 'cstring' for now:
if a.len == 1 and a.sons[0].kind == tyChar: result = isConvertible if a.len == 1:
of tyArray: let pointsTo = a.sons[0].skipTypes(abstractInst)
if (firstOrd(a.sons[0]) == 0) and if pointsTo.kind == tyChar: result = isConvertible
(skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and elif pointsTo.kind == tyArray and firstOrd(pointsTo.sons[0]) == 0 and
(a.sons[1].kind == tyChar): skipTypes(pointsTo.sons[0], {tyRange}).kind in {tyInt..tyInt64} and
pointsTo.sons[1].kind == tyChar:
result = isConvertible result = isConvertible
else: discard else: discard

View file

@ -667,14 +667,6 @@ proc lengthOrd*(t: PType): BiggestInt =
else: else:
result = lastOrd(t) - firstOrd(t) + 1 result = lastOrd(t) - firstOrd(t) + 1
proc isCompatibleToCString*(a: PType): bool =
if a.kind == tyArray:
if (firstOrd(a.sons[0]) == 0) and
(skipTypes(a.sons[0], {tyRange, tyGenericInst, tyAlias}).kind in
{tyInt..tyInt64, tyUInt..tyUInt64}) and
(a.sons[1].kind == tyChar):
result = true
# -------------- type equality ----------------------------------------------- # -------------- type equality -----------------------------------------------
type type

View file

@ -63,16 +63,16 @@ proc recvLine*(sock: SecureSocket, line: var TaintedString): bool =
setLen(line.string, 0) setLen(line.string, 0)
while true: while true:
var c: array[0..0, char] var c: array[0..0, char]
var n = BIO_read(sock.bio, c, c.len.cint) var n = BIO_read(sock.bio, addr c, c.len.cint)
if n <= 0: return false if n <= 0: return false
if c[0] == '\r': if c[0] == '\r':
n = BIO_read(sock.bio, c, c.len.cint) n = BIO_read(sock.bio, addr c, c.len.cint)
if n > 0 and c[0] == '\L': if n > 0 and c[0] == '\L':
return true return true
elif n <= 0: elif n <= 0:
return false return false
elif c[0] == '\L': return true elif c[0] == '\L': return true
add(line.string, c) add(line.string, c[0])
proc send*(sock: SecureSocket, data: string) = proc send*(sock: SecureSocket, data: string) =

View file

@ -496,11 +496,12 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
addr(namelen)) == -1'i32: addr(namelen)) == -1'i32:
raiseOSError(osLastError()) raiseOSError(osLastError())
# Cannot use INET6_ADDRSTRLEN here, because it's a C define. # Cannot use INET6_ADDRSTRLEN here, because it's a C define.
var buf: array[64, char] result[0] = newString(64)
if inet_ntop(name.sin6_family.cint, if inet_ntop(name.sin6_family.cint,
addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil: addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil:
raiseOSError(osLastError()) raiseOSError(osLastError())
result = ($buf, Port(nativesockets.ntohs(name.sin6_port))) setLen(result[0], result[0].cstring.len)
result[1] = Port(nativesockets.ntohs(name.sin6_port))
else: else:
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")
@ -532,11 +533,12 @@ proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
addr(namelen)) == -1'i32: addr(namelen)) == -1'i32:
raiseOSError(osLastError()) raiseOSError(osLastError())
# Cannot use INET6_ADDRSTRLEN here, because it's a C define. # Cannot use INET6_ADDRSTRLEN here, because it's a C define.
var buf: array[64, char] result[0] = newString(64)
if inet_ntop(name.sin6_family.cint, if inet_ntop(name.sin6_family.cint,
addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil: addr name.sin6_addr, addr result[0][0], (result[0].len+1).int32).isNil:
raiseOSError(osLastError()) raiseOSError(osLastError())
result = ($buf, Port(nativesockets.ntohs(name.sin6_port))) setLen(result[0], result[0].cstring.len)
result[1] = Port(nativesockets.ntohs(name.sin6_port))
else: else:
raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr") raiseOSError(OSErrorCode(-1), "invalid socket family in getLocalAddr")

View file

@ -790,7 +790,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
while true: while true:
var x = readdir(d) var x = readdir(d)
if x == nil: break if x == nil: break
var y = $x.d_name when defined(nimNoArrayToCstringConversion):
var y = $cstring(addr x.d_name)
else:
var y = $x.d_name.cstring
if y != "." and y != "..": if y != "." and y != "..":
var s: Stat var s: Stat
if not relative: if not relative:

View file

@ -1890,10 +1890,16 @@ proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
frmtstr[3] = '*' frmtstr[3] = '*'
frmtstr[4] = floatFormatToChar[format] frmtstr[4] = floatFormatToChar[format]
frmtstr[5] = '\0' frmtstr[5] = '\0'
when defined(nimNoArrayToCstringConversion):
L = c_sprintf(addr buf, addr frmtstr, precision, f)
else:
L = c_sprintf(buf, frmtstr, precision, f) L = c_sprintf(buf, frmtstr, precision, f)
else: else:
frmtstr[1] = floatFormatToChar[format] frmtstr[1] = floatFormatToChar[format]
frmtstr[2] = '\0' frmtstr[2] = '\0'
when defined(nimNoArrayToCstringConversion):
L = c_sprintf(addr buf, addr frmtstr, f)
else:
L = c_sprintf(buf, frmtstr, f) L = c_sprintf(buf, frmtstr, f)
result = newString(L) result = newString(L)
for i in 0 ..< L: for i in 0 ..< L:

View file

@ -1875,7 +1875,7 @@ proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.}
proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.} proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.}
## The stringify operator for a boolean argument. Returns `x` ## The stringify operator for a boolean argument. Returns `x`
## converted to the string "false" or "true". ## converted to the string "false" or "true".
#
proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.} proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
## The stringify operator for a character argument. Returns `x` ## The stringify operator for a character argument. Returns `x`
## converted to a string. ## converted to a string.
@ -2437,20 +2437,28 @@ proc `$`*[T: tuple|object](x: T): string =
result.add("...") result.add("...")
result.add(")") result.add(")")
proc collectionToString[T: set | seq](x: T, b, e: string): string = proc collectionToString[T](x: T, prefix, separator, suffix: string): string =
when x is seq: result = prefix
if x.isNil: return "nil"
result = b
var firstElement = true var firstElement = true
for value in items(x): for value in items(x):
if not firstElement: result.add(", ") if firstElement:
firstElement = false
else:
result.add(separator)
when compiles(value.isNil): when compiles(value.isNil):
if value.isNil: result.add "nil" # this branch should not be necessary
else: result.add($value) if value.isNil:
result.add "nil"
else: else:
result.add($value) result.add($value)
firstElement = false # prevent temporary string allocation
result.add(e) elif compiles(result.add(value)):
result.add(value)
else:
result.add($value)
result.add(suffix)
proc `$`*[T](x: set[T]): string = proc `$`*[T](x: set[T]): string =
## generic ``$`` operator for sets that is lifted from the components ## generic ``$`` operator for sets that is lifted from the components
@ -2458,7 +2466,7 @@ proc `$`*[T](x: set[T]): string =
## ##
## .. code-block:: nim ## .. code-block:: nim
## ${23, 45} == "{23, 45}" ## ${23, 45} == "{23, 45}"
collectionToString(x, "{", "}") collectionToString(x, "{", ", ", "}")
proc `$`*[T](x: seq[T]): string = proc `$`*[T](x: seq[T]): string =
## generic ``$`` operator for seqs that is lifted from the components ## generic ``$`` operator for seqs that is lifted from the components
@ -2466,13 +2474,10 @@ proc `$`*[T](x: seq[T]): string =
## ##
## .. code-block:: nim ## .. code-block:: nim
## $(@[23, 45]) == "@[23, 45]" ## $(@[23, 45]) == "@[23, 45]"
collectionToString(x, "@[", "]") if x.isNil:
"nil"
when false: else:
# causes bootstrapping to fail as we use array of chars and cstring should collectionToString(x, "@[", ", ", "]")
# match better ...
proc `$`*[T, IDX](x: array[IDX, T]): string =
collectionToString(x, "[", "]")
# ----------------- GC interface --------------------------------------------- # ----------------- GC interface ---------------------------------------------
@ -3329,6 +3334,10 @@ elif defined(JS):
include "system/sysio" include "system/sysio"
proc `$`*[T, IDX](x: array[IDX, T]): string =
## generic ``$`` operator for arrays that is lifted from the components
collectionToString(x, "[", ", ", "]")
proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} = proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} =
## a shorthand for ``echo(errormsg); quit(errorcode)``. ## a shorthand for ``echo(errormsg); quit(errorcode)``.
echo(errormsg) echo(errormsg)

View file

@ -142,6 +142,9 @@ elif defined(windows) or defined(dos):
dec(m) dec(m)
k = k div 10 k = k div 10
if k == 0: break if k == 0: break
when defined(nimNoArrayToCstringConversion):
result = getProcAddress(cast[THINSTANCE](lib), addr decorated)
else:
result = getProcAddress(cast[THINSTANCE](lib), decorated) result = getProcAddress(cast[THINSTANCE](lib), decorated)
if result != nil: return if result != nil: return
procAddrError(name) procAddrError(name)

View file

@ -76,10 +76,10 @@ proc `==`(a, b: StaticStr): bool =
return true return true
proc `==`(a: StaticStr, b: cstring): bool = proc `==`(a: StaticStr, b: cstring): bool =
result = c_strcmp(a.data, b) == 0 result = c_strcmp(unsafeAddr a.data, b) == 0
proc write(f: File, s: StaticStr) = proc write(f: File, s: StaticStr) =
write(f, cstring(s.data)) write(f, cstring(unsafeAddr s.data))
proc listBreakPoints() = proc listBreakPoints() =
write(stdout, EndbBeg) write(stdout, EndbBeg)
@ -260,8 +260,8 @@ proc parseBreakpoint(s: cstring, start: int): Breakpoint =
if result.high == 0: result.high = result.low if result.high == 0: result.high = result.low
i = scanFilename(s, dbgTemp, i) i = scanFilename(s, dbgTemp, i)
if dbgTemp.len != 0: if dbgTemp.len != 0:
if not hasExt(dbgTemp.data): add(dbgTemp, ".nim") if not hasExt(addr dbgTemp.data): add(dbgTemp, ".nim")
result.filename = canonFilename(dbgTemp.data.cstring) result.filename = canonFilename(addr dbgTemp.data)
if result.filename.isNil: if result.filename.isNil:
debugOut("[Warning] no breakpoint could be set; unknown filename ") debugOut("[Warning] no breakpoint could be set; unknown filename ")
return return
@ -292,12 +292,12 @@ proc dbgEvaluate(stream: File, s: cstring, start: int, f: PFrame) =
i = scanAndAppendWord(s, dbgTemp, i) i = scanAndAppendWord(s, dbgTemp, i)
for i in 0 .. getGlobalLen()-1: for i in 0 .. getGlobalLen()-1:
let v = getGlobal(i) let v = getGlobal(i)
if c_strcmp(v.name, dbgTemp.data) == 0: if c_strcmp(v.name, addr dbgTemp.data) == 0:
writeVariable(stream, v) writeVariable(stream, v)
else: else:
for i in 0 .. f.len-1: for i in 0 .. f.len-1:
let v = getLocal(f, i) let v = getLocal(f, i)
if c_strcmp(v.name, dbgTemp.data) == 0: if c_strcmp(v.name, addr dbgTemp.data) == 0:
writeVariable(stream, v) writeVariable(stream, v)
proc dbgOut(s: cstring, start: int, currFrame: PFrame) = proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
@ -306,7 +306,7 @@ proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
if dbgTemp.len == 0: if dbgTemp.len == 0:
invalidCommand() invalidCommand()
return return
var stream = openAppend(dbgTemp.data) var stream = openAppend(addr dbgTemp.data)
if stream == nil: if stream == nil:
debugOut("[Warning] could not open or create file ") debugOut("[Warning] could not open or create file ")
return return
@ -320,7 +320,7 @@ proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
# just write it to stdout: # just write it to stdout:
listFrame(stdout, currFrame) listFrame(stdout, currFrame)
else: else:
var stream = openAppend(dbgTemp.data) var stream = openAppend(addr dbgTemp.data)
if stream == nil: if stream == nil:
debugOut("[Warning] could not open or create file ") debugOut("[Warning] could not open or create file ")
return return
@ -369,7 +369,7 @@ proc commandPrompt() =
if not readLine(stdin, dbgUser): break if not readLine(stdin, dbgUser): break
if dbgUser.len == 0: dbgUser.len = oldLen if dbgUser.len == 0: dbgUser.len = oldLen
# now look what we have to do: # now look what we have to do:
var i = scanWord(dbgUser.data, dbgTemp, 0) var i = scanWord(addr dbgUser.data, dbgTemp, 0)
template `?`(x: expr): expr = dbgTemp == cstring(x) template `?`(x: expr): expr = dbgTemp == cstring(x)
if ?"s" or ?"step": if ?"s" or ?"step":
dbgState = dbStepInto dbgState = dbStepInto
@ -400,13 +400,13 @@ proc commandPrompt() =
prevState = dbgState prevState = dbgState
prevSkipFrame = dbgSkipToFrame prevSkipFrame = dbgSkipToFrame
dbgState = dbSkipCurrent dbgState = dbSkipCurrent
dbgEvaluate(stdout, dbgUser.data, i, dbgFramePtr) dbgEvaluate(stdout, addr dbgUser.data, i, dbgFramePtr)
dbgState = prevState dbgState = prevState
dbgSkipToFrame = prevSkipFrame dbgSkipToFrame = prevSkipFrame
elif ?"o" or ?"out": elif ?"o" or ?"out":
dbgOut(dbgUser.data, i, dbgFramePtr) dbgOut(addr dbgUser.data, i, dbgFramePtr)
elif ?"stackframe": elif ?"stackframe":
dbgStackFrame(dbgUser.data, i, dbgFramePtr) dbgStackFrame(addr dbgUser.data, i, dbgFramePtr)
elif ?"w" or ?"where": elif ?"w" or ?"where":
dbgShowExecutionPoint() dbgShowExecutionPoint()
elif ?"l" or ?"locals": elif ?"l" or ?"locals":
@ -444,16 +444,16 @@ proc commandPrompt() =
elif ?"bt" or ?"backtrace": elif ?"bt" or ?"backtrace":
dbgWriteStackTrace(framePtr) dbgWriteStackTrace(framePtr)
elif ?"b" or ?"break": elif ?"b" or ?"break":
createBreakPoint(dbgUser.data, i) createBreakPoint(addr dbgUser.data, i)
elif ?"breakpoints": elif ?"breakpoints":
listBreakPoints() listBreakPoints()
elif ?"toggle": elif ?"toggle":
breakpointToggle(dbgUser.data, i) breakpointToggle(addr dbgUser.data, i)
elif ?"filenames": elif ?"filenames":
listFilenames() listFilenames()
elif ?"maxdisplay": elif ?"maxdisplay":
var parsed: int var parsed: int
i = scanNumber(dbgUser.data, parsed, i) i = scanNumber(addr dbgUser.data, parsed, i)
if dbgUser.data[i-1] in {'0'..'9'}: if dbgUser.data[i-1] in {'0'..'9'}:
if parsed == 0: maxDisplayRecDepth = -1 if parsed == 0: maxDisplayRecDepth = -1
else: maxDisplayRecDepth = parsed else: maxDisplayRecDepth = parsed

View file

@ -289,8 +289,12 @@ proc raiseExceptionAux(e: ref Exception) =
add(buf, " [") add(buf, " [")
xadd(buf, e.name, e.name.len) xadd(buf, e.name, e.name.len)
add(buf, "]\n") add(buf, "]\n")
unhandled(buf): when defined(nimNoArrayToCstringConversion):
showErrorMessage(buf) template tbuf(): untyped = addr buf
else:
template tbuf(): untyped = buf
unhandled(tbuf()):
showErrorMessage(tbuf())
quitOrDebug() quitOrDebug()
proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} = proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =

View file

@ -16,6 +16,11 @@ proc reprInt(x: int64): string {.compilerproc.} = return $x
proc reprFloat(x: float): string {.compilerproc.} = return $x proc reprFloat(x: float): string {.compilerproc.} = return $x
proc reprPointer(x: pointer): string {.compilerproc.} = proc reprPointer(x: pointer): string {.compilerproc.} =
when defined(nimNoArrayToCstringConversion):
result = newString(60)
let n = c_sprintf(addr result[0], "%p", x)
setLen(result, n)
else:
var buf: array[0..59, char] var buf: array[0..59, char]
discard c_sprintf(buf, "%p", x) discard c_sprintf(buf, "%p", x)
return $buf return $buf
@ -24,19 +29,19 @@ proc `$`(x: uint64): string =
if x == 0: if x == 0:
result = "0" result = "0"
else: else:
var buf: array[60, char] result = newString(60)
var i = 0 var i = 0
var n = x var n = x
while n != 0: while n != 0:
let nn = n div 10'u64 let nn = n div 10'u64
buf[i] = char(n - 10'u64 * nn + ord('0')) result[i] = char(n - 10'u64 * nn + ord('0'))
inc i inc i
n = nn n = nn
result.setLen i
let half = i div 2 let half = i div 2
# Reverse # Reverse
for t in 0 .. < half: swap(buf[t], buf[i-t-1]) for t in 0 .. < half: swap(result[t], result[i-t-1])
result = $buf
proc reprStrAux(result: var string, s: cstring; len: int) = proc reprStrAux(result: var string, s: cstring; len: int) =
if cast[pointer](s) == nil: if cast[pointer](s) == nil:

View file

@ -24,6 +24,9 @@ proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
if a == b: return 0 if a == b: return 0
if a == nil: return -1 if a == nil: return -1
if b == nil: return 1 if b == nil: return 1
when defined(nimNoArrayToCstringConversion):
return c_strcmp(addr a.data, addr b.data)
else:
return c_strcmp(a.data, b.data) return c_strcmp(a.data, b.data)
proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} = proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
@ -320,6 +323,9 @@ proc nimIntToStr(x: int): string {.compilerRtl.} =
proc add*(result: var string; x: float) = proc add*(result: var string; x: float) =
var buf: array[0..64, char] var buf: array[0..64, char]
when defined(nimNoArrayToCstringConversion):
var n: int = c_sprintf(addr buf, "%.16g", x)
else:
var n: int = c_sprintf(buf, "%.16g", x) var n: int = c_sprintf(buf, "%.16g", x)
var hasDot = false var hasDot = false
for i in 0..n-1: for i in 0..n-1:
@ -342,7 +348,10 @@ proc add*(result: var string; x: float) =
else: else:
result.add "inf" result.add "inf"
else: else:
result.add buf var i = 0
while buf[i] != '\0':
result.add buf[i]
inc i
proc nimFloatToStr(f: float): string {.compilerproc.} = proc nimFloatToStr(f: float): string {.compilerproc.} =
result = newStringOfCap(8) result = newStringOfCap(8)
@ -507,6 +516,9 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
t[ti-3] = ('0'.ord + abs_exponent mod 10).char t[ti-3] = ('0'.ord + abs_exponent mod 10).char
when defined(nimNoArrayToCstringConversion):
number = c_strtod(addr t, nil)
else:
number = c_strtod(t, nil) number = c_strtod(t, nil)
proc nimInt64ToStr(x: int64): string {.compilerRtl.} = proc nimInt64ToStr(x: int64): string {.compilerRtl.} =

View file

@ -590,13 +590,13 @@ proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.importc: "MD5_Transform".}
from strutils import toHex, toLowerAscii from strutils import toHex, toLowerAscii
proc hexStr (buf:cstring): string = proc hexStr(buf: cstring): string =
# turn md5s output into a nice hex str # turn md5s output into a nice hex str
result = newStringOfCap(32) result = newStringOfCap(32)
for i in 0 .. <16: for i in 0 .. <16:
result.add toHex(buf[i].ord, 2).toLowerAscii result.add toHex(buf[i].ord, 2).toLowerAscii
proc md5_File* (file: string): string {.raises: [IOError,Exception].} = proc md5_File*(file: string): string {.raises: [IOError,Exception].} =
## Generate MD5 hash for a file. Result is a 32 character ## Generate MD5 hash for a file. Result is a 32 character
# hex string with lowercase characters (like the output # hex string with lowercase characters (like the output
# of `md5sum` # of `md5sum`
@ -611,14 +611,14 @@ proc md5_File* (file: string): string {.raises: [IOError,Exception].} =
while(let bytes = f.readChars(buf, 0, sz); bytes > 0): while(let bytes = f.readChars(buf, 0, sz); bytes > 0):
discard md5_update(ctx, buf[0].addr, bytes) discard md5_update(ctx, buf[0].addr, bytes)
discard md5_final( buf[0].addr, ctx ) discard md5_final(buf[0].addr, ctx)
f.close f.close
result = hexStr(buf) result = hexStr(addr buf)
proc md5_Str*(str:string): string = proc md5_Str*(str: string): string =
##Generate MD5 hash for a string. Result is a 32 character ## Generate MD5 hash for a string. Result is a 32 character
#hex string with lowercase characters ## hex string with lowercase characters
var var
ctx: MD5_CTX ctx: MD5_CTX
res: array[MD5_DIGEST_LENGTH,char] res: array[MD5_DIGEST_LENGTH,char]
@ -631,5 +631,5 @@ proc md5_Str*(str:string): string =
discard md5_update(ctx, input[i].addr, L) discard md5_update(ctx, input[i].addr, L)
i += L i += L
discard md5_final(res,ctx) discard md5_final(addr res, ctx)
result = hexStr(res) result = hexStr(addr res)

View file

@ -62,7 +62,7 @@ proc launchSwarm(name: ptr SockAddr) {.async.} =
16384, cast[ptr SockAddr](addr saddr), 16384, cast[ptr SockAddr](addr saddr),
addr slen) addr slen)
size = 0 size = 0
var grammString = $buffer var grammString = $cstring(addr buffer)
if grammString == message: if grammString == message:
saveSendingPort(sockport) saveSendingPort(sockport)
inc(recvCount) inc(recvCount)
@ -84,7 +84,7 @@ proc readMessages(server: AsyncFD) {.async.} =
16384, cast[ptr SockAddr](addr(saddr)), 16384, cast[ptr SockAddr](addr(saddr)),
addr(slen)) addr(slen))
size = 0 size = 0
var grammString = $buffer var grammString = $cstring(addr buffer)
if grammString.startswith("Message ") and if grammString.startswith("Message ") and
saddr.sin_addr.s_addr == 0x100007F: saddr.sin_addr.s_addr == 0x100007F:
await sendTo(server, addr grammString[0], len(grammString), await sendTo(server, addr grammString[0], len(grammString),

View file

@ -9,7 +9,7 @@ proc c_sprintf(buf, fmt: cstring) {.importc:"sprintf", header: "<stdio.h>", vara
proc floatToStr(f: float64): string = proc floatToStr(f: float64): string =
var buffer: array[128, char] var buffer: array[128, char]
c_sprintf(buffer, "%.16e", f) c_sprintf(addr buffer, "%.16e", f)
result = "" result = ""
for ch in buffer: for ch in buffer:
if ch == '\0': if ch == '\0':

View file

@ -31,7 +31,7 @@ type
of nkList: sons: seq[PCaseNode] of nkList: sons: seq[PCaseNode]
else: unused: seq[string] else: unused: seq[string]
TIdObj* = object of TObject TIdObj* = object of RootObj
id*: int # unique id; use this for comparisons and not the pointers id*: int # unique id; use this for comparisons and not the pointers
PIdObj* = ref TIdObj PIdObj* = ref TIdObj

View file

@ -6,9 +6,8 @@ when not defined(windows):
var buf: array[0..10, char] var buf: array[0..10, char]
while true: while true:
var r = read(0, addr(buf), sizeof(buf)-1) var r = read(0, addr(buf), sizeof(buf)-1)
add inp, $buf add inp, $cstring(addr buf)
if r != sizeof(buf)-1: break if r != sizeof(buf)-1: break
echo inp echo inp
#dafkladskölklödsaf ölksdakölfölksfklwe4iojr389wr 89uweokf sdlkf jweklr jweflksdj fioewjfsdlfsd #dafkladskölklödsaf ölksdakölfölksfklwe4iojr389wr 89uweokf sdlkf jweklr jweflksdj fioewjfsdlfsd

View file

@ -1,42 +1,53 @@
discard """ discard """
output:'''@[23, 45] output:""
@[, foo, bar]
{a, b, c}
2.3242
2.982
123912.1
123912.1823
5.0
1e+100
inf
-inf
nan
nil
nil'''
""" """
echo($(@[23, 45])) doAssert "@[23, 45]" == $(@[23, 45])
echo($(@["", "foo", "bar"])) doAssert "[32, 45]" == $([32, 45])
#echo($(["", "foo", "bar"])) doAssert "@[, foo, bar]" == $(@["", "foo", "bar"])
#echo($([23, 45])) doAssert "[, foo, bar]" == $(["", "foo", "bar"])
# bug #2395 # bug #2395
let alphaSet: set[char] = {'a'..'c'} let alphaSet: set[char] = {'a'..'c'}
echo alphaSet doAssert "{a, b, c}" == $alphaSet
doAssert "2.3242" == $(2.3242)
echo($(2.3242)) doAssert "2.982" == $(2.982)
echo($(2.982)) doAssert "123912.1" == $(123912.1)
echo($(123912.1)) doAssert "123912.1823" == $(123912.1823)
echo($(123912.1823)) doAssert "5.0" == $(5.0)
echo($(5.0)) doAssert "1e+100" == $(1e100)
echo($(1e100)) doAssert "inf" == $(1e1000000)
echo($(1e1000000)) doAssert "-inf" == $(-1e1000000)
echo($(-1e1000000)) doAssert "nan" == $(0.0/0.0)
echo($(0.0/0.0))
# nil tests # nil tests
# maybe a bit inconsistent in types
var x: seq[string] var x: seq[string]
var y: string doAssert "nil" == $(x)
echo(x)
echo(y) var y: string = nil
doAssert nil == $(y)
type
Foo = object
a: int
b: string
var foo1: Foo
# nil string should be an some point in time equal to the empty string
doAssert(($foo1)[0..9] == "(a: 0, b: ")
const
data = @['a','b', '\0', 'c','d']
dataStr = $data
# ensure same result when on VM or when at program execution
doAssert dataStr == $data
import strutils
# array test
let arr = ['H','e','l','l','o',' ','W','o','r','l','d','!','\0']
doAssert $arr == "[H, e, l, l, o, , W, o, r, l, d, !, \0]"
doAssert $cstring(unsafeAddr arr) == "Hello World!"

View file

@ -1,7 +1,6 @@
version 1.0 battle plan version 1.0 battle plan
======================= =======================
- disallow conversions from ``array`` to ``cstring``!
- make 'not nil' the default (produce warnings instead of errors for - make 'not nil' the default (produce warnings instead of errors for
a smooth migration path) a smooth migration path)
- case objects needs to be safe and need to support pattern matching - case objects needs to be safe and need to support pattern matching