mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-02 11:12:37 +00:00
Support only some types as JsAssoc types (#8627)
This commit is contained in:
committed by
Andreas Rumpf
parent
562d185cb7
commit
88d707cb88
@@ -69,10 +69,25 @@ template mangleJsName(name: cstring): cstring =
|
||||
inc nameCounter
|
||||
"mangledName" & $nameCounter
|
||||
|
||||
# only values that can be mapped 1 to 1 with cstring should be keys: they have an injective function with cstring
|
||||
|
||||
proc toJsKey*[T: SomeInteger](text: cstring, t: type T): T {.importcpp: "parseInt(#)".}
|
||||
|
||||
proc toJsKey*[T: enum](text: cstring, t: type T): T =
|
||||
T(text.toJsKey(int))
|
||||
|
||||
proc toJsKey*(text: cstring, t: type cstring): cstring =
|
||||
text
|
||||
|
||||
proc toJsKey*[T: SomeFloat](text: cstring, t: type T): T {.importcpp: "parseFloat(#)".}
|
||||
|
||||
type
|
||||
JsKey* = concept a, type T
|
||||
cstring.toJsKey(T) is type(a)
|
||||
|
||||
JsObject* = ref object of JsRoot
|
||||
## Dynamically typed wrapper around a JavaScript object.
|
||||
JsAssoc*[K, V] = ref object of JsRoot
|
||||
JsAssoc*[K: JsKey, V] = ref object of JsRoot
|
||||
## Statically typed wrapper around a JavaScript object.
|
||||
|
||||
js* = JsObject
|
||||
@@ -104,7 +119,7 @@ type
|
||||
proc newJsObject*: JsObject {. importcpp: "{@}" .}
|
||||
## Creates a new empty JsObject
|
||||
|
||||
proc newJsAssoc*[K, V]: JsAssoc[K, V] {. importcpp: "{@}" .}
|
||||
proc newJsAssoc*[K: JsKey, V]: JsAssoc[K, V] {. importcpp: "{@}" .}
|
||||
## Creates a new empty JsAssoc with key type `K` and value type `V`.
|
||||
|
||||
# Checks
|
||||
@@ -176,21 +191,19 @@ proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {. importcpp: setImpl .}
|
||||
proc `[]=`*[T](obj: JsObject, field: int, val: T) {. importcpp: setImpl .}
|
||||
## Set the value of a property of name `field` in a JsObject `obj` to `v`.
|
||||
|
||||
proc `[]`*[K: not string, V](obj: JsAssoc[K, V], field: K): V
|
||||
proc `[]`*[K: JsKey, V](obj: JsAssoc[K, V], field: K): V
|
||||
{. importcpp: getImpl .}
|
||||
## Return the value of a property of name `field` from a JsAssoc `obj`.
|
||||
|
||||
proc `[]`*[V](obj: JsAssoc[string, V], field: cstring): V
|
||||
{. importcpp: getImpl .}
|
||||
## Return the value of a property of name `field` from a JsAssoc `obj`.
|
||||
|
||||
proc `[]=`*[K: not string, V](obj: JsAssoc[K, V], field: K, val: V)
|
||||
proc `[]=`*[K: JsKey, V](obj: JsAssoc[K, V], field: K, val: V)
|
||||
{. importcpp: setImpl .}
|
||||
## Set the value of a property of name `field` in a JsAssoc `obj` to `v`.
|
||||
|
||||
proc `[]=`*[V](obj: JsAssoc[string, V], field: cstring, val: V)
|
||||
{. importcpp: setImpl .}
|
||||
## Set the value of a property of name `field` in a JsAssoc `obj` to `v`.
|
||||
proc `[]`*[V](obj: JsAssoc[cstring, V], field: string): V =
|
||||
obj[cstring(field)]
|
||||
|
||||
proc `[]=`*[V](obj: JsAssoc[cstring, V], field: string, val: V) =
|
||||
obj[cstring(field)] = val
|
||||
|
||||
proc `==`*(x, y: JsRoot): bool {. importcpp: "(# === #)" .}
|
||||
## Compare two JsObjects or JsAssocs. Be careful though, as this is comparison
|
||||
@@ -277,7 +290,7 @@ macro `.()`*(obj: JsObject,
|
||||
result[0][3].add newIdentDefs(paramName, newIdentNode(!"JsObject"))
|
||||
result[1].add args[idx].copyNimTree
|
||||
|
||||
macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||
macro `.`*[K: cstring, V](obj: JsAssoc[K, V],
|
||||
field: untyped): V =
|
||||
## Experimental dot accessor (get) for type JsAssoc.
|
||||
## Returns the value of a property of name `field` from a JsObject `x`.
|
||||
@@ -293,7 +306,7 @@ macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||
{. importcpp: `importString`, gensym .}
|
||||
helper(`obj`)
|
||||
|
||||
macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||
macro `.=`*[K: cstring, V](obj: JsAssoc[K, V],
|
||||
field: untyped,
|
||||
value: V): untyped =
|
||||
## Experimental dot accessor (set) for type JsAssoc.
|
||||
@@ -310,7 +323,7 @@ macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||
{. importcpp: `importString`, gensym .}
|
||||
helper(`obj`, `value`)
|
||||
|
||||
macro `.()`*[K: string | cstring, V: proc](obj: JsAssoc[K, V],
|
||||
macro `.()`*[K: cstring, V: proc](obj: JsAssoc[K, V],
|
||||
field: untyped,
|
||||
args: varargs[untyped]): auto =
|
||||
## Experimental "method call" operator for type JsAssoc.
|
||||
@@ -354,24 +367,18 @@ iterator keys*(obj: JsObject): cstring =
|
||||
yield k
|
||||
{.emit: "}".}
|
||||
|
||||
iterator pairs*[K, V](assoc: JsAssoc[K, V]): (K,V) =
|
||||
iterator pairs*[K: JsKey, V](assoc: JsAssoc[K, V]): (K,V) =
|
||||
## Yields tuples of type ``(K, V)``, with the first entry
|
||||
## being a `key` in the JsAssoc and the second being its corresponding value.
|
||||
when K is string:
|
||||
var k: cstring
|
||||
else:
|
||||
var k: K
|
||||
var k: cstring
|
||||
var v: V
|
||||
{.emit: "for (var `k` in `assoc`) {".}
|
||||
{.emit: " if (!`assoc`.hasOwnProperty(`k`)) continue;".}
|
||||
{.emit: " `v`=`assoc`[`k`];".}
|
||||
when K is string:
|
||||
yield ($k, v)
|
||||
else:
|
||||
yield (k, v)
|
||||
yield (k.toJsKey(K), v)
|
||||
{.emit: "}".}
|
||||
|
||||
iterator items*[K,V](assoc: JSAssoc[K,V]): V =
|
||||
iterator items*[K, V](assoc: JSAssoc[K, V]): V =
|
||||
## Yields the `values` in a JsAssoc.
|
||||
var v: V
|
||||
{.emit: "for (var k in `assoc`) {".}
|
||||
@@ -380,18 +387,12 @@ iterator items*[K,V](assoc: JSAssoc[K,V]): V =
|
||||
yield v
|
||||
{.emit: "}".}
|
||||
|
||||
iterator keys*[K,V](assoc: JSAssoc[K,V]): K =
|
||||
iterator keys*[K: JsKey, V](assoc: JSAssoc[K, V]): K =
|
||||
## Yields the `keys` in a JsAssoc.
|
||||
when K is string:
|
||||
var k: cstring
|
||||
else:
|
||||
var k: K
|
||||
var k: cstring
|
||||
{.emit: "for (var `k` in `assoc`) {".}
|
||||
{.emit: " if (!`assoc`.hasOwnProperty(`k`)) continue;".}
|
||||
when K is string:
|
||||
yield $k
|
||||
else:
|
||||
yield k
|
||||
yield k.toJsKey(K)
|
||||
{.emit: "}".}
|
||||
|
||||
# Literal generation
|
||||
|
||||
@@ -154,7 +154,7 @@ block:
|
||||
# Test JsAssoc .= and .
|
||||
block:
|
||||
proc test(): bool =
|
||||
let obj = newJsAssoc[string, int]()
|
||||
let obj = newJsAssoc[cstring, int]()
|
||||
var working = true
|
||||
obj.a = 11
|
||||
obj.`$!&` = 42
|
||||
@@ -168,7 +168,7 @@ block:
|
||||
# Test JsAssoc .()
|
||||
block:
|
||||
proc test(): bool =
|
||||
let obj = newJsAssoc[string, proc(e: int): int]()
|
||||
let obj = newJsAssoc[cstring, proc(e: int): int]()
|
||||
obj.a = proc(e: int): int = e * e
|
||||
obj.a(10) == 100
|
||||
echo test()
|
||||
@@ -176,7 +176,7 @@ block:
|
||||
# Test JsAssoc []()
|
||||
block:
|
||||
proc test(): bool =
|
||||
let obj = newJsAssoc[string, proc(e: int): int]()
|
||||
let obj = newJsAssoc[cstring, proc(e: int): int]()
|
||||
obj.a = proc(e: int): int = e * e
|
||||
let call = obj["a"]
|
||||
call(10) == 100
|
||||
@@ -185,7 +185,7 @@ block:
|
||||
# Test JsAssoc Iterators
|
||||
block:
|
||||
proc testPairs(): bool =
|
||||
let obj = newJsAssoc[string, int]()
|
||||
let obj = newJsAssoc[cstring, int]()
|
||||
var working = true
|
||||
obj.a = 10
|
||||
obj.b = 20
|
||||
@@ -202,7 +202,7 @@ block:
|
||||
return false
|
||||
working
|
||||
proc testItems(): bool =
|
||||
let obj = newJsAssoc[string, int]()
|
||||
let obj = newJsAssoc[cstring, int]()
|
||||
var working = true
|
||||
obj.a = 10
|
||||
obj.b = 20
|
||||
@@ -211,13 +211,13 @@ block:
|
||||
working = working and v in [10, 20, 30]
|
||||
working
|
||||
proc testKeys(): bool =
|
||||
let obj = newJsAssoc[string, int]()
|
||||
let obj = newJsAssoc[cstring, int]()
|
||||
var working = true
|
||||
obj.a = 10
|
||||
obj.b = 20
|
||||
obj.c = 30
|
||||
for v in obj.keys:
|
||||
working = working and v in ["a", "b", "c"]
|
||||
working = working and v in [cstring"a", cstring"b", cstring"c"]
|
||||
working
|
||||
proc test(): bool = testPairs() and testItems() and testKeys()
|
||||
echo test()
|
||||
@@ -226,8 +226,8 @@ block:
|
||||
block:
|
||||
proc test(): bool =
|
||||
{. emit: "var comparison = {a: 22, b: 55};" .}
|
||||
var comparison {. importcpp, nodecl .}: JsAssoc[string, int]
|
||||
let obj = newJsAssoc[string, int]()
|
||||
var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int]
|
||||
let obj = newJsAssoc[cstring, int]()
|
||||
obj.a = 22
|
||||
obj.b = 55
|
||||
obj.a == comparison.a and obj.b == comparison.b
|
||||
@@ -237,15 +237,15 @@ block:
|
||||
block:
|
||||
proc test(): bool =
|
||||
{. emit: "var comparison = {a: 22, b: 55};" .}
|
||||
var comparison {. importcpp, nodecl .}: JsAssoc[string, int]
|
||||
let obj = JsAssoc[string, int]{ a: 22, b: 55 }
|
||||
var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int]
|
||||
let obj = JsAssoc[cstring, int]{ a: 22, b: 55 }
|
||||
var working = true
|
||||
working = working and
|
||||
compiles(JsAssoc[int, int]{ 1: 22, 2: 55 })
|
||||
working = working and
|
||||
comparison.a == obj.a and comparison.b == obj.b
|
||||
working = working and
|
||||
not compiles(JsAssoc[string, int]{ a: "test" })
|
||||
not compiles(JsAssoc[cstring, int]{ a: "test" })
|
||||
working
|
||||
echo test()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user