diff options
-rw-r--r-- | compiler/evalffi.nim | 16 | ||||
-rw-r--r-- | compiler/jsgen.nim | 95 | ||||
-rw-r--r-- | compiler/renderer.nim | 6 | ||||
-rw-r--r-- | doc/manual/exceptions.txt | 10 | ||||
-rw-r--r-- | doc/manual/modules.txt | 2 | ||||
-rw-r--r-- | doc/manual/procs.txt | 10 | ||||
-rw-r--r-- | doc/manual/stmts.txt | 32 | ||||
-rw-r--r-- | doc/manual/types.txt | 2 | ||||
-rw-r--r-- | doc/nimc.txt | 30 | ||||
-rw-r--r-- | doc/tut1.txt | 124 | ||||
-rw-r--r-- | doc/tut2.txt | 10 | ||||
-rw-r--r-- | lib/pure/nimprof.nim | 2 | ||||
-rw-r--r-- | lib/pure/ospaths.nim | 4 | ||||
-rw-r--r-- | lib/pure/osproc.nim | 15 | ||||
-rw-r--r-- | lib/system/alloc.nim | 2 | ||||
-rw-r--r-- | lib/system/gc.nim | 6 | ||||
-rw-r--r-- | lib/system/gc_common.nim | 8 | ||||
-rw-r--r-- | lib/system/jssys.nim | 45 | ||||
-rw-r--r-- | lib/wrappers/openssl.nim | 11 | ||||
-rw-r--r-- | readme.md | 4 | ||||
-rw-r--r-- | tests/js/tstringitems.nim | 84 | ||||
-rw-r--r-- | tests/misc/tints.nim | 39 | ||||
-rw-r--r-- | tests/testament/categories.nim | 2 |
23 files changed, 369 insertions, 190 deletions
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index b1a23802d..75394c2f3 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -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]) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index c36f5a5a3..9424a9fc5 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -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") diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 8e4aa1831..34688c798 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -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") diff --git a/doc/manual/exceptions.txt b/doc/manual/exceptions.txt index 0010d5d09..e7af65386 100644 --- a/doc/manual/exceptions.txt +++ b/doc/manual/exceptions.txt @@ -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) diff --git a/doc/manual/modules.txt b/doc/manual/modules.txt index ac47d89dd..9cb6a11af 100644 --- a/doc/manual/modules.txt +++ b/doc/manual/modules.txt @@ -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 ----------- diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt index 654893286..9ce92de0d 100644 --- a/doc/manual/procs.txt +++ b/doc/manual/procs.txt @@ -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 diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt index 59f7eef55..83852b1ff 100644 --- a/doc/manual/stmts.txt +++ b/doc/manual/stmts.txt @@ -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) diff --git a/doc/manual/types.txt b/doc/manual/types.txt index babf3286f..a1596bcea 100644 --- a/doc/manual/types.txt +++ b/doc/manual/types.txt @@ -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" diff --git a/doc/nimc.txt b/doc/nimc.txt index 95449d060..e7cb57037 100644 --- a/doc/nimc.txt +++ b/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 -==================== - -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 ``"""``. +.. + 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: + + 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 diff --git a/doc/tut1.txt b/doc/tut1.txt index 747c1a3ff..d896a7044 100644 --- a/doc/tut1.txt +++ b/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 diff --git a/doc/tut2.txt b/doc/tut2.txt index 563344570..3f94325ff 100644 --- a/doc/tut2.txt +++ b/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. diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index e2397b91c..5a7deaab0 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -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.} diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim index e9f5bee0a..9fc816f2f 100644 --- a/lib/pure/ospaths.nim +++ b/lib/pure/ospaths.nim @@ -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 diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 8560c3ee4..34fb81520 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -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) diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index b4462ed83..6de8e19e7 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -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 diff --git a/lib/system/gc.nim b/lib/system/gc.nim index c25cf4606..727b039d7 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -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: diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim index 47e8b4b1f..fdedcaf18 100644 --- a/lib/system/gc_common.nim +++ b/lib/system/gc_common.nim @@ -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".} diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 3df460952..6eadae17a 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -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 """ diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index a227ac98c..05843e2d3 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -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 diff --git a/readme.md b/readme.md index 32dbad9f1..27b2273f0 100644 --- a/readme.md +++ b/readme.md @@ -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 diff --git a/tests/js/tstringitems.nim b/tests/js/tstringitems.nim index f4ea02fec..20aed6e8b 100644 --- a/tests/js/tstringitems.nim +++ b/tests/js/tstringitems.nim @@ -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) diff --git a/tests/misc/tints.nim b/tests/misc/tints.nim index ded24fb5c..5bfb8a17c 100644 --- a/tests/misc/tints.nim +++ b/tests/misc/tints.nim @@ -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 diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 3200c7da9..ff83379b8 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -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"]: |