mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-01 17:41:17 +00:00
Merge branch 'devel' of github.com:nim-lang/Nim into devel
This commit is contained in:
@@ -50,10 +50,10 @@ proc importcSymbol*(sym: PSym): PNode =
|
||||
# that contains the address instead:
|
||||
result = newNodeIT(nkPtrLit, sym.info, sym.typ)
|
||||
case name
|
||||
of "stdin": result.intVal = cast[TAddress](system.stdin)
|
||||
of "stdout": result.intVal = cast[TAddress](system.stdout)
|
||||
of "stderr": result.intVal = cast[TAddress](system.stderr)
|
||||
of "vmErrnoWrapper": result.intVal = cast[TAddress](myerrno)
|
||||
of "stdin": result.intVal = cast[ByteAddress](system.stdin)
|
||||
of "stdout": result.intVal = cast[ByteAddress](system.stdout)
|
||||
of "stderr": result.intVal = cast[ByteAddress](system.stderr)
|
||||
of "vmErrnoWrapper": result.intVal = cast[ByteAddress](myerrno)
|
||||
else:
|
||||
let lib = sym.annex
|
||||
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)
|
||||
theAddr = dllhandle.symAddr(name)
|
||||
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 =
|
||||
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 wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
|
||||
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 =
|
||||
## 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:
|
||||
result = n
|
||||
else:
|
||||
awi(nkPtrLit, cast[TAddress](p))
|
||||
awi(nkPtrLit, cast[ByteAddress](p))
|
||||
of tyPtr, tyRef, tyVar:
|
||||
let p = rd(pointer, x)
|
||||
if p.isNil:
|
||||
setNil()
|
||||
elif n == nil or n.kind == nkPtrLit:
|
||||
awi(nkPtrLit, cast[TAddress](p))
|
||||
awi(nkPtrLit, cast[ByteAddress](p))
|
||||
elif n != nil and n.len == 1:
|
||||
internalAssert n.kind == nkRefTy
|
||||
n.sons[0] = unpack(p, typ.lastSon, n.sons[0])
|
||||
|
||||
@@ -163,8 +163,31 @@ proc mangleName(s: PSym): Rope =
|
||||
add(result, rope(s.id))
|
||||
s.loc.r = result
|
||||
|
||||
proc makeJSString(s: string): Rope =
|
||||
(if s.isNil: "null".rope else: strutils.escape(s).rope)
|
||||
proc escapeJSString(s: string): string =
|
||||
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
|
||||
|
||||
@@ -264,7 +287,7 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
||||
["", "", "($1 - $2)", "($1 - $2)"], # SubF64
|
||||
["", "", "($1 * $2)", "($1 * $2)"], # MulF64
|
||||
["", "", "($1 / $2)", "($1 / $2)"], # DivF64
|
||||
["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI
|
||||
["", "", "", ""], # ShrI
|
||||
["", "", "($1 << $2)", "($1 << $2)"], # ShlI
|
||||
["", "", "($1 & $2)", "($1 & $2)"], # BitandI
|
||||
["", "", "($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.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) =
|
||||
var x, y: TCompRes
|
||||
gen(p, n.sons[1], x)
|
||||
gen(p, n.sons[2], y)
|
||||
let trimmer = case n[1].typ.skipTypes(abstractRange).size
|
||||
of 1: "& 0xff"
|
||||
of 2: "& 0xffff"
|
||||
of 4: ">>> 0"
|
||||
else: ""
|
||||
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
|
||||
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:
|
||||
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) =
|
||||
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 mMulU: 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:
|
||||
arithAux(p, n, r, op, jsOps)
|
||||
r.kind = resExpr
|
||||
@@ -568,7 +600,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if stringSwitch:
|
||||
case e.kind
|
||||
of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ",
|
||||
[makeJSString(e.strVal)])
|
||||
[makeJSString(e.strVal, false)])
|
||||
else: internalError(e.info, "jsgen.genCaseStmt: 2")
|
||||
else:
|
||||
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 mLeStr: 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 mNew, mNewFinalize: genNew(p, n)
|
||||
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])
|
||||
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) =
|
||||
r.typ = etyNone
|
||||
r.kind = resNone
|
||||
@@ -1596,10 +1659,10 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.kind = resExpr
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if skipTypes(n.typ, abstractVarRange).kind == tyString:
|
||||
useMagic(p, "cstrToNimstr")
|
||||
r.res = "cstrToNimstr($1)" % [makeJSString(n.strVal)]
|
||||
useMagic(p, "makeNimstrLit")
|
||||
r.res = "makeNimstrLit($1)" % [makeJSString(n.strVal)]
|
||||
else:
|
||||
r.res = makeJSString(n.strVal)
|
||||
r.res = makeJSString(n.strVal, false)
|
||||
r.kind = resExpr
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
let f = n.floatVal
|
||||
@@ -1630,7 +1693,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of nkCheckedFieldExpr: genCheckedFieldAccess(p, n, r)
|
||||
of nkObjDownConv: gen(p, n.sons[0], 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 nkChckRange64: genRangeChck(p, n, r, "chckRange64")
|
||||
of nkChckRange: genRangeChck(p, n, r, "chckRange")
|
||||
|
||||
@@ -438,7 +438,7 @@ proc lsub(n: PNode): int =
|
||||
len("if_:_")
|
||||
of nkElifExpr: result = lsons(n) + len("_elif_:_")
|
||||
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 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")
|
||||
@@ -1030,8 +1030,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
putWithSpace(g, tkColon, ":")
|
||||
gsub(g, n.sons[0])
|
||||
of nkTypeOfExpr:
|
||||
putWithSpace(g, tkType, "type")
|
||||
put(g, tkType, "type")
|
||||
put(g, tkParLe, "(")
|
||||
if n.len > 0: gsub(g, n.sons[0])
|
||||
put(g, tkParRi, ")")
|
||||
of nkRefTy:
|
||||
if sonsLen(n) > 0:
|
||||
putWithSpace(g, tkRef, "ref")
|
||||
|
||||
@@ -15,15 +15,15 @@ Example:
|
||||
try:
|
||||
var a = readLine(f)
|
||||
var b = readLine(f)
|
||||
echo("sum: " & $(parseInt(a) + parseInt(b)))
|
||||
echo "sum: " & $(parseInt(a) + parseInt(b))
|
||||
except OverflowError:
|
||||
echo("overflow!")
|
||||
echo "overflow!"
|
||||
except ValueError:
|
||||
echo("could not convert string to integer")
|
||||
echo "could not convert string to integer"
|
||||
except IOError:
|
||||
echo("IO error!")
|
||||
echo "IO error!"
|
||||
except:
|
||||
echo("Unknown exception!")
|
||||
echo "Unknown exception!"
|
||||
finally:
|
||||
close(f)
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ modules don't need to import a module's dependencies:
|
||||
|
||||
# B.MyObject has been imported implicitly here:
|
||||
var x: MyObject
|
||||
echo($x)
|
||||
echo $x
|
||||
|
||||
Note on paths
|
||||
-----------
|
||||
|
||||
@@ -129,9 +129,9 @@ to supply any type of first argument for procedures:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
echo("abc".len) # is the same as echo(len("abc"))
|
||||
echo("abc".toUpper())
|
||||
echo({'a', 'b', 'c'}.card)
|
||||
echo "abc".len # is the same as echo len "abc"
|
||||
echo "abc".toUpper()
|
||||
echo {'a', 'b', 'c'}.card
|
||||
stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo")
|
||||
|
||||
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)
|
||||
|
||||
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:
|
||||
|
||||
@@ -494,7 +494,7 @@ The compiler generates code as if the programmer would have written this:
|
||||
var i = 0
|
||||
while i < len(a):
|
||||
var ch = a[i]
|
||||
echo(ch)
|
||||
echo ch
|
||||
inc(i)
|
||||
|
||||
If the iterator yields a tuple, there can be as many iteration variables
|
||||
|
||||
@@ -234,11 +234,11 @@ Example:
|
||||
var name = readLine(stdin)
|
||||
|
||||
if name == "Andreas":
|
||||
echo("What a nice name!")
|
||||
echo "What a nice name!"
|
||||
elif name == "":
|
||||
echo("Don't you have a name?")
|
||||
echo "Don't you have a name?"
|
||||
else:
|
||||
echo("Boring name...")
|
||||
echo "Boring name..."
|
||||
|
||||
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
|
||||
@@ -269,17 +269,17 @@ Example:
|
||||
|
||||
case readline(stdin)
|
||||
of "delete-everything", "restart-computer":
|
||||
echo("permission denied")
|
||||
of "go-for-a-walk": echo("please yourself")
|
||||
else: echo("unknown command")
|
||||
echo "permission denied"
|
||||
of "go-for-a-walk": echo "please yourself"
|
||||
else: echo "unknown command"
|
||||
|
||||
# indentation of the branches is also allowed; and so is an optional colon
|
||||
# after the selecting expression:
|
||||
case readline(stdin):
|
||||
of "delete-everything", "restart-computer":
|
||||
echo("permission denied")
|
||||
of "go-for-a-walk": echo("please yourself")
|
||||
else: echo("unknown command")
|
||||
echo "permission denied"
|
||||
of "go-for-a-walk": echo "please yourself"
|
||||
else: echo "unknown command"
|
||||
|
||||
|
||||
The ``case`` statement is similar to the if statement, but it represents
|
||||
@@ -326,13 +326,13 @@ Example:
|
||||
.. code-block:: nim
|
||||
|
||||
when sizeof(int) == 2:
|
||||
echo("running on a 16 bit system!")
|
||||
echo "running on a 16 bit system!"
|
||||
elif sizeof(int) == 4:
|
||||
echo("running on a 32 bit system!")
|
||||
echo "running on a 32 bit system!"
|
||||
elif sizeof(int) == 8:
|
||||
echo("running on a 64 bit system!")
|
||||
echo "running on a 64 bit system!"
|
||||
else:
|
||||
echo("cannot happen!")
|
||||
echo "cannot happen!"
|
||||
|
||||
The ``when`` statement is almost identical to the ``if`` statement with some
|
||||
exceptions:
|
||||
@@ -435,7 +435,7 @@ Example:
|
||||
if a[j][i] == 7:
|
||||
found = true
|
||||
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``.
|
||||
Inside the block, the ``break`` statement is allowed to leave the block
|
||||
@@ -462,10 +462,10 @@ While statement
|
||||
Example:
|
||||
|
||||
.. code-block:: nim
|
||||
echo("Please tell me your password: \n")
|
||||
echo "Please tell me your password: \n"
|
||||
var pw = readLine(stdin)
|
||||
while pw != "12345":
|
||||
echo("Wrong password! Next try: \n")
|
||||
echo "Wrong password! Next try: \n"
|
||||
pw = readLine(stdin)
|
||||
|
||||
|
||||
|
||||
@@ -546,7 +546,7 @@ so that the builtin ``echo`` proc does what is expected:
|
||||
.. code-block:: nim
|
||||
proc echo*(x: varargs[expr, `$`]) {...}
|
||||
|
||||
echo(@[1, 2, 3])
|
||||
echo @[1, 2, 3]
|
||||
# prints "@[1, 2, 3]" and not "123"
|
||||
|
||||
|
||||
|
||||
26
doc/nimc.txt
26
doc/nimc.txt
@@ -333,21 +333,21 @@ Nim provides language integration with external IDEs through the
|
||||
idetools command. See the documentation of `idetools <idetools.html>`_
|
||||
for further information.
|
||||
|
||||
..
|
||||
Nim interactive mode
|
||||
====================
|
||||
|
||||
Nim interactive mode
|
||||
====================
|
||||
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
|
||||
``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal
|
||||
input management. To start Nim in interactive mode use the command
|
||||
``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:
|
||||
|
||||
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
|
||||
``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal
|
||||
input management. To start Nim in interactive mode use the command
|
||||
``nim i``. To quit use the ``quit()`` command. To determine whether an input
|
||||
line is an incomplete statement to be continued these rules are used:
|
||||
|
||||
1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace).
|
||||
2. The line starts with a space (indentation).
|
||||
3. The line is within a triple quoted string literal. However, the detection
|
||||
does not work if the line contains more than one ``"""``.
|
||||
1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace).
|
||||
2. The line starts with a space (indentation).
|
||||
3. The line is within a triple quoted string literal. However, the detection
|
||||
does not work if the line contains more than one ``"""``.
|
||||
|
||||
|
||||
Nim for embedded systems
|
||||
|
||||
124
doc/tut1.txt
124
doc/tut1.txt
@@ -31,9 +31,9 @@ We start the tour with a modified "hello world" program:
|
||||
|
||||
.. code-block:: Nim
|
||||
# This is a comment
|
||||
echo("What's your name? ")
|
||||
echo "What's your name? "
|
||||
var name: string = readLine(stdin)
|
||||
echo("Hi, ", name, "!")
|
||||
echo "Hi, ", name, "!"
|
||||
|
||||
|
||||
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
|
||||
let name = readLine(stdin)
|
||||
if name == "":
|
||||
echo("Poor soul, you lost your name?")
|
||||
echo "Poor soul, you lost your name?"
|
||||
elif name == "name":
|
||||
echo("Very funny, your name is name.")
|
||||
echo "Very funny, your name is name."
|
||||
else:
|
||||
echo("Hi, ", name, "!")
|
||||
echo "Hi, ", name, "!"
|
||||
|
||||
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
|
||||
@@ -272,13 +272,13 @@ a multi-branch:
|
||||
let name = readLine(stdin)
|
||||
case name
|
||||
of "":
|
||||
echo("Poor soul, you lost your name?")
|
||||
echo "Poor soul, you lost your name?"
|
||||
of "name":
|
||||
echo("Very funny, your name is name.")
|
||||
echo "Very funny, your name is name."
|
||||
of "Dave", "Frank":
|
||||
echo("Cool name!")
|
||||
echo "Cool name!"
|
||||
else:
|
||||
echo("Hi, ", name, "!")
|
||||
echo "Hi, ", name, "!"
|
||||
|
||||
As it can be seen, for an ``of`` branch a comma separated list of values is also
|
||||
allowed.
|
||||
@@ -291,11 +291,11 @@ For integers or other ordinal types value ranges are also possible:
|
||||
# this statement will be explained later:
|
||||
from strutils import parseInt
|
||||
|
||||
echo("A number please: ")
|
||||
echo "A number please: "
|
||||
let n = parseInt(readLine(stdin))
|
||||
case n
|
||||
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 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"
|
||||
|
||||
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
|
||||
@@ -306,8 +306,8 @@ the compiler that for every other value nothing should be done:
|
||||
.. code-block:: nim
|
||||
...
|
||||
case n
|
||||
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 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"
|
||||
else: discard
|
||||
|
||||
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
|
||||
|
||||
echo("What's your name? ")
|
||||
echo "What's your name? "
|
||||
var name = readLine(stdin)
|
||||
while name == "":
|
||||
echo("Please tell me your name: ")
|
||||
echo "Please tell me your name: "
|
||||
name = readLine(stdin)
|
||||
# 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:
|
||||
|
||||
.. code-block:: nim
|
||||
echo("Counting to ten: ")
|
||||
echo "Counting to ten: "
|
||||
for i in countup(1, 10):
|
||||
echo($i)
|
||||
echo $i
|
||||
# --> 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
|
||||
@@ -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:
|
||||
|
||||
.. code-block:: nim
|
||||
echo("Counting to 10: ")
|
||||
echo "Counting to 10: "
|
||||
var i = 1
|
||||
while i <= 10:
|
||||
echo($i)
|
||||
echo $i
|
||||
inc(i) # increment i by 1
|
||||
# --> 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):
|
||||
|
||||
.. code-block:: nim
|
||||
echo("Counting down from 10 to 1: ")
|
||||
echo "Counting down from 10 to 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
|
||||
|
||||
Since counting up occurs so often in programs, Nim also has a `..
|
||||
@@ -390,7 +390,7 @@ outside the loop:
|
||||
.. code-block:: nim
|
||||
while false:
|
||||
var x = "hi"
|
||||
echo(x) # does not work
|
||||
echo x # does not work
|
||||
|
||||
A while (for) statement introduces an implicit block. Identifiers
|
||||
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
|
||||
block myblock:
|
||||
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.
|
||||
|
||||
@@ -412,18 +412,18 @@ innermost construct, unless a label of a block is given:
|
||||
|
||||
.. code-block:: nim
|
||||
block myblock:
|
||||
echo("entering block")
|
||||
echo "entering block"
|
||||
while true:
|
||||
echo("looping")
|
||||
echo "looping"
|
||||
break # leaves the loop, but not the block
|
||||
echo("still in block")
|
||||
echo "still in block"
|
||||
|
||||
block myblock2:
|
||||
echo("entering block")
|
||||
echo "entering block"
|
||||
while true:
|
||||
echo("looping")
|
||||
echo "looping"
|
||||
break myblock2 # leaves the block (and the loop)
|
||||
echo("still in block")
|
||||
echo "still in block"
|
||||
|
||||
|
||||
Continue statement
|
||||
@@ -435,7 +435,7 @@ the next iteration immediately:
|
||||
while true:
|
||||
let x = readLine(stdin)
|
||||
if x == "": continue
|
||||
echo(x)
|
||||
echo x
|
||||
|
||||
|
||||
When statement
|
||||
@@ -446,13 +446,13 @@ Example:
|
||||
.. code-block:: nim
|
||||
|
||||
when system.hostOS == "windows":
|
||||
echo("running on Windows!")
|
||||
echo "running on Windows!"
|
||||
elif system.hostOS == "linux":
|
||||
echo("running on Linux!")
|
||||
echo "running on Linux!"
|
||||
elif system.hostOS == "macosx":
|
||||
echo("running on Mac OS X!")
|
||||
echo "running on Mac OS X!"
|
||||
else:
|
||||
echo("unknown operating system")
|
||||
echo "unknown operating system"
|
||||
|
||||
The ``when`` statement is almost identical to the ``if`` statement with some
|
||||
differences:
|
||||
@@ -533,17 +533,17 @@ procedures are defined with the ``proc`` keyword:
|
||||
|
||||
.. code-block:: nim
|
||||
proc yes(question: string): bool =
|
||||
echo(question, " (y/n)")
|
||||
echo question, " (y/n)"
|
||||
while true:
|
||||
case readLine(stdin)
|
||||
of "y", "Y", "yes", "Yes": return true
|
||||
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?"):
|
||||
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:
|
||||
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``
|
||||
and returns true if they answered "yes" (or something similar) and returns
|
||||
@@ -611,8 +611,8 @@ caller, a ``var`` parameter can be used:
|
||||
var
|
||||
x, y: int
|
||||
divmod(8, 5, x, y) # modifies x and y
|
||||
echo(x)
|
||||
echo(y)
|
||||
echo x
|
||||
echo y
|
||||
|
||||
In the example, ``res`` and ``remainder`` are `var parameters`.
|
||||
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"
|
||||
else: result = "false"
|
||||
|
||||
echo(toString(13)) # calls the toString(x: int) proc
|
||||
echo(toString(true)) # calls the toString(x: bool) proc
|
||||
echo toString(13) # calls the toString(x: int) proc
|
||||
echo toString(true) # calls the toString(x: bool) proc
|
||||
|
||||
(Note that ``toString`` is usually the `$ <system.html#$>`_ operator in
|
||||
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:
|
||||
|
||||
.. code-block:: nim
|
||||
if `==`( `+`(3, 4), 7): echo("True")
|
||||
if `==`( `+`(3, 4), 7): echo "True"
|
||||
|
||||
|
||||
Forward declarations
|
||||
@@ -790,9 +790,9 @@ Iterators
|
||||
Let's return to the boring counting example:
|
||||
|
||||
.. code-block:: nim
|
||||
echo("Counting to ten: ")
|
||||
echo "Counting to ten: "
|
||||
for i in countup(1, 10):
|
||||
echo($i)
|
||||
echo $i
|
||||
|
||||
Can a `countup <system.html#countup>`_ proc be written that supports this
|
||||
loop? Lets try:
|
||||
@@ -1000,15 +1000,15 @@ there is a difference between the ``$`` and ``repr`` outputs:
|
||||
myString = "nim"
|
||||
myInteger = 42
|
||||
myFloat = 3.14
|
||||
echo($myBool, ":", repr(myBool))
|
||||
echo $myBool, ":", repr(myBool)
|
||||
# --> true:true
|
||||
echo($myCharacter, ":", repr(myCharacter))
|
||||
echo $myCharacter, ":", repr(myCharacter)
|
||||
# --> n:'n'
|
||||
echo($myString, ":", repr(myString))
|
||||
echo $myString, ":", repr(myString)
|
||||
# --> nim:0x10fa8c050"nim"
|
||||
echo($myInteger, ":", repr(myInteger))
|
||||
echo $myInteger, ":", repr(myInteger)
|
||||
# --> 42:42
|
||||
echo($myFloat, ":", repr(myFloat))
|
||||
echo $myFloat, ":", repr(myFloat)
|
||||
# --> 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
|
||||
|
||||
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.
|
||||
|
||||
@@ -1133,7 +1133,7 @@ Arrays can be constructed via ``[]``:
|
||||
x: IntArray
|
||||
x = [1, 2, 3, 4, 5, 6]
|
||||
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``.
|
||||
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]
|
||||
y = x
|
||||
for i in low(x)..high(x):
|
||||
echo(x[i], y[i])
|
||||
echo x[i], y[i]
|
||||
|
||||
|
||||
Sequences
|
||||
@@ -1254,13 +1254,13 @@ value. Here the ``for`` statement is looping over the results from the
|
||||
|
||||
.. code-block:: nim
|
||||
for i in @[3, 4, 5]:
|
||||
echo($i)
|
||||
echo $i
|
||||
# --> 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: 1, value:4
|
||||
# --> index: 2, value:5
|
||||
@@ -1386,16 +1386,16 @@ integer.
|
||||
# the same, but less readable:
|
||||
person = ("Peter", 30)
|
||||
|
||||
echo(person.name) # "Peter"
|
||||
echo(person.age) # 30
|
||||
echo person.name # "Peter"
|
||||
echo person.age # 30
|
||||
|
||||
echo(person[0]) # "Peter"
|
||||
echo(person[1]) # 30
|
||||
echo person[0] # "Peter"
|
||||
echo person[1] # 30
|
||||
|
||||
# You don't need to declare tuples in a separate type section.
|
||||
var building: tuple[street: string, number: int]
|
||||
building = ("Rue del Percebe", 13)
|
||||
echo(building.street)
|
||||
echo building.street
|
||||
|
||||
# The following line does not compile, they are different tuples!
|
||||
#person = building
|
||||
@@ -1503,7 +1503,7 @@ techniques.
|
||||
Example:
|
||||
|
||||
.. code-block:: nim
|
||||
proc echoItem(x: int) = echo(x)
|
||||
proc echoItem(x: int) = echo x
|
||||
|
||||
proc forEach(action: proc (x: int)) =
|
||||
const
|
||||
|
||||
10
doc/tut2.txt
10
doc/tut2.txt
@@ -204,9 +204,9 @@ for any type:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
echo("abc".len) # is the same as echo(len("abc"))
|
||||
echo("abc".toUpper())
|
||||
echo({'a', 'b', 'c'}.card)
|
||||
echo "abc".len # is the same as echo len("abc")
|
||||
echo "abc".toUpper()
|
||||
echo {'a', 'b', 'c'}.card
|
||||
stdout.writeLine("Hallo") # the same as writeLine(stdout, "Hallo")
|
||||
|
||||
(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.
|
||||
It is recommended to avoid those if you're not sure how they are translated
|
||||
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
|
||||
use ``cstring`` only when it is semantically appropriate. E.g. don't use
|
||||
``cstring`` as a binary data buffer.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
## report at program exit.
|
||||
|
||||
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 ...
|
||||
{.push profiler: off.}
|
||||
|
||||
@@ -567,7 +567,9 @@ when declared(getEnv) or defined(nimscript):
|
||||
var path = string(getEnv("PATH"))
|
||||
for candidate in split(path, PathSep):
|
||||
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:
|
||||
var x = expandTilde(candidate) / result
|
||||
if existsFile(x): return x
|
||||
|
||||
@@ -886,7 +886,7 @@ elif not defined(useNimRtl):
|
||||
discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error))
|
||||
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
|
||||
|
||||
proc startProcessAfterFork(data: ptr StartProcessData) =
|
||||
@@ -916,17 +916,16 @@ elif not defined(useNimRtl):
|
||||
discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC)
|
||||
|
||||
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.
|
||||
# On MacOSX we can arrive here only from fork, so this is safe:
|
||||
environ = data.sysEnv
|
||||
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:
|
||||
discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
|
||||
|
||||
|
||||
@@ -688,7 +688,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
|
||||
sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %%
|
||||
s == 0, "rawDealloc 3")
|
||||
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")
|
||||
f.zeroField = 0
|
||||
f.next = c.freeList
|
||||
|
||||
@@ -659,7 +659,7 @@ when useMarkForDebug or useBackupGc:
|
||||
proc stackMarkS(gch: var GcHeap, p: pointer) {.inline.} =
|
||||
# the addresses are not as cells on the stack, so turn them to cells:
|
||||
var cell = usrToCell(p)
|
||||
var c = cast[TAddress](cell)
|
||||
var c = cast[ByteAddress](cell)
|
||||
if c >% PageSize:
|
||||
# fast check: does it look like a cell?
|
||||
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
|
||||
@@ -805,8 +805,8 @@ proc markThreadStacks(gch: var GcHeap) =
|
||||
while it != nil:
|
||||
# mark registers:
|
||||
for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
|
||||
var sp = cast[TAddress](it.stackBottom)
|
||||
var max = cast[TAddress](it.stackTop)
|
||||
var sp = cast[ByteAddress](it.stackBottom)
|
||||
var max = cast[ByteAddress](it.stackTop)
|
||||
# XXX stack direction?
|
||||
# XXX unroll this loop:
|
||||
while sp <=% max:
|
||||
|
||||
@@ -131,9 +131,9 @@ when defined(sparc): # For SPARC architecture.
|
||||
proc isOnStack(p: pointer): bool =
|
||||
var stackTop {.volatile.}: pointer
|
||||
stackTop = addr(stackTop)
|
||||
var b = cast[TAddress](gch.stackBottom)
|
||||
var a = cast[TAddress](stackTop)
|
||||
var x = cast[TAddress](p)
|
||||
var b = cast[ByteAddress](gch.stackBottom)
|
||||
var a = cast[ByteAddress](stackTop)
|
||||
var x = cast[ByteAddress](p)
|
||||
result = a <=% x and x <=% b
|
||||
|
||||
template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
|
||||
@@ -150,7 +150,7 @@ when defined(sparc): # For SPARC architecture.
|
||||
# Addresses decrease as the stack grows.
|
||||
while sp <= max:
|
||||
gcMark(gch, sp[])
|
||||
sp = cast[PPointer](cast[TAddress](sp) +% sizeof(pointer))
|
||||
sp = cast[PPointer](cast[ByteAddress](sp) +% sizeof(pointer))
|
||||
|
||||
elif defined(ELATE):
|
||||
{.error: "stack marking code is to be written for this architecture".}
|
||||
|
||||
@@ -165,15 +165,46 @@ proc SetConstr() {.varargs, asmNoStackFrame, compilerproc.} =
|
||||
return result;
|
||||
"""
|
||||
|
||||
proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
||||
{.emit: """
|
||||
var ln = `c`.length;
|
||||
var result = new Array(ln + 1);
|
||||
var i = 0;
|
||||
for (; i < ln; ++i) {
|
||||
result[i] = `c`.charCodeAt(i);
|
||||
}
|
||||
result[i] = 0; // terminating zero
|
||||
return result;
|
||||
""".}
|
||||
|
||||
proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
|
||||
asm """
|
||||
var result = [];
|
||||
for (var i = 0; i < `c`.length; ++i) {
|
||||
result[i] = `c`.charCodeAt(i);
|
||||
{.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;
|
||||
}
|
||||
result[result.length] = 0; // terminating zero
|
||||
return result;
|
||||
"""
|
||||
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.} =
|
||||
asm """
|
||||
|
||||
@@ -496,13 +496,12 @@ type
|
||||
data: array[MD5_LBLOCK, MD5_LONG]
|
||||
num: cuint
|
||||
|
||||
{.pragma: ic, importc: "$1".}
|
||||
{.push callconv:cdecl, dynlib:DLLUtilName.}
|
||||
proc md5_Init*(c: var MD5_CTX): cint{.ic.}
|
||||
proc md5_Update*(c: var MD5_CTX; data: pointer; len: csize): cint{.ic.}
|
||||
proc md5_Final*(md: cstring; c: var MD5_CTX): cint{.ic.}
|
||||
proc md5*(d: ptr cuchar; n: csize; md: ptr cuchar): ptr cuchar{.ic.}
|
||||
proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.ic.}
|
||||
proc md5_Init*(c: var MD5_CTX): cint{.importc: "MD5_Init".}
|
||||
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{.importc: "MD5_Final".}
|
||||
proc md5*(d: ptr cuchar; n: csize; md: ptr cuchar): ptr cuchar{.importc: "MD5".}
|
||||
proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.importc: "MD5_Transform".}
|
||||
{.pop.}
|
||||
|
||||
from strutils import toHex,toLower
|
||||
|
||||
@@ -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:
|
||||
|
||||
```
|
||||
$ git clone git://github.com/nim-lang/Nim.git
|
||||
$ git clone https://github.com/nim-lang/Nim.git
|
||||
$ 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 ..
|
||||
$ bin/nim c koch
|
||||
|
||||
@@ -3,22 +3,76 @@ discard """
|
||||
Hello'''
|
||||
"""
|
||||
|
||||
# bug #2581
|
||||
block: # bug #2581
|
||||
const someVars = [ "Hello" ]
|
||||
var someVars2 = [ "Hello" ]
|
||||
|
||||
const someVars = [ "Hello" ]
|
||||
var someVars2 = [ "Hello" ]
|
||||
proc getSomeVar: string =
|
||||
for i in someVars:
|
||||
if i == "Hello":
|
||||
result = i
|
||||
break
|
||||
|
||||
proc getSomeVar: string =
|
||||
for i in someVars:
|
||||
if i == "Hello":
|
||||
result = i
|
||||
break
|
||||
proc getSomeVar2: string =
|
||||
for i in someVars2:
|
||||
if i == "Hello":
|
||||
result = i
|
||||
break
|
||||
|
||||
proc getSomeVar2: string =
|
||||
for i in someVars2:
|
||||
if i == "Hello":
|
||||
result = i
|
||||
break
|
||||
echo getSomeVar()
|
||||
echo getSomeVar2()
|
||||
|
||||
echo getSomeVar()
|
||||
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)
|
||||
|
||||
@@ -23,24 +23,29 @@ template test(opr, a, b, c: expr): stmt {.immediate.} =
|
||||
|
||||
test(`+`, 12'i8, -13'i16, -1'i16)
|
||||
test(`shl`, 0b11, 0b100, 0b110000)
|
||||
test(`shl`, 0b11'i32, 0b100'i64, 0b110000'i64)
|
||||
when not defined(js):
|
||||
test(`shl`, 0b11'i32, 0b100'i64, 0b110000'i64)
|
||||
test(`shl`, 0b11'i32, 0b100'i32, 0b110000'i32)
|
||||
|
||||
test(`or`, 0xf0f0'i16, 0x0d0d'i16, 0xfdfd'i16)
|
||||
test(`and`, 0xf0f0'i16, 0xfdfd'i16, 0xf0f0'i16)
|
||||
|
||||
test(`shr`, 0xffffffffffffffff'i64, 0x4'i64, 0x0fffffffffffffff'i64)
|
||||
when not defined(js):
|
||||
test(`shr`, 0xffffffffffffffff'i64, 0x4'i64, 0x0fffffffffffffff'i64)
|
||||
test(`shr`, 0xffff'i16, 0x4'i16, 0x0fff'i16)
|
||||
test(`shr`, 0xff'i8, 0x4'i8, 0x0f'i8)
|
||||
|
||||
test(`shr`, 0xffffffff'i64, 0x4'i64, 0x0fffffff'i64)
|
||||
when not defined(js):
|
||||
test(`shr`, 0xffffffff'i64, 0x4'i64, 0x0fffffff'i64)
|
||||
test(`shr`, 0xffffffff'i32, 0x4'i32, 0x0fffffff'i32)
|
||||
|
||||
test(`shl`, 0xffffffffffffffff'i64, 0x4'i64, 0xfffffffffffffff0'i64)
|
||||
when not defined(js):
|
||||
test(`shl`, 0xffffffffffffffff'i64, 0x4'i64, 0xfffffffffffffff0'i64)
|
||||
test(`shl`, 0xffff'i16, 0x4'i16, 0xfff0'i16)
|
||||
test(`shl`, 0xff'i8, 0x4'i8, 0xf0'i8)
|
||||
|
||||
test(`shl`, 0xffffffff'i64, 0x4'i64, 0xffffffff0'i64)
|
||||
when not defined(js):
|
||||
test(`shl`, 0xffffffff'i64, 0x4'i64, 0xffffffff0'i64)
|
||||
test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32)
|
||||
|
||||
# bug #916
|
||||
@@ -50,5 +55,27 @@ proc unc(a: float): float =
|
||||
echo int(unc(0.5)), " ", int(unc(-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
|
||||
|
||||
@@ -220,7 +220,7 @@ proc jsTests(r: var TResults, cat: Category, options: string) =
|
||||
"actiontable/tactiontable", "method/tmultim1",
|
||||
"method/tmultim3", "method/tmultim4",
|
||||
"varres/tvarres0", "varres/tvarres3", "varres/tvarres4",
|
||||
"varres/tvartup", "misc/tunsignedinc"]:
|
||||
"varres/tvartup", "misc/tints", "misc/tunsignedinc"]:
|
||||
test "tests/" & testfile & ".nim"
|
||||
|
||||
for testfile in ["pure/strutils"]:
|
||||
|
||||
Reference in New Issue
Block a user