Support only some types as JsAssoc types (#8627)
This commit is contained in:
parent
562d185cb7
commit
88d707cb88
2 changed files with 46 additions and 45 deletions
|
|
@ -69,10 +69,25 @@ template mangleJsName(name: cstring): cstring =
|
||||||
inc nameCounter
|
inc nameCounter
|
||||||
"mangledName" & $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
|
type
|
||||||
|
JsKey* = concept a, type T
|
||||||
|
cstring.toJsKey(T) is type(a)
|
||||||
|
|
||||||
JsObject* = ref object of JsRoot
|
JsObject* = ref object of JsRoot
|
||||||
## Dynamically typed wrapper around a JavaScript object.
|
## 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.
|
## Statically typed wrapper around a JavaScript object.
|
||||||
|
|
||||||
js* = JsObject
|
js* = JsObject
|
||||||
|
|
@ -104,7 +119,7 @@ type
|
||||||
proc newJsObject*: JsObject {. importcpp: "{@}" .}
|
proc newJsObject*: JsObject {. importcpp: "{@}" .}
|
||||||
## Creates a new empty JsObject
|
## 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`.
|
## Creates a new empty JsAssoc with key type `K` and value type `V`.
|
||||||
|
|
||||||
# Checks
|
# 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 .}
|
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`.
|
## 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 .}
|
{. importcpp: getImpl .}
|
||||||
## Return the value of a property of name `field` from a JsAssoc `obj`.
|
## Return the value of a property of name `field` from a JsAssoc `obj`.
|
||||||
|
|
||||||
proc `[]`*[V](obj: JsAssoc[string, V], field: cstring): V
|
proc `[]=`*[K: JsKey, V](obj: JsAssoc[K, V], field: K, val: 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)
|
|
||||||
{. importcpp: setImpl .}
|
{. importcpp: setImpl .}
|
||||||
## Set the value of a property of name `field` in a JsAssoc `obj` to `v`.
|
## 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)
|
proc `[]`*[V](obj: JsAssoc[cstring, V], field: string): V =
|
||||||
{. importcpp: setImpl .}
|
obj[cstring(field)]
|
||||||
## Set the value of a property of name `field` in a JsAssoc `obj` to `v`.
|
|
||||||
|
proc `[]=`*[V](obj: JsAssoc[cstring, V], field: string, val: V) =
|
||||||
|
obj[cstring(field)] = val
|
||||||
|
|
||||||
proc `==`*(x, y: JsRoot): bool {. importcpp: "(# === #)" .}
|
proc `==`*(x, y: JsRoot): bool {. importcpp: "(# === #)" .}
|
||||||
## Compare two JsObjects or JsAssocs. Be careful though, as this is comparison
|
## 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[0][3].add newIdentDefs(paramName, newIdentNode(!"JsObject"))
|
||||||
result[1].add args[idx].copyNimTree
|
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 =
|
field: untyped): V =
|
||||||
## Experimental dot accessor (get) for type JsAssoc.
|
## Experimental dot accessor (get) for type JsAssoc.
|
||||||
## Returns the value of a property of name `field` from a JsObject `x`.
|
## 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 .}
|
{. importcpp: `importString`, gensym .}
|
||||||
helper(`obj`)
|
helper(`obj`)
|
||||||
|
|
||||||
macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
macro `.=`*[K: cstring, V](obj: JsAssoc[K, V],
|
||||||
field: untyped,
|
field: untyped,
|
||||||
value: V): untyped =
|
value: V): untyped =
|
||||||
## Experimental dot accessor (set) for type JsAssoc.
|
## Experimental dot accessor (set) for type JsAssoc.
|
||||||
|
|
@ -310,7 +323,7 @@ macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||||
{. importcpp: `importString`, gensym .}
|
{. importcpp: `importString`, gensym .}
|
||||||
helper(`obj`, `value`)
|
helper(`obj`, `value`)
|
||||||
|
|
||||||
macro `.()`*[K: string | cstring, V: proc](obj: JsAssoc[K, V],
|
macro `.()`*[K: cstring, V: proc](obj: JsAssoc[K, V],
|
||||||
field: untyped,
|
field: untyped,
|
||||||
args: varargs[untyped]): auto =
|
args: varargs[untyped]): auto =
|
||||||
## Experimental "method call" operator for type JsAssoc.
|
## Experimental "method call" operator for type JsAssoc.
|
||||||
|
|
@ -354,24 +367,18 @@ iterator keys*(obj: JsObject): cstring =
|
||||||
yield k
|
yield k
|
||||||
{.emit: "}".}
|
{.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
|
## Yields tuples of type ``(K, V)``, with the first entry
|
||||||
## being a `key` in the JsAssoc and the second being its corresponding value.
|
## being a `key` in the JsAssoc and the second being its corresponding value.
|
||||||
when K is string:
|
var k: cstring
|
||||||
var k: cstring
|
|
||||||
else:
|
|
||||||
var k: K
|
|
||||||
var v: V
|
var v: V
|
||||||
{.emit: "for (var `k` in `assoc`) {".}
|
{.emit: "for (var `k` in `assoc`) {".}
|
||||||
{.emit: " if (!`assoc`.hasOwnProperty(`k`)) continue;".}
|
{.emit: " if (!`assoc`.hasOwnProperty(`k`)) continue;".}
|
||||||
{.emit: " `v`=`assoc`[`k`];".}
|
{.emit: " `v`=`assoc`[`k`];".}
|
||||||
when K is string:
|
yield (k.toJsKey(K), v)
|
||||||
yield ($k, v)
|
|
||||||
else:
|
|
||||||
yield (k, v)
|
|
||||||
{.emit: "}".}
|
{.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.
|
## Yields the `values` in a JsAssoc.
|
||||||
var v: V
|
var v: V
|
||||||
{.emit: "for (var k in `assoc`) {".}
|
{.emit: "for (var k in `assoc`) {".}
|
||||||
|
|
@ -380,18 +387,12 @@ iterator items*[K,V](assoc: JSAssoc[K,V]): V =
|
||||||
yield v
|
yield v
|
||||||
{.emit: "}".}
|
{.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.
|
## Yields the `keys` in a JsAssoc.
|
||||||
when K is string:
|
var k: cstring
|
||||||
var k: cstring
|
|
||||||
else:
|
|
||||||
var k: K
|
|
||||||
{.emit: "for (var `k` in `assoc`) {".}
|
{.emit: "for (var `k` in `assoc`) {".}
|
||||||
{.emit: " if (!`assoc`.hasOwnProperty(`k`)) continue;".}
|
{.emit: " if (!`assoc`.hasOwnProperty(`k`)) continue;".}
|
||||||
when K is string:
|
yield k.toJsKey(K)
|
||||||
yield $k
|
|
||||||
else:
|
|
||||||
yield k
|
|
||||||
{.emit: "}".}
|
{.emit: "}".}
|
||||||
|
|
||||||
# Literal generation
|
# Literal generation
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ block:
|
||||||
# Test JsAssoc .= and .
|
# Test JsAssoc .= and .
|
||||||
block:
|
block:
|
||||||
proc test(): bool =
|
proc test(): bool =
|
||||||
let obj = newJsAssoc[string, int]()
|
let obj = newJsAssoc[cstring, int]()
|
||||||
var working = true
|
var working = true
|
||||||
obj.a = 11
|
obj.a = 11
|
||||||
obj.`$!&` = 42
|
obj.`$!&` = 42
|
||||||
|
|
@ -168,7 +168,7 @@ block:
|
||||||
# Test JsAssoc .()
|
# Test JsAssoc .()
|
||||||
block:
|
block:
|
||||||
proc test(): bool =
|
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 = proc(e: int): int = e * e
|
||||||
obj.a(10) == 100
|
obj.a(10) == 100
|
||||||
echo test()
|
echo test()
|
||||||
|
|
@ -176,7 +176,7 @@ block:
|
||||||
# Test JsAssoc []()
|
# Test JsAssoc []()
|
||||||
block:
|
block:
|
||||||
proc test(): bool =
|
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 = proc(e: int): int = e * e
|
||||||
let call = obj["a"]
|
let call = obj["a"]
|
||||||
call(10) == 100
|
call(10) == 100
|
||||||
|
|
@ -185,7 +185,7 @@ block:
|
||||||
# Test JsAssoc Iterators
|
# Test JsAssoc Iterators
|
||||||
block:
|
block:
|
||||||
proc testPairs(): bool =
|
proc testPairs(): bool =
|
||||||
let obj = newJsAssoc[string, int]()
|
let obj = newJsAssoc[cstring, int]()
|
||||||
var working = true
|
var working = true
|
||||||
obj.a = 10
|
obj.a = 10
|
||||||
obj.b = 20
|
obj.b = 20
|
||||||
|
|
@ -202,7 +202,7 @@ block:
|
||||||
return false
|
return false
|
||||||
working
|
working
|
||||||
proc testItems(): bool =
|
proc testItems(): bool =
|
||||||
let obj = newJsAssoc[string, int]()
|
let obj = newJsAssoc[cstring, int]()
|
||||||
var working = true
|
var working = true
|
||||||
obj.a = 10
|
obj.a = 10
|
||||||
obj.b = 20
|
obj.b = 20
|
||||||
|
|
@ -211,13 +211,13 @@ block:
|
||||||
working = working and v in [10, 20, 30]
|
working = working and v in [10, 20, 30]
|
||||||
working
|
working
|
||||||
proc testKeys(): bool =
|
proc testKeys(): bool =
|
||||||
let obj = newJsAssoc[string, int]()
|
let obj = newJsAssoc[cstring, int]()
|
||||||
var working = true
|
var working = true
|
||||||
obj.a = 10
|
obj.a = 10
|
||||||
obj.b = 20
|
obj.b = 20
|
||||||
obj.c = 30
|
obj.c = 30
|
||||||
for v in obj.keys:
|
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
|
working
|
||||||
proc test(): bool = testPairs() and testItems() and testKeys()
|
proc test(): bool = testPairs() and testItems() and testKeys()
|
||||||
echo test()
|
echo test()
|
||||||
|
|
@ -226,8 +226,8 @@ block:
|
||||||
block:
|
block:
|
||||||
proc test(): bool =
|
proc test(): bool =
|
||||||
{. emit: "var comparison = {a: 22, b: 55};" .}
|
{. emit: "var comparison = {a: 22, b: 55};" .}
|
||||||
var comparison {. importcpp, nodecl .}: JsAssoc[string, int]
|
var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int]
|
||||||
let obj = newJsAssoc[string, int]()
|
let obj = newJsAssoc[cstring, int]()
|
||||||
obj.a = 22
|
obj.a = 22
|
||||||
obj.b = 55
|
obj.b = 55
|
||||||
obj.a == comparison.a and obj.b == comparison.b
|
obj.a == comparison.a and obj.b == comparison.b
|
||||||
|
|
@ -237,15 +237,15 @@ block:
|
||||||
block:
|
block:
|
||||||
proc test(): bool =
|
proc test(): bool =
|
||||||
{. emit: "var comparison = {a: 22, b: 55};" .}
|
{. emit: "var comparison = {a: 22, b: 55};" .}
|
||||||
var comparison {. importcpp, nodecl .}: JsAssoc[string, int]
|
var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int]
|
||||||
let obj = JsAssoc[string, int]{ a: 22, b: 55 }
|
let obj = JsAssoc[cstring, int]{ a: 22, b: 55 }
|
||||||
var working = true
|
var working = true
|
||||||
working = working and
|
working = working and
|
||||||
compiles(JsAssoc[int, int]{ 1: 22, 2: 55 })
|
compiles(JsAssoc[int, int]{ 1: 22, 2: 55 })
|
||||||
working = working and
|
working = working and
|
||||||
comparison.a == obj.a and comparison.b == obj.b
|
comparison.a == obj.a and comparison.b == obj.b
|
||||||
working = working and
|
working = working and
|
||||||
not compiles(JsAssoc[string, int]{ a: "test" })
|
not compiles(JsAssoc[cstring, int]{ a: "test" })
|
||||||
working
|
working
|
||||||
echo test()
|
echo test()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue