array literals uses typed arrays; fix a jsgen bug (#16850)

* array litterals uses typed arrays
* Update compiler/jsgen.nim

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
flywind
2021-02-15 04:28:11 -06:00
committed by GitHub
parent c8d9963150
commit 240879bf3d
6 changed files with 81 additions and 31 deletions

View File

@@ -194,6 +194,8 @@ provided by the operating system.
- TLS: OSX now uses native TLS (`--tlsEmulation:off`), TLS now works with importcpp non-POD types,
such types must use `.cppNonPod` and `--tlsEmulation:off`should be used.
- Now array literals(JS backend) uses JS typed arrays when the corresponding js typed array exists, for example `[byte(1), 2, 3]` generates `new Uint8Array([1, 2, 3])`.
- docgen: rst files can now use single backticks instead of double backticks and correctly render
in both rst2html (as before) as well as common tools rendering rst directly (e.g. github), by
adding: `default-role:: code` directive inside the rst file, which is now handled by rst2html.

View File

@@ -1991,6 +1991,23 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) =
genReset(p, n)
#lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
proc genJSArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
r.res = rope("[")
r.kind = resExpr
for i in 0 ..< n.len:
if i > 0: r.res.add(", ")
gen(p, n[i], a)
if a.typ == etyBaseIndex:
r.res.addf("[$1, $2]", [a.address, a.res])
else:
if not needsNoCopy(p, n[i]):
let typ = n[i].typ.skipTypes(abstractInst)
useMagic(p, "nimCopy")
a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
r.res.add(a.res)
r.res.add("]")
proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
var
a: TCompRes
@@ -2054,8 +2071,9 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mNew, mNewFinalize: genNew(p, n)
of mChr: gen(p, n[1], r)
of mArrToSeq:
if needsNoCopy(p, n[1]):
gen(p, n[1], r)
# only array literals doesn't need copy
if n[1].kind == nkBracket:
genJSArrayConstr(p, n[1], r)
else:
var x: TCompRes
gen(p, n[1], x)
@@ -2172,21 +2190,26 @@ proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
r.res = tmp
proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
r.res = rope("[")
r.kind = resExpr
for i in 0..<n.len:
if i > 0: r.res.add(", ")
gen(p, n[i], a)
if a.typ == etyBaseIndex:
r.res.addf("[$1, $2]", [a.address, a.res])
else:
if not needsNoCopy(p, n[i]):
let typ = n[i].typ.skipTypes(abstractInst)
useMagic(p, "nimCopy")
a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
## Constructs array or sequence.
## Nim array of uint8..uint32, int8..int32 maps to JS typed arrays.
## Nim sequence maps to JS array.
var t = skipTypes(n.typ, abstractInst)
let e = elemType(t)
let jsTyp = arrayTypeForElemType(e)
if skipTypes(n.typ, abstractVarRange).kind != tySequence and jsTyp.len > 0:
# generate typed array
# for example Nim generates `new Uint8Array([1, 2, 3])` for `[byte(1), 2, 3]`
# TODO use `set` or loop to initialize typed array which improves performances in some situations
var a: TCompRes
r.res = "new $1([" % [rope(jsTyp)]
r.kind = resExpr
for i in 0 ..< n.len:
if i > 0: r.res.add(", ")
gen(p, n[i], a)
r.res.add(a.res)
r.res.add("]")
r.res.add("])")
else:
genJSArrayConstr(p, n, r)
proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes

View File

@@ -23,8 +23,16 @@ when defined(js):
func `[]=`*(arr: Float64Array, i: int, v: float) {.importjs: "#[#] = #".}
proc jsTypeOf*[T](x: T): cstring {.importjs: "typeof(#)".}
## Returns the name of the JsObject's JavaScript type as a cstring.
# xxx replace jsffi.jsTypeOf with this definition and add tests
proc jsConstructorName*[T](a: T): cstring =
asm """`result` = `a`.constructor.name"""
proc hasJsBigInt*(): bool =
asm """`result` = typeof BigInt != 'undefined'"""
proc hasBigUint64Array*(): bool =
asm """`result` = typeof BigUint64Array != 'undefined'"""

View File

@@ -1,6 +1,5 @@
proc jsTypeOf*[T](x: T): cstring {.importjs: "typeof(#)".}
## Returns the name of the JsObject's JavaScript type as a cstring.
# xxx replace jsffi.jsTypeOf with this definition and add tests
import std/private/jsutils
type JsBigIntImpl {.importc: "bigint".} = int
type JsBigInt = distinct JsBigIntImpl

View File

@@ -1,11 +1,3 @@
discard """
output: '''(x: 0, y: 0)
(x: 5, y: 0)
@[(x: "2", y: 4), (x: "4", y: 5), (x: "4", y: 5)]
@[(a: "3", b: 3), (a: "1", b: 1), (a: "2", b: 2)]
'''
"""
# bug #4139
type
@@ -17,8 +9,8 @@ proc onLoad() =
var foo = TestO(x: 0, y: 0)
test.add(foo)
foo.x = 5
echo(test[0])
echo foo
doAssert $test[0] == "(x: 0, y: 0)"
doAssert $foo == "(x: 5, y: 0)"
onLoad()
@@ -34,7 +26,7 @@ proc foo(x: var seq[MyObj]) =
var s = @[MyObj(x: "2", y: 4), MyObj(x: "4", y: 5)]
foo(s)
echo s
doAssert $s == """@[(x: "2", y: 4), (x: "4", y: 5), (x: "4", y: 5)]"""
# bug #5933
import sequtils
@@ -48,4 +40,9 @@ var test = @[Test(a: "1", b: 1), Test(a: "2", b: 2)]
test.insert(@[Test(a: "3", b: 3)], 0)
echo test
doAssert $test == """@[(a: "3", b: 3), (a: "1", b: 1), (a: "2", b: 2)]"""
proc hello(): array[5, int] = discard
var x = @(hello())
x.add(2)
doAssert x == @[0, 0, 0, 0, 0, 2]

21
tests/js/ttypedarray.nim Normal file
View File

@@ -0,0 +1,21 @@
import std/private/jsutils
proc main()=
template fn(a): untyped = jsConstructorName(a)
doAssert fn(array[2, int8].default) == "Int8Array"
doAssert fn(array[2, uint8].default) == "Uint8Array"
doAssert fn(array[2, byte].default) == "Uint8Array"
# doAssert fn(array[2, char].default) == "Uint8Array" # xxx fails; bug?
doAssert fn(array[2, uint64].default) == "Array"
# pending https://github.com/nim-lang/RFCs/issues/187 maybe use `BigUint64Array`
doAssert fn([1'u8]) == "Uint8Array"
doAssert fn([1'u16]) == "Uint16Array"
doAssert fn([byte(1)]) == "Uint8Array"
doAssert fn([1.0'f32]) == "Float32Array"
doAssert fn(array[2, float32].default) == "Float32Array"
doAssert fn(array[2, float].default) == "Float64Array"
doAssert fn(array[2, float64].default) == "Float64Array"
doAssert fn([1.0]) == "Float64Array"
doAssert fn([1.0'f64]) == "Float64Array"
main()