Merge branch 'devel' of github.com:nim-lang/Nim into devel

This commit is contained in:
Dominik Picheta 2016-01-27 16:19:38 +00:00
commit 4c2894ca26
23 changed files with 367 additions and 188 deletions

View file

@ -50,10 +50,10 @@ proc importcSymbol*(sym: PSym): PNode =
# that contains the address instead: # that contains the address instead:
result = newNodeIT(nkPtrLit, sym.info, sym.typ) result = newNodeIT(nkPtrLit, sym.info, sym.typ)
case name case name
of "stdin": result.intVal = cast[TAddress](system.stdin) of "stdin": result.intVal = cast[ByteAddress](system.stdin)
of "stdout": result.intVal = cast[TAddress](system.stdout) of "stdout": result.intVal = cast[ByteAddress](system.stdout)
of "stderr": result.intVal = cast[TAddress](system.stderr) of "stderr": result.intVal = cast[ByteAddress](system.stderr)
of "vmErrnoWrapper": result.intVal = cast[TAddress](myerrno) of "vmErrnoWrapper": result.intVal = cast[ByteAddress](myerrno)
else: else:
let lib = sym.annex let lib = sym.annex
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}: if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
@ -71,7 +71,7 @@ proc importcSymbol*(sym: PSym): PNode =
else: lib.path.strVal, sym.info) else: lib.path.strVal, sym.info)
theAddr = dllhandle.symAddr(name) theAddr = dllhandle.symAddr(name)
if theAddr.isNil: globalError(sym.info, "cannot import: " & sym.name.s) if theAddr.isNil: globalError(sym.info, "cannot import: " & sym.name.s)
result.intVal = cast[TAddress](theAddr) result.intVal = cast[ByteAddress](theAddr)
proc mapType(t: ast.PType): ptr libffi.TType = proc mapType(t: ast.PType): ptr libffi.TType =
if t == nil: return addr libffi.type_void if t == nil: return addr libffi.type_void
@ -107,7 +107,7 @@ proc mapCallConv(cc: TCallingConvention, info: TLineInfo): TABI =
template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[] template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
template `+!`(x, y: expr): expr {.immediate.} = template `+!`(x, y: expr): expr {.immediate.} =
cast[pointer](cast[TAddress](x) + y) cast[pointer](cast[ByteAddress](x) + y)
proc packSize(v: PNode, typ: PType): int = proc packSize(v: PNode, typ: PType): int =
## computes the size of the blob ## computes the size of the blob
@ -363,13 +363,13 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
# in their unboxed representation so nothing it to be unpacked: # in their unboxed representation so nothing it to be unpacked:
result = n result = n
else: else:
awi(nkPtrLit, cast[TAddress](p)) awi(nkPtrLit, cast[ByteAddress](p))
of tyPtr, tyRef, tyVar: of tyPtr, tyRef, tyVar:
let p = rd(pointer, x) let p = rd(pointer, x)
if p.isNil: if p.isNil:
setNil() setNil()
elif n == nil or n.kind == nkPtrLit: elif n == nil or n.kind == nkPtrLit:
awi(nkPtrLit, cast[TAddress](p)) awi(nkPtrLit, cast[ByteAddress](p))
elif n != nil and n.len == 1: elif n != nil and n.len == 1:
internalAssert n.kind == nkRefTy internalAssert n.kind == nkRefTy
n.sons[0] = unpack(p, typ.lastSon, n.sons[0]) n.sons[0] = unpack(p, typ.lastSon, n.sons[0])

View file

@ -163,8 +163,31 @@ proc mangleName(s: PSym): Rope =
add(result, rope(s.id)) add(result, rope(s.id))
s.loc.r = result s.loc.r = result
proc makeJSString(s: string): Rope = proc escapeJSString(s: string): string =
(if s.isNil: "null".rope else: strutils.escape(s).rope) result = newStringOfCap(s.len + s.len shr 2)
result.add("\"")
for c in items(s):
case c
of '\l': result.add("\\n")
of '\r': result.add("\\r")
of '\t': result.add("\\t")
of '\b': result.add("\\b")
of '\a': result.add("\\a")
of '\e': result.add("\\e")
of '\v': result.add("\\v")
of '\\': result.add("\\\\")
of '\'': result.add("\\'")
of '\"': result.add("\\\"")
else: add(result, c)
result.add("\"")
proc makeJSString(s: string, escapeNonAscii = true): Rope =
if s.isNil:
result = "null".rope
elif escapeNonAscii:
result = strutils.escape(s).rope
else:
result = escapeJSString(s).rope
include jstypes include jstypes
@ -264,7 +287,7 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "($1 - $2)", "($1 - $2)"], # SubF64 ["", "", "($1 - $2)", "($1 - $2)"], # SubF64
["", "", "($1 * $2)", "($1 * $2)"], # MulF64 ["", "", "($1 * $2)", "($1 * $2)"], # MulF64
["", "", "($1 / $2)", "($1 / $2)"], # DivF64 ["", "", "($1 / $2)", "($1 / $2)"], # DivF64
["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI ["", "", "", ""], # ShrI
["", "", "($1 << $2)", "($1 << $2)"], # ShlI ["", "", "($1 << $2)", "($1 << $2)"], # ShlI
["", "", "($1 & $2)", "($1 & $2)"], # BitandI ["", "", "($1 & $2)", "($1 & $2)"], # BitandI
["", "", "($1 | $2)", "($1 | $2)"], # BitorI ["", "", "($1 | $2)", "($1 | $2)"], # BitorI
@ -344,19 +367,22 @@ proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
r.res = frmt % [x.rdLoc, y.rdLoc] r.res = frmt % [x.rdLoc, y.rdLoc]
r.kind = resExpr r.kind = resExpr
proc unsignedTrimmer(size: BiggestInt): Rope =
case size
of 1: rope"& 0xff"
of 2: rope"& 0xffff"
of 4: rope">>> 0"
else: rope""
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, reassign: bool = false) = proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, reassign: bool = false) =
var x, y: TCompRes var x, y: TCompRes
gen(p, n.sons[1], x) gen(p, n.sons[1], x)
gen(p, n.sons[2], y) gen(p, n.sons[2], y)
let trimmer = case n[1].typ.skipTypes(abstractRange).size let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
of 1: "& 0xff"
of 2: "& 0xffff"
of 4: ">>> 0"
else: ""
if reassign: if reassign:
r.res = "$1 = (($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, rope trimmer] r.res = "$1 = (($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
else: else:
r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, rope trimmer] r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
var x, y, z: TCompRes var x, y, z: TCompRes
@ -392,6 +418,12 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mSubU: binaryUintExpr(p, n, r, "-") of mSubU: binaryUintExpr(p, n, r, "-")
of mMulU: binaryUintExpr(p, n, r, "*") of mMulU: binaryUintExpr(p, n, r, "*")
of mDivU: binaryUintExpr(p, n, r, "/") of mDivU: binaryUintExpr(p, n, r, "/")
of mShrI:
var x, y: TCompRes
gen(p, n.sons[1], x)
gen(p, n.sons[2], y)
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc]
else: else:
arithAux(p, n, r, op, jsOps) arithAux(p, n, r, op, jsOps)
r.kind = resExpr r.kind = resExpr
@ -568,7 +600,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
if stringSwitch: if stringSwitch:
case e.kind case e.kind
of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ", of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ",
[makeJSString(e.strVal)]) [makeJSString(e.strVal, false)])
else: internalError(e.info, "jsgen.genCaseStmt: 2") else: internalError(e.info, "jsgen.genCaseStmt: 2")
else: else:
gen(p, e, cond) gen(p, e, cond)
@ -1324,7 +1356,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mEqStr: binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)") of mEqStr: binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
of mLeStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)") of mLeStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
of mLtStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)") of mLtStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)")
of mIsNil: unaryExpr(p, n, r, "", "$1 == null") of mIsNil: unaryExpr(p, n, r, "", "($1 === null)")
of mEnumToStr: genRepr(p, n, r) of mEnumToStr: genRepr(p, n, r)
of mNew, mNewFinalize: genNew(p, n) of mNew, mNewFinalize: genNew(p, n)
of mSizeOf: r.res = rope(getSize(n.sons[1].typ)) of mSizeOf: r.res = rope(getSize(n.sons[1].typ))
@ -1569,6 +1601,37 @@ proc genPragma(p: PProc, n: PNode) =
of wEmit: genAsmOrEmitStmt(p, it.sons[1]) of wEmit: genAsmOrEmitStmt(p, it.sons[1])
else: discard else: discard
proc genCast(p: PProc, n: PNode, r: var TCompRes) =
var dest = skipTypes(n.typ, abstractVarRange)
var src = skipTypes(n.sons[1].typ, abstractVarRange)
gen(p, n.sons[1], r)
if dest.kind == src.kind:
# no-op conversion
return
let toInt = (dest.kind in tyInt .. tyInt32)
let toUint = (dest.kind in tyUInt .. tyUInt32)
let fromInt = (src.kind in tyInt .. tyInt32)
let fromUint = (src.kind in tyUInt .. tyUInt32)
if toUint and (fromInt or fromUint):
let trimmer = unsignedTrimmer(dest.size)
r.res = "($1 $2)" % [r.res, trimmer]
elif toInt:
if fromInt:
let trimmer = unsignedTrimmer(dest.size)
r.res = "($1 $2)" % [r.res, trimmer]
elif fromUint:
if src.size == 4 and dest.size == 4:
r.res = "($1|0)" % [r.res]
else:
let trimmer = unsignedTrimmer(dest.size)
let minuend = case dest.size
of 1: "0xfe"
of 2: "0xfffe"
of 4: "0xfffffffe"
else: ""
r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer]
proc gen(p: PProc, n: PNode, r: var TCompRes) = proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.typ = etyNone r.typ = etyNone
r.kind = resNone r.kind = resNone
@ -1596,10 +1659,10 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.kind = resExpr r.kind = resExpr
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if skipTypes(n.typ, abstractVarRange).kind == tyString: if skipTypes(n.typ, abstractVarRange).kind == tyString:
useMagic(p, "cstrToNimstr") useMagic(p, "makeNimstrLit")
r.res = "cstrToNimstr($1)" % [makeJSString(n.strVal)] r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
else: else:
r.res = makeJSString(n.strVal) r.res = makeJSString(n.strVal, false)
r.kind = resExpr r.kind = resExpr
of nkFloatLit..nkFloat64Lit: of nkFloatLit..nkFloat64Lit:
let f = n.floatVal let f = n.floatVal
@ -1630,7 +1693,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkCheckedFieldExpr: genCheckedFieldAccess(p, n, r) of nkCheckedFieldExpr: genCheckedFieldAccess(p, n, r)
of nkObjDownConv: gen(p, n.sons[0], r) of nkObjDownConv: gen(p, n.sons[0], r)
of nkObjUpConv: upConv(p, n, r) of nkObjUpConv: upConv(p, n, r)
of nkCast: gen(p, n.sons[1], r) of nkCast: genCast(p, n, r)
of nkChckRangeF: genRangeChck(p, n, r, "chckRangeF") of nkChckRangeF: genRangeChck(p, n, r, "chckRangeF")
of nkChckRange64: genRangeChck(p, n, r, "chckRange64") of nkChckRange64: genRangeChck(p, n, r, "chckRange64")
of nkChckRange: genRangeChck(p, n, r, "chckRange") of nkChckRange: genRangeChck(p, n, r, "chckRange")

View file

@ -438,7 +438,7 @@ proc lsub(n: PNode): int =
len("if_:_") len("if_:_")
of nkElifExpr: result = lsons(n) + len("_elif_:_") of nkElifExpr: result = lsons(n) + len("_elif_:_")
of nkElseExpr: result = lsub(n.sons[0]) + len("_else:_") # type descriptions of nkElseExpr: result = lsub(n.sons[0]) + len("_else:_") # type descriptions
of nkTypeOfExpr: result = (if n.len > 0: lsub(n.sons[0]) else: 0)+len("type_") of nkTypeOfExpr: result = (if n.len > 0: lsub(n.sons[0]) else: 0)+len("type()")
of nkRefTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ref") of nkRefTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ref")
of nkPtrTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ptr") of nkPtrTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ptr")
of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var") of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
@ -1030,8 +1030,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
putWithSpace(g, tkColon, ":") putWithSpace(g, tkColon, ":")
gsub(g, n.sons[0]) gsub(g, n.sons[0])
of nkTypeOfExpr: of nkTypeOfExpr:
putWithSpace(g, tkType, "type") put(g, tkType, "type")
put(g, tkParLe, "(")
if n.len > 0: gsub(g, n.sons[0]) if n.len > 0: gsub(g, n.sons[0])
put(g, tkParRi, ")")
of nkRefTy: of nkRefTy:
if sonsLen(n) > 0: if sonsLen(n) > 0:
putWithSpace(g, tkRef, "ref") putWithSpace(g, tkRef, "ref")

View file

@ -15,15 +15,15 @@ Example:
try: try:
var a = readLine(f) var a = readLine(f)
var b = readLine(f) var b = readLine(f)
echo("sum: " & $(parseInt(a) + parseInt(b))) echo "sum: " & $(parseInt(a) + parseInt(b))
except OverflowError: except OverflowError:
echo("overflow!") echo "overflow!"
except ValueError: except ValueError:
echo("could not convert string to integer") echo "could not convert string to integer"
except IOError: except IOError:
echo("IO error!") echo "IO error!"
except: except:
echo("Unknown exception!") echo "Unknown exception!"
finally: finally:
close(f) close(f)

View file

@ -144,7 +144,7 @@ modules don't need to import a module's dependencies:
# B.MyObject has been imported implicitly here: # B.MyObject has been imported implicitly here:
var x: MyObject var x: MyObject
echo($x) echo $x
Note on paths Note on paths
----------- -----------

View file

@ -129,9 +129,9 @@ to supply any type of first argument for procedures:
.. code-block:: nim .. code-block:: nim
echo("abc".len) # is the same as echo(len("abc")) echo "abc".len # is the same as echo len "abc"
echo("abc".toUpper()) echo "abc".toUpper()
echo({'a', 'b', 'c'}.card) echo {'a', 'b', 'c'}.card
stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo") stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo")
Another way to look at the method call syntax is that it provides the missing Another way to look at the method call syntax is that it provides the missing
@ -486,7 +486,7 @@ state are automatically saved between calls. Example:
inc(i) inc(i)
for ch in items("hello world"): # `ch` is an iteration variable for ch in items("hello world"): # `ch` is an iteration variable
echo(ch) echo ch
The compiler generates code as if the programmer would have written this: The compiler generates code as if the programmer would have written this:
@ -494,7 +494,7 @@ The compiler generates code as if the programmer would have written this:
var i = 0 var i = 0
while i < len(a): while i < len(a):
var ch = a[i] var ch = a[i]
echo(ch) echo ch
inc(i) inc(i)
If the iterator yields a tuple, there can be as many iteration variables If the iterator yields a tuple, there can be as many iteration variables

View file

@ -234,11 +234,11 @@ Example:
var name = readLine(stdin) var name = readLine(stdin)
if name == "Andreas": if name == "Andreas":
echo("What a nice name!") echo "What a nice name!"
elif name == "": elif name == "":
echo("Don't you have a name?") echo "Don't you have a name?"
else: else:
echo("Boring name...") echo "Boring name..."
The ``if`` statement is a simple way to make a branch in the control flow: The ``if`` statement is a simple way to make a branch in the control flow:
The expression after the keyword ``if`` is evaluated, if it is true The expression after the keyword ``if`` is evaluated, if it is true
@ -269,17 +269,17 @@ Example:
case readline(stdin) case readline(stdin)
of "delete-everything", "restart-computer": of "delete-everything", "restart-computer":
echo("permission denied") echo "permission denied"
of "go-for-a-walk": echo("please yourself") of "go-for-a-walk": echo "please yourself"
else: echo("unknown command") else: echo "unknown command"
# indentation of the branches is also allowed; and so is an optional colon # indentation of the branches is also allowed; and so is an optional colon
# after the selecting expression: # after the selecting expression:
case readline(stdin): case readline(stdin):
of "delete-everything", "restart-computer": of "delete-everything", "restart-computer":
echo("permission denied") echo "permission denied"
of "go-for-a-walk": echo("please yourself") of "go-for-a-walk": echo "please yourself"
else: echo("unknown command") else: echo "unknown command"
The ``case`` statement is similar to the if statement, but it represents The ``case`` statement is similar to the if statement, but it represents
@ -326,13 +326,13 @@ Example:
.. code-block:: nim .. code-block:: nim
when sizeof(int) == 2: when sizeof(int) == 2:
echo("running on a 16 bit system!") echo "running on a 16 bit system!"
elif sizeof(int) == 4: elif sizeof(int) == 4:
echo("running on a 32 bit system!") echo "running on a 32 bit system!"
elif sizeof(int) == 8: elif sizeof(int) == 8:
echo("running on a 64 bit system!") echo "running on a 64 bit system!"
else: else:
echo("cannot happen!") echo "cannot happen!"
The ``when`` statement is almost identical to the ``if`` statement with some The ``when`` statement is almost identical to the ``if`` statement with some
exceptions: exceptions:
@ -435,7 +435,7 @@ Example:
if a[j][i] == 7: if a[j][i] == 7:
found = true found = true
break myblock # leave the block, in this case both for-loops break myblock # leave the block, in this case both for-loops
echo(found) echo found
The block statement is a means to group statements to a (named) ``block``. The block statement is a means to group statements to a (named) ``block``.
Inside the block, the ``break`` statement is allowed to leave the block Inside the block, the ``break`` statement is allowed to leave the block
@ -462,10 +462,10 @@ While statement
Example: Example:
.. code-block:: nim .. code-block:: nim
echo("Please tell me your password: \n") echo "Please tell me your password: \n"
var pw = readLine(stdin) var pw = readLine(stdin)
while pw != "12345": while pw != "12345":
echo("Wrong password! Next try: \n") echo "Wrong password! Next try: \n"
pw = readLine(stdin) pw = readLine(stdin)

View file

@ -546,7 +546,7 @@ so that the builtin ``echo`` proc does what is expected:
.. code-block:: nim .. code-block:: nim
proc echo*(x: varargs[expr, `$`]) {...} proc echo*(x: varargs[expr, `$`]) {...}
echo(@[1, 2, 3]) echo @[1, 2, 3]
# prints "@[1, 2, 3]" and not "123" # prints "@[1, 2, 3]" and not "123"

View file

@ -333,7 +333,7 @@ Nim provides language integration with external IDEs through the
idetools command. See the documentation of `idetools <idetools.html>`_ idetools command. See the documentation of `idetools <idetools.html>`_
for further information. for further information.
..
Nim interactive mode Nim interactive mode
==================== ====================
@ -341,7 +341,7 @@ The Nim compiler supports an interactive mode. This is also known as
a `REPL`:idx: (*read eval print loop*). If Nim has been built with the a `REPL`:idx: (*read eval print loop*). If Nim has been built with the
``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal ``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal
input management. To start Nim in interactive mode use the command input management. To start Nim in interactive mode use the command
``nim i``. To quit use the ``quit()`` command. To determine whether an input ``nim secret``. To quit use the ``quit()`` command. To determine whether an input
line is an incomplete statement to be continued these rules are used: line is an incomplete statement to be continued these rules are used:
1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace). 1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace).

View file

@ -31,9 +31,9 @@ We start the tour with a modified "hello world" program:
.. code-block:: Nim .. code-block:: Nim
# This is a comment # This is a comment
echo("What's your name? ") echo "What's your name? "
var name: string = readLine(stdin) var name: string = readLine(stdin)
echo("Hi, ", name, "!") echo "Hi, ", name, "!"
Save this code to the file "greetings.nim". Now compile and run it:: Save this code to the file "greetings.nim". Now compile and run it::
@ -250,11 +250,11 @@ The if statement is one way to branch the control flow:
.. code-block:: nim .. code-block:: nim
let name = readLine(stdin) let name = readLine(stdin)
if name == "": if name == "":
echo("Poor soul, you lost your name?") echo "Poor soul, you lost your name?"
elif name == "name": elif name == "name":
echo("Very funny, your name is name.") echo "Very funny, your name is name."
else: else:
echo("Hi, ", name, "!") echo "Hi, ", name, "!"
There can be zero or more ``elif`` parts, and the ``else`` part is optional. There can be zero or more ``elif`` parts, and the ``else`` part is optional.
The keyword ``elif`` is short for ``else if``, and is useful to avoid The keyword ``elif`` is short for ``else if``, and is useful to avoid
@ -272,13 +272,13 @@ a multi-branch:
let name = readLine(stdin) let name = readLine(stdin)
case name case name
of "": of "":
echo("Poor soul, you lost your name?") echo "Poor soul, you lost your name?"
of "name": of "name":
echo("Very funny, your name is name.") echo "Very funny, your name is name."
of "Dave", "Frank": of "Dave", "Frank":
echo("Cool name!") echo "Cool name!"
else: else:
echo("Hi, ", name, "!") echo "Hi, ", name, "!"
As it can be seen, for an ``of`` branch a comma separated list of values is also As it can be seen, for an ``of`` branch a comma separated list of values is also
allowed. allowed.
@ -291,11 +291,11 @@ For integers or other ordinal types value ranges are also possible:
# this statement will be explained later: # this statement will be explained later:
from strutils import parseInt from strutils import parseInt
echo("A number please: ") echo "A number please: "
let n = parseInt(readLine(stdin)) let n = parseInt(readLine(stdin))
case n case n
of 0..2, 4..7: echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}") of 0..2, 4..7: echo "The number is in the set: {0, 1, 2, 4, 5, 6, 7}"
of 3, 8: echo("The number is 3 or 8") of 3, 8: echo "The number is 3 or 8"
However, the above code does not compile: the reason is that you have to cover However, the above code does not compile: the reason is that you have to cover
every value that ``n`` may contain, but the code only handles the values every value that ``n`` may contain, but the code only handles the values
@ -306,8 +306,8 @@ the compiler that for every other value nothing should be done:
.. code-block:: nim .. code-block:: nim
... ...
case n case n
of 0..2, 4..7: echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}") of 0..2, 4..7: echo "The number is in the set: {0, 1, 2, 4, 5, 6, 7}"
of 3, 8: echo("The number is 3 or 8") of 3, 8: echo "The number is 3 or 8"
else: discard else: discard
The empty `discard statement`_ is a *do nothing* statement. The compiler knows The empty `discard statement`_ is a *do nothing* statement. The compiler knows
@ -327,10 +327,10 @@ The while statement is a simple looping construct:
.. code-block:: nim .. code-block:: nim
echo("What's your name? ") echo "What's your name? "
var name = readLine(stdin) var name = readLine(stdin)
while name == "": while name == "":
echo("Please tell me your name: ") echo "Please tell me your name: "
name = readLine(stdin) name = readLine(stdin)
# no ``var``, because we do not declare a new variable here # no ``var``, because we do not declare a new variable here
@ -346,9 +346,9 @@ provides. The example uses the built-in `countup <system.html#countup>`_
iterator: iterator:
.. code-block:: nim .. code-block:: nim
echo("Counting to ten: ") echo "Counting to ten: "
for i in countup(1, 10): for i in countup(1, 10):
echo($i) echo $i
# --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines
The built-in `$ <system.html#$>`_ operator turns an integer (``int``) and many The built-in `$ <system.html#$>`_ operator turns an integer (``int``) and many
@ -358,19 +358,19 @@ other types into a string. The variable ``i`` is implicitly declared by the
Each value is ``echo``-ed. This code does the same: Each value is ``echo``-ed. This code does the same:
.. code-block:: nim .. code-block:: nim
echo("Counting to 10: ") echo "Counting to 10: "
var i = 1 var i = 1
while i <= 10: while i <= 10:
echo($i) echo $i
inc(i) # increment i by 1 inc(i) # increment i by 1
# --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines
Counting down can be achieved as easily (but is less often needed): Counting down can be achieved as easily (but is less often needed):
.. code-block:: nim .. code-block:: nim
echo("Counting down from 10 to 1: ") echo "Counting down from 10 to 1: "
for i in countdown(10, 1): for i in countdown(10, 1):
echo($i) echo $i
# --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines # --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines
Since counting up occurs so often in programs, Nim also has a `.. Since counting up occurs so often in programs, Nim also has a `..
@ -390,7 +390,7 @@ outside the loop:
.. code-block:: nim .. code-block:: nim
while false: while false:
var x = "hi" var x = "hi"
echo(x) # does not work echo x # does not work
A while (for) statement introduces an implicit block. Identifiers A while (for) statement introduces an implicit block. Identifiers
are only visible within the block they have been declared. The ``block`` are only visible within the block they have been declared. The ``block``
@ -399,7 +399,7 @@ statement can be used to open a new block explicitly:
.. code-block:: nim .. code-block:: nim
block myblock: block myblock:
var x = "hi" var x = "hi"
echo(x) # does not work either echo x # does not work either
The block's *label* (``myblock`` in the example) is optional. The block's *label* (``myblock`` in the example) is optional.
@ -412,18 +412,18 @@ innermost construct, unless a label of a block is given:
.. code-block:: nim .. code-block:: nim
block myblock: block myblock:
echo("entering block") echo "entering block"
while true: while true:
echo("looping") echo "looping"
break # leaves the loop, but not the block break # leaves the loop, but not the block
echo("still in block") echo "still in block"
block myblock2: block myblock2:
echo("entering block") echo "entering block"
while true: while true:
echo("looping") echo "looping"
break myblock2 # leaves the block (and the loop) break myblock2 # leaves the block (and the loop)
echo("still in block") echo "still in block"
Continue statement Continue statement
@ -435,7 +435,7 @@ the next iteration immediately:
while true: while true:
let x = readLine(stdin) let x = readLine(stdin)
if x == "": continue if x == "": continue
echo(x) echo x
When statement When statement
@ -446,13 +446,13 @@ Example:
.. code-block:: nim .. code-block:: nim
when system.hostOS == "windows": when system.hostOS == "windows":
echo("running on Windows!") echo "running on Windows!"
elif system.hostOS == "linux": elif system.hostOS == "linux":
echo("running on Linux!") echo "running on Linux!"
elif system.hostOS == "macosx": elif system.hostOS == "macosx":
echo("running on Mac OS X!") echo "running on Mac OS X!"
else: else:
echo("unknown operating system") echo "unknown operating system"
The ``when`` statement is almost identical to the ``if`` statement with some The ``when`` statement is almost identical to the ``if`` statement with some
differences: differences:
@ -533,17 +533,17 @@ procedures are defined with the ``proc`` keyword:
.. code-block:: nim .. code-block:: nim
proc yes(question: string): bool = proc yes(question: string): bool =
echo(question, " (y/n)") echo question, " (y/n)"
while true: while true:
case readLine(stdin) case readLine(stdin)
of "y", "Y", "yes", "Yes": return true of "y", "Y", "yes", "Yes": return true
of "n", "N", "no", "No": return false of "n", "N", "no", "No": return false
else: echo("Please be clear: yes or no") else: echo "Please be clear: yes or no"
if yes("Should I delete all your important files?"): if yes("Should I delete all your important files?"):
echo("I'm sorry Dave, I'm afraid I can't do that.") echo "I'm sorry Dave, I'm afraid I can't do that."
else: else:
echo("I think you know what the problem is just as well as I do.") echo "I think you know what the problem is just as well as I do."
This example shows a procedure named ``yes`` that asks the user a ``question`` This example shows a procedure named ``yes`` that asks the user a ``question``
and returns true if they answered "yes" (or something similar) and returns and returns true if they answered "yes" (or something similar) and returns
@ -611,8 +611,8 @@ caller, a ``var`` parameter can be used:
var var
x, y: int x, y: int
divmod(8, 5, x, y) # modifies x and y divmod(8, 5, x, y) # modifies x and y
echo(x) echo x
echo(y) echo y
In the example, ``res`` and ``remainder`` are `var parameters`. In the example, ``res`` and ``remainder`` are `var parameters`.
Var parameters can be modified by the procedure and the changes are Var parameters can be modified by the procedure and the changes are
@ -701,8 +701,8 @@ Nim provides the ability to overload procedures similar to C++:
if x: result = "true" if x: result = "true"
else: result = "false" else: result = "false"
echo(toString(13)) # calls the toString(x: int) proc echo toString(13) # calls the toString(x: int) proc
echo(toString(true)) # calls the toString(x: bool) proc echo toString(true) # calls the toString(x: bool) proc
(Note that ``toString`` is usually the `$ <system.html#$>`_ operator in (Note that ``toString`` is usually the `$ <system.html#$>`_ operator in
Nim.) The compiler chooses the most appropriate proc for the ``toString`` Nim.) The compiler chooses the most appropriate proc for the ``toString``
@ -743,7 +743,7 @@ The "``" notation can also be used to call an operator just like any other
procedure: procedure:
.. code-block:: nim .. code-block:: nim
if `==`( `+`(3, 4), 7): echo("True") if `==`( `+`(3, 4), 7): echo "True"
Forward declarations Forward declarations
@ -790,9 +790,9 @@ Iterators
Let's return to the boring counting example: Let's return to the boring counting example:
.. code-block:: nim .. code-block:: nim
echo("Counting to ten: ") echo "Counting to ten: "
for i in countup(1, 10): for i in countup(1, 10):
echo($i) echo $i
Can a `countup <system.html#countup>`_ proc be written that supports this Can a `countup <system.html#countup>`_ proc be written that supports this
loop? Lets try: loop? Lets try:
@ -1000,15 +1000,15 @@ there is a difference between the ``$`` and ``repr`` outputs:
myString = "nim" myString = "nim"
myInteger = 42 myInteger = 42
myFloat = 3.14 myFloat = 3.14
echo($myBool, ":", repr(myBool)) echo $myBool, ":", repr(myBool)
# --> true:true # --> true:true
echo($myCharacter, ":", repr(myCharacter)) echo $myCharacter, ":", repr(myCharacter)
# --> n:'n' # --> n:'n'
echo($myString, ":", repr(myString)) echo $myString, ":", repr(myString)
# --> nim:0x10fa8c050"nim" # --> nim:0x10fa8c050"nim"
echo($myInteger, ":", repr(myInteger)) echo $myInteger, ":", repr(myInteger)
# --> 42:42 # --> 42:42
echo($myFloat, ":", repr(myFloat)) echo $myFloat, ":", repr(myFloat)
# --> 3.1400000000000001e+00:3.1400000000000001e+00 # --> 3.1400000000000001e+00:3.1400000000000001e+00
@ -1040,7 +1040,7 @@ at runtime by 0, the second by 1 and so on. Example:
north, east, south, west north, east, south, west
var x = south # `x` is of type `Direction`; its value is `south` var x = south # `x` is of type `Direction`; its value is `south`
echo($x) # writes "south" to `stdout` echo $x # writes "south" to `stdout`
All comparison operators can be used with enumeration types. All comparison operators can be used with enumeration types.
@ -1133,7 +1133,7 @@ Arrays can be constructed via ``[]``:
x: IntArray x: IntArray
x = [1, 2, 3, 4, 5, 6] x = [1, 2, 3, 4, 5, 6]
for i in low(x)..high(x): for i in low(x)..high(x):
echo(x[i]) echo x[i]
The notation ``x[i]`` is used to access the i-th element of ``x``. The notation ``x[i]`` is used to access the i-th element of ``x``.
Array access is always bounds checked (at compile-time or at runtime). These Array access is always bounds checked (at compile-time or at runtime). These
@ -1208,7 +1208,7 @@ to specify a range from zero to the specified index minus one:
x = [1, 2, 3, 4, 5, 6] x = [1, 2, 3, 4, 5, 6]
y = x y = x
for i in low(x)..high(x): for i in low(x)..high(x):
echo(x[i], y[i]) echo x[i], y[i]
Sequences Sequences
@ -1254,13 +1254,13 @@ value. Here the ``for`` statement is looping over the results from the
.. code-block:: nim .. code-block:: nim
for i in @[3, 4, 5]: for i in @[3, 4, 5]:
echo($i) echo $i
# --> 3 # --> 3
# --> 4 # --> 4
# --> 5 # --> 5
for i, value in @[3, 4, 5]: for i, value in @[3, 4, 5]:
echo("index: ", $i, ", value:", $value) echo "index: ", $i, ", value:", $value
# --> index: 0, value:3 # --> index: 0, value:3
# --> index: 1, value:4 # --> index: 1, value:4
# --> index: 2, value:5 # --> index: 2, value:5
@ -1386,16 +1386,16 @@ integer.
# the same, but less readable: # the same, but less readable:
person = ("Peter", 30) person = ("Peter", 30)
echo(person.name) # "Peter" echo person.name # "Peter"
echo(person.age) # 30 echo person.age # 30
echo(person[0]) # "Peter" echo person[0] # "Peter"
echo(person[1]) # 30 echo person[1] # 30
# You don't need to declare tuples in a separate type section. # You don't need to declare tuples in a separate type section.
var building: tuple[street: string, number: int] var building: tuple[street: string, number: int]
building = ("Rue del Percebe", 13) building = ("Rue del Percebe", 13)
echo(building.street) echo building.street
# The following line does not compile, they are different tuples! # The following line does not compile, they are different tuples!
#person = building #person = building
@ -1503,7 +1503,7 @@ techniques.
Example: Example:
.. code-block:: nim .. code-block:: nim
proc echoItem(x: int) = echo(x) proc echoItem(x: int) = echo x
proc forEach(action: proc (x: int)) = proc forEach(action: proc (x: int)) =
const const

View file

@ -204,9 +204,9 @@ for any type:
.. code-block:: nim .. code-block:: nim
echo("abc".len) # is the same as echo(len("abc")) echo "abc".len # is the same as echo len("abc")
echo("abc".toUpper()) echo "abc".toUpper()
echo({'a', 'b', 'c'}.card) echo {'a', 'b', 'c'}.card
stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo") stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo")
(Another way to look at the method call syntax is that it provides the missing (Another way to look at the method call syntax is that it provides the missing
@ -1000,7 +1000,9 @@ JavaScript-compatible code you should remember the following:
- ``addr`` and ``ptr`` have slightly different semantic meaning in JavaScript. - ``addr`` and ``ptr`` have slightly different semantic meaning in JavaScript.
It is recommended to avoid those if you're not sure how they are translated It is recommended to avoid those if you're not sure how they are translated
to JavaScript. to JavaScript.
- ``cast[T](x)`` in JavaScript is translated to ``(x)``. - ``cast[T](x)`` in JavaScript is translated to ``(x)``, except for casting
between signed/unsigned ints, in which case it behaves as static cast in
C language.
- ``cstring`` in JavaScript means JavaScript string. It is a good practice to - ``cstring`` in JavaScript means JavaScript string. It is a good practice to
use ``cstring`` only when it is semantically appropriate. E.g. don't use use ``cstring`` only when it is semantically appropriate. E.g. don't use
``cstring`` as a binary data buffer. ``cstring`` as a binary data buffer.

View file

@ -12,7 +12,7 @@
## report at program exit. ## report at program exit.
when not defined(profiler) and not defined(memProfiler): when not defined(profiler) and not defined(memProfiler):
{.warning: "Profiling support is turned off!".} {.error: "Profiling support is turned off! Enable profiling by passing `--profiler:on --stackTrace:on` to the compiler (see the Nim Compiler User Guide for more options).".}
# We don't want to profile the profiling code ... # We don't want to profile the profiling code ...
{.push profiler: off.} {.push profiler: off.}

View file

@ -567,7 +567,9 @@ when declared(getEnv) or defined(nimscript):
var path = string(getEnv("PATH")) var path = string(getEnv("PATH"))
for candidate in split(path, PathSep): for candidate in split(path, PathSep):
when defined(windows): when defined(windows):
var x = candidate / result var x = (if candidate[0] == '"' and candidate[^1] == '"':
substr(candidate, 1, candidate.len-2) else: candidate) /
result
else: else:
var x = expandTilde(candidate) / result var x = expandTilde(candidate) / result
if existsFile(x): return x if existsFile(x): return x

View file

@ -886,7 +886,7 @@ elif not defined(useNimRtl):
discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error)) discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error))
exitnow(1) exitnow(1)
when defined(macosx) or defined(freebsd) or defined(netbsd) or defined(android): when not defined(uClibc) and (not defined(linux) or defined(android)):
var environ {.importc.}: cstringArray var environ {.importc.}: cstringArray
proc startProcessAfterFork(data: ptr StartProcessData) = proc startProcessAfterFork(data: ptr StartProcessData) =
@ -916,17 +916,16 @@ elif not defined(useNimRtl):
discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC) discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC)
if data.optionPoUsePath: if data.optionPoUsePath:
when defined(macosx) or defined(freebsd) or defined(netbsd) or defined(android): when defined(uClibc):
# uClibc environment (OpenWrt included) doesn't have the full execvpe
discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
elif defined(linux) and not defined(android):
discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv)
else:
# MacOSX doesn't have execvpe, so we need workaround. # MacOSX doesn't have execvpe, so we need workaround.
# On MacOSX we can arrive here only from fork, so this is safe: # On MacOSX we can arrive here only from fork, so this is safe:
environ = data.sysEnv environ = data.sysEnv
discard execvp(data.sysCommand, data.sysArgs) discard execvp(data.sysCommand, data.sysArgs)
else:
when defined(uClibc):
# uClibc environment (OpenWrt included) doesn't have the full execvpe
discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
else:
discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv)
else: else:
discard execve(data.sysCommand, data.sysArgs, data.sysEnv) discard execve(data.sysCommand, data.sysArgs, data.sysEnv)

View file

@ -688,7 +688,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %% sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %%
s == 0, "rawDealloc 3") s == 0, "rawDealloc 3")
var f = cast[ptr FreeCell](p) var f = cast[ptr FreeCell](p)
#echo("setting to nil: ", $cast[TAddress](addr(f.zeroField))) #echo("setting to nil: ", $cast[ByteAddress](addr(f.zeroField)))
sysAssert(f.zeroField != 0, "rawDealloc 1") sysAssert(f.zeroField != 0, "rawDealloc 1")
f.zeroField = 0 f.zeroField = 0
f.next = c.freeList f.next = c.freeList

View file

@ -659,7 +659,7 @@ when useMarkForDebug or useBackupGc:
proc stackMarkS(gch: var GcHeap, p: pointer) {.inline.} = proc stackMarkS(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells: # the addresses are not as cells on the stack, so turn them to cells:
var cell = usrToCell(p) var cell = usrToCell(p)
var c = cast[TAddress](cell) var c = cast[ByteAddress](cell)
if c >% PageSize: if c >% PageSize:
# fast check: does it look like a cell? # fast check: does it look like a cell?
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
@ -805,8 +805,8 @@ proc markThreadStacks(gch: var GcHeap) =
while it != nil: while it != nil:
# mark registers: # mark registers:
for i in 0 .. high(it.registers): gcMark(gch, it.registers[i]) for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
var sp = cast[TAddress](it.stackBottom) var sp = cast[ByteAddress](it.stackBottom)
var max = cast[TAddress](it.stackTop) var max = cast[ByteAddress](it.stackTop)
# XXX stack direction? # XXX stack direction?
# XXX unroll this loop: # XXX unroll this loop:
while sp <=% max: while sp <=% max:

View file

@ -131,9 +131,9 @@ when defined(sparc): # For SPARC architecture.
proc isOnStack(p: pointer): bool = proc isOnStack(p: pointer): bool =
var stackTop {.volatile.}: pointer var stackTop {.volatile.}: pointer
stackTop = addr(stackTop) stackTop = addr(stackTop)
var b = cast[TAddress](gch.stackBottom) var b = cast[ByteAddress](gch.stackBottom)
var a = cast[TAddress](stackTop) var a = cast[ByteAddress](stackTop)
var x = cast[TAddress](p) var x = cast[ByteAddress](p)
result = a <=% x and x <=% b result = a <=% x and x <=% b
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} = template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
@ -150,7 +150,7 @@ when defined(sparc): # For SPARC architecture.
# Addresses decrease as the stack grows. # Addresses decrease as the stack grows.
while sp <= max: while sp <= max:
gcMark(gch, sp[]) gcMark(gch, sp[])
sp = cast[PPointer](cast[TAddress](sp) +% sizeof(pointer)) sp = cast[PPointer](cast[ByteAddress](sp) +% sizeof(pointer))
elif defined(ELATE): elif defined(ELATE):
{.error: "stack marking code is to be written for this architecture".} {.error: "stack marking code is to be written for this architecture".}

View file

@ -165,15 +165,46 @@ proc SetConstr() {.varargs, asmNoStackFrame, compilerproc.} =
return result; return result;
""" """
proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} = proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
asm """ {.emit: """
var result = []; var ln = `c`.length;
for (var i = 0; i < `c`.length; ++i) { var result = new Array(ln + 1);
var i = 0;
for (; i < ln; ++i) {
result[i] = `c`.charCodeAt(i); result[i] = `c`.charCodeAt(i);
} }
result[result.length] = 0; // terminating zero result[i] = 0; // terminating zero
return result; return result;
""" """.}
proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
{.emit: """
var ln = `c`.length;
var result = new Array(ln);
var r = 0;
for (var i = 0; i < ln; ++i) {
var ch = `c`.charCodeAt(i);
if (ch < 128) {
result[r] = ch;
}
else if((ch > 127) && (ch < 2048)) {
result[r] = (ch >> 6) | 192;
++r;
result[r] = (ch & 63) | 128;
}
else {
result[r] = (ch >> 12) | 224;
++r;
result[r] = ((ch >> 6) & 63) | 128;
++r;
result[r] = (ch & 63) | 128;
}
++r;
}
result[r] = 0; // terminating zero
return result;
""".}
proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
asm """ asm """

View file

@ -496,13 +496,12 @@ type
data: array[MD5_LBLOCK, MD5_LONG] data: array[MD5_LBLOCK, MD5_LONG]
num: cuint num: cuint
{.pragma: ic, importc: "$1".}
{.push callconv:cdecl, dynlib:DLLUtilName.} {.push callconv:cdecl, dynlib:DLLUtilName.}
proc md5_Init*(c: var MD5_CTX): cint{.ic.} proc md5_Init*(c: var MD5_CTX): cint{.importc: "MD5_Init".}
proc md5_Update*(c: var MD5_CTX; data: pointer; len: csize): cint{.ic.} proc md5_Update*(c: var MD5_CTX; data: pointer; len: csize): cint{.importc: "MD5_Update".}
proc md5_Final*(md: cstring; c: var MD5_CTX): cint{.ic.} proc md5_Final*(md: cstring; c: var MD5_CTX): cint{.importc: "MD5_Final".}
proc md5*(d: ptr cuchar; n: csize; md: ptr cuchar): ptr cuchar{.ic.} proc md5*(d: ptr cuchar; n: csize; md: ptr cuchar): ptr cuchar{.importc: "MD5".}
proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.ic.} proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.importc: "MD5_Transform".}
{.pop.} {.pop.}
from strutils import toHex,toLower from strutils import toHex,toLower

View file

@ -39,9 +39,9 @@ To build from source you will need:
If you are on a fairly modern *nix system, the following steps should work: If you are on a fairly modern *nix system, the following steps should work:
``` ```
$ git clone git://github.com/nim-lang/Nim.git $ git clone https://github.com/nim-lang/Nim.git
$ cd Nim $ cd Nim
$ git clone --depth 1 git://github.com/nim-lang/csources $ git clone --depth 1 https://github.com/nim-lang/csources
$ cd csources && sh build.sh $ cd csources && sh build.sh
$ cd .. $ cd ..
$ bin/nim c koch $ bin/nim c koch

View file

@ -3,8 +3,7 @@ discard """
Hello''' Hello'''
""" """
# bug #2581 block: # bug #2581
const someVars = [ "Hello" ] const someVars = [ "Hello" ]
var someVars2 = [ "Hello" ] var someVars2 = [ "Hello" ]
@ -22,3 +21,58 @@ proc getSomeVar2: string =
echo getSomeVar() echo getSomeVar()
echo getSomeVar2() echo getSomeVar2()
block: # Test compile-time binary data generation, invalid unicode
proc signatureMaker(): string {. compiletime .} =
const signatureBytes = [137, 80, 78, 71, 13, 10, 26, 10]
result = ""
for c in signatureBytes: result.add chr(c)
const cSig = signatureMaker()
var rSig = newString(8)
rSig[0] = chr(137)
rSig[1] = chr(80)
rSig[2] = chr(78)
rSig[3] = chr(71)
rSig[4] = chr(13)
rSig[5] = chr(10)
rSig[6] = chr(26)
rSig[7] = chr(10)
doAssert(rSig == cSig)
block: # Test unicode strings
const constStr = "Привет!"
var jsStr : cstring
{.emit: """`jsStr`[0] = "Привет!";""".}
doAssert($jsStr == constStr)
var runtimeStr = "При"
runtimeStr &= "вет!"
doAssert(runtimeStr == constStr)
block: # Conversions from/to cstring
proc stringSaysHelloInRussian(s: cstring): bool =
{.emit: """`result` = (`s` === "Привет!");""".}
doAssert(stringSaysHelloInRussian("Привет!"))
const constStr = "Привет!"
doAssert(stringSaysHelloInRussian(constStr))
var rtStr = "Привет!"
doAssert(stringSaysHelloInRussian(rtStr))
block: # String case of
const constStr = "Привет!"
var s = "Привет!"
case s
of constStr: discard
else: doAssert(false)
case s
of "Привет!": discard
else: doAssert(false)

View file

@ -23,23 +23,28 @@ template test(opr, a, b, c: expr): stmt {.immediate.} =
test(`+`, 12'i8, -13'i16, -1'i16) test(`+`, 12'i8, -13'i16, -1'i16)
test(`shl`, 0b11, 0b100, 0b110000) test(`shl`, 0b11, 0b100, 0b110000)
when not defined(js):
test(`shl`, 0b11'i32, 0b100'i64, 0b110000'i64) test(`shl`, 0b11'i32, 0b100'i64, 0b110000'i64)
test(`shl`, 0b11'i32, 0b100'i32, 0b110000'i32) test(`shl`, 0b11'i32, 0b100'i32, 0b110000'i32)
test(`or`, 0xf0f0'i16, 0x0d0d'i16, 0xfdfd'i16) test(`or`, 0xf0f0'i16, 0x0d0d'i16, 0xfdfd'i16)
test(`and`, 0xf0f0'i16, 0xfdfd'i16, 0xf0f0'i16) test(`and`, 0xf0f0'i16, 0xfdfd'i16, 0xf0f0'i16)
when not defined(js):
test(`shr`, 0xffffffffffffffff'i64, 0x4'i64, 0x0fffffffffffffff'i64) test(`shr`, 0xffffffffffffffff'i64, 0x4'i64, 0x0fffffffffffffff'i64)
test(`shr`, 0xffff'i16, 0x4'i16, 0x0fff'i16) test(`shr`, 0xffff'i16, 0x4'i16, 0x0fff'i16)
test(`shr`, 0xff'i8, 0x4'i8, 0x0f'i8) test(`shr`, 0xff'i8, 0x4'i8, 0x0f'i8)
when not defined(js):
test(`shr`, 0xffffffff'i64, 0x4'i64, 0x0fffffff'i64) test(`shr`, 0xffffffff'i64, 0x4'i64, 0x0fffffff'i64)
test(`shr`, 0xffffffff'i32, 0x4'i32, 0x0fffffff'i32) test(`shr`, 0xffffffff'i32, 0x4'i32, 0x0fffffff'i32)
when not defined(js):
test(`shl`, 0xffffffffffffffff'i64, 0x4'i64, 0xfffffffffffffff0'i64) test(`shl`, 0xffffffffffffffff'i64, 0x4'i64, 0xfffffffffffffff0'i64)
test(`shl`, 0xffff'i16, 0x4'i16, 0xfff0'i16) test(`shl`, 0xffff'i16, 0x4'i16, 0xfff0'i16)
test(`shl`, 0xff'i8, 0x4'i8, 0xf0'i8) test(`shl`, 0xff'i8, 0x4'i8, 0xf0'i8)
when not defined(js):
test(`shl`, 0xffffffff'i64, 0x4'i64, 0xffffffff0'i64) test(`shl`, 0xffffffff'i64, 0x4'i64, 0xffffffff0'i64)
test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32) test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32)
@ -50,5 +55,27 @@ proc unc(a: float): float =
echo int(unc(0.5)), " ", int(unc(-0.5)) echo int(unc(0.5)), " ", int(unc(-0.5))
echo int(0.5), " ", int(-0.5) echo int(0.5), " ", int(-0.5)
echo("Success") #OUT Success block: # Casts to uint
template testCast(fromValue: typed, toType: typed, expectedResult: typed) =
let src = fromValue
let dst = cast[toType](src)
if dst != expectedResult:
echo "Casting ", astToStr(fromValue), " to ", astToStr(toType), " = ", dst.int, " instead of ", astToStr(expectedResult)
doAssert(dst == expectedResult)
testCast(-1'i16, uint16, 0xffff'u16)
testCast(0xffff'u16, int16, -1'i16)
testCast(0xff'u16, uint8, 0xff'u8)
testCast(0xffff'u16, uint8, 0xff'u8)
testCast(-1'i16, uint32, 0xffffffff'u32)
testCast(0xffffffff'u32, int32, -1)
testCast(0xfffffffe'u32, int32, -2'i32)
testCast(0xffffff'u32, int16, -1'i32)
testCast(-5'i32, uint8, 251'u8)
echo("Success") #OUT Success

View file

@ -220,7 +220,7 @@ proc jsTests(r: var TResults, cat: Category, options: string) =
"actiontable/tactiontable", "method/tmultim1", "actiontable/tactiontable", "method/tmultim1",
"method/tmultim3", "method/tmultim4", "method/tmultim3", "method/tmultim4",
"varres/tvarres0", "varres/tvarres3", "varres/tvarres4", "varres/tvarres0", "varres/tvarres3", "varres/tvarres4",
"varres/tvartup", "misc/tunsignedinc"]: "varres/tvartup", "misc/tints", "misc/tunsignedinc"]:
test "tests/" & testfile & ".nim" test "tests/" & testfile & ".nim"
for testfile in ["pure/strutils"]: for testfile in ["pure/strutils"]: