Merge pull request #3761 from yglukhov/more-love-to-ints
JS: Corrected shift operators. Cast ints like C does.
This commit is contained in:
commit
d3c9f03f69
4 changed files with 86 additions and 17 deletions
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -23,24 +23,29 @@ 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)
|
||||||
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(`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)
|
||||||
|
|
||||||
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`, 0xffff'i16, 0x4'i16, 0x0fff'i16)
|
||||||
test(`shr`, 0xff'i8, 0x4'i8, 0x0f'i8)
|
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(`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`, 0xffff'i16, 0x4'i16, 0xfff0'i16)
|
||||||
test(`shl`, 0xff'i8, 0x4'i8, 0xf0'i8)
|
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)
|
test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32)
|
||||||
|
|
||||||
# bug #916
|
# bug #916
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"]:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue