summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorYuriy Glukhov <yuriy.glukhov@gmail.com>2016-01-22 18:30:07 +0200
committerYuriy Glukhov <yuriy.glukhov@gmail.com>2016-01-22 18:32:47 +0200
commitd2ecd84f67c209eac883354c8009b5d6a52faabc (patch)
treeab9a421b9363a9352131bb71d9150098363d0329
parent732479b797422adaadf6891b8d8c32230f548692 (diff)
downloadNim-d2ecd84f67c209eac883354c8009b5d6a52faabc.tar.gz
JS: Corrected shift operators. Made casting between ints behave like C does.
-rw-r--r--compiler/jsgen.nim58
-rw-r--r--doc/tut2.txt4
-rw-r--r--tests/misc/tints.nim39
-rw-r--r--tests/testament/categories.nim2
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"]: