diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2016-01-22 18:29:23 +0100 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2016-01-22 18:29:23 +0100 |
commit | d3c9f03f69e7c798e07096b7395a6d9f7494a675 (patch) | |
tree | ab9a421b9363a9352131bb71d9150098363d0329 | |
parent | 732479b797422adaadf6891b8d8c32230f548692 (diff) | |
parent | d2ecd84f67c209eac883354c8009b5d6a52faabc (diff) | |
download | Nim-d3c9f03f69e7c798e07096b7395a6d9f7494a675.tar.gz |
Merge pull request #3761 from yglukhov/more-love-to-ints
JS: Corrected shift operators. Cast ints like C does.
-rw-r--r-- | compiler/jsgen.nim | 58 | ||||
-rw-r--r-- | doc/tut2.txt | 4 | ||||
-rw-r--r-- | tests/misc/tints.nim | 39 | ||||
-rw-r--r-- | tests/testament/categories.nim | 2 |
4 files changed, 86 insertions, 17 deletions
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index c36f5a5a3..607b85924 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -264,7 +264,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 +344,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 +395,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 @@ -1569,6 +1578,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 @@ -1630,7 +1670,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/doc/tut2.txt b/doc/tut2.txt index 563344570..f60818da6 100644 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -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/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"]: |