JS: Corrected shift operators. Made casting between ints behave like C does.

This commit is contained in:
Yuriy Glukhov 2016-01-22 18:30:07 +02:00
commit d2ecd84f67
4 changed files with 86 additions and 17 deletions

View file

@ -264,7 +264,7 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "($1 - $2)", "($1 - $2)"], # SubF64 ["", "", "($1 - $2)", "($1 - $2)"], # SubF64
["", "", "($1 * $2)", "($1 * $2)"], # MulF64 ["", "", "($1 * $2)", "($1 * $2)"], # MulF64
["", "", "($1 / $2)", "($1 / $2)"], # DivF64 ["", "", "($1 / $2)", "($1 / $2)"], # DivF64
["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI ["", "", "", ""], # ShrI
["", "", "($1 << $2)", "($1 << $2)"], # ShlI ["", "", "($1 << $2)", "($1 << $2)"], # ShlI
["", "", "($1 & $2)", "($1 & $2)"], # BitandI ["", "", "($1 & $2)", "($1 & $2)"], # BitandI
["", "", "($1 | $2)", "($1 | $2)"], # BitorI ["", "", "($1 | $2)", "($1 | $2)"], # BitorI
@ -344,19 +344,22 @@ proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
r.res = frmt % [x.rdLoc, y.rdLoc] r.res = frmt % [x.rdLoc, y.rdLoc]
r.kind = resExpr r.kind = resExpr
proc unsignedTrimmer(size: BiggestInt): Rope =
case size
of 1: rope"& 0xff"
of 2: rope"& 0xffff"
of 4: rope">>> 0"
else: rope""
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, reassign: bool = false) = proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string, reassign: bool = false) =
var x, y: TCompRes var x, y: TCompRes
gen(p, n.sons[1], x) gen(p, n.sons[1], x)
gen(p, n.sons[2], y) gen(p, n.sons[2], y)
let trimmer = case n[1].typ.skipTypes(abstractRange).size let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
of 1: "& 0xff"
of 2: "& 0xffff"
of 4: ">>> 0"
else: ""
if reassign: if reassign:
r.res = "$1 = (($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, rope trimmer] r.res = "$1 = (($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
else: else:
r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, rope trimmer] r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
var x, y, z: TCompRes var x, y, z: TCompRes
@ -392,6 +395,12 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mSubU: binaryUintExpr(p, n, r, "-") of mSubU: binaryUintExpr(p, n, r, "-")
of mMulU: binaryUintExpr(p, n, r, "*") of mMulU: binaryUintExpr(p, n, r, "*")
of mDivU: binaryUintExpr(p, n, r, "/") of mDivU: binaryUintExpr(p, n, r, "/")
of mShrI:
var x, y: TCompRes
gen(p, n.sons[1], x)
gen(p, n.sons[2], y)
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc]
else: else:
arithAux(p, n, r, op, jsOps) arithAux(p, n, r, op, jsOps)
r.kind = resExpr r.kind = resExpr
@ -1569,6 +1578,37 @@ proc genPragma(p: PProc, n: PNode) =
of wEmit: genAsmOrEmitStmt(p, it.sons[1]) of wEmit: genAsmOrEmitStmt(p, it.sons[1])
else: discard else: discard
proc genCast(p: PProc, n: PNode, r: var TCompRes) =
var dest = skipTypes(n.typ, abstractVarRange)
var src = skipTypes(n.sons[1].typ, abstractVarRange)
gen(p, n.sons[1], r)
if dest.kind == src.kind:
# no-op conversion
return
let toInt = (dest.kind in tyInt .. tyInt32)
let toUint = (dest.kind in tyUInt .. tyUInt32)
let fromInt = (src.kind in tyInt .. tyInt32)
let fromUint = (src.kind in tyUInt .. tyUInt32)
if toUint and (fromInt or fromUint):
let trimmer = unsignedTrimmer(dest.size)
r.res = "($1 $2)" % [r.res, trimmer]
elif toInt:
if fromInt:
let trimmer = unsignedTrimmer(dest.size)
r.res = "($1 $2)" % [r.res, trimmer]
elif fromUint:
if src.size == 4 and dest.size == 4:
r.res = "($1|0)" % [r.res]
else:
let trimmer = unsignedTrimmer(dest.size)
let minuend = case dest.size
of 1: "0xfe"
of 2: "0xfffe"
of 4: "0xfffffffe"
else: ""
r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer]
proc gen(p: PProc, n: PNode, r: var TCompRes) = proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.typ = etyNone r.typ = etyNone
r.kind = resNone r.kind = resNone
@ -1630,7 +1670,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkCheckedFieldExpr: genCheckedFieldAccess(p, n, r) of nkCheckedFieldExpr: genCheckedFieldAccess(p, n, r)
of nkObjDownConv: gen(p, n.sons[0], r) of nkObjDownConv: gen(p, n.sons[0], r)
of nkObjUpConv: upConv(p, n, r) of nkObjUpConv: upConv(p, n, r)
of nkCast: gen(p, n.sons[1], r) of nkCast: genCast(p, n, r)
of nkChckRangeF: genRangeChck(p, n, r, "chckRangeF") of nkChckRangeF: genRangeChck(p, n, r, "chckRangeF")
of nkChckRange64: genRangeChck(p, n, r, "chckRange64") of nkChckRange64: genRangeChck(p, n, r, "chckRange64")
of nkChckRange: genRangeChck(p, n, r, "chckRange") of nkChckRange: genRangeChck(p, n, r, "chckRange")

View file

@ -1000,7 +1000,9 @@ JavaScript-compatible code you should remember the following:
- ``addr`` and ``ptr`` have slightly different semantic meaning in JavaScript. - ``addr`` and ``ptr`` have slightly different semantic meaning in JavaScript.
It is recommended to avoid those if you're not sure how they are translated It is recommended to avoid those if you're not sure how they are translated
to JavaScript. to JavaScript.
- ``cast[T](x)`` in JavaScript is translated to ``(x)``. - ``cast[T](x)`` in JavaScript is translated to ``(x)``, except for casting
between signed/unsigned ints, in which case it behaves as static cast in
C language.
- ``cstring`` in JavaScript means JavaScript string. It is a good practice to - ``cstring`` in JavaScript means JavaScript string. It is a good practice to
use ``cstring`` only when it is semantically appropriate. E.g. don't use use ``cstring`` only when it is semantically appropriate. E.g. don't use
``cstring`` as a binary data buffer. ``cstring`` as a binary data buffer.

View file

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

View file

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