improve the usability of the jsffi module
* All JavaScript operators are usable with JsObject * The dot operators will use native JavaScript strings * Results returned from dot calls are consired discardable
This commit is contained in:
parent
987b522071
commit
48a1a54d1c
2 changed files with 104 additions and 10 deletions
|
|
@ -79,6 +79,9 @@ type
|
||||||
NotString = concept c
|
NotString = concept c
|
||||||
c isnot string
|
c isnot string
|
||||||
|
|
||||||
|
var jsarguments* {.importc: "arguments", nodecl}: JsObject
|
||||||
|
## JavaScript's arguments pseudo-variable
|
||||||
|
|
||||||
# New
|
# New
|
||||||
proc newJsObject*: JsObject {. importcpp: "{@}" .}
|
proc newJsObject*: JsObject {. importcpp: "{@}" .}
|
||||||
## Creates a new empty JsObject
|
## Creates a new empty JsObject
|
||||||
|
|
@ -93,18 +96,62 @@ proc hasOwnProperty*(x: JsObject, prop: cstring): bool
|
||||||
proc jsTypeOf*(x: JsObject): cstring {. importcpp: "typeof(#)" .}
|
proc jsTypeOf*(x: JsObject): cstring {. importcpp: "typeof(#)" .}
|
||||||
## Returns the name of the JsObject's JavaScript type as a cstring.
|
## Returns the name of the JsObject's JavaScript type as a cstring.
|
||||||
|
|
||||||
|
proc jsnew*(x: auto): JsObject {.importcpp: "(new #)".}
|
||||||
|
## Turns a regular function call into an invocation of the
|
||||||
|
## JavaScript's `new` operator
|
||||||
|
|
||||||
|
proc jsdelete*(x: auto): JsObject {.importcpp: "(delete #)".}
|
||||||
|
## JavaScript's `delete` operator
|
||||||
|
|
||||||
# Conversion to and from JsObject
|
# Conversion to and from JsObject
|
||||||
proc to*(x: JsObject, T: typedesc): T {. importcpp: "(#)" .}
|
proc to*(x: JsObject, T: typedesc): T {. importcpp: "(#)" .}
|
||||||
## Converts a JsObject `x` to type `T`.
|
## Converts a JsObject `x` to type `T`.
|
||||||
|
|
||||||
proc toJs*[T](val: T): JsObject {. importcpp: "(#)" .}
|
proc toJs*[T](val: T): JsObject {. importcpp: "(#)" .}
|
||||||
## Converts a value of any type to type JsObject
|
## Converts a value of any type to type JsObject
|
||||||
|
|
||||||
|
template toJs*(s: string): JsObject = cstring(s).toJs
|
||||||
|
|
||||||
|
proc `&`*(a, b: cstring): cstring {.importcpp: "(# + #)".}
|
||||||
|
## Concatenation operator for JavaScript strings
|
||||||
|
|
||||||
|
proc `+` *(x, y: JsObject): JsObject {. importcpp: "(# + #)" .}
|
||||||
|
proc `-` *(x, y: JsObject): JsObject {. importcpp: "(# - #)" .}
|
||||||
|
proc `*` *(x, y: JsObject): JsObject {. importcpp: "(# * #)" .}
|
||||||
|
proc `/` *(x, y: JsObject): JsObject {. importcpp: "(# / #)" .}
|
||||||
|
proc `%` *(x, y: JsObject): JsObject {. importcpp: "(# % #)" .}
|
||||||
|
proc `+=` *(x, y: JsObject): JsObject {. importcpp: "(# += #)", discardable .}
|
||||||
|
proc `-=` *(x, y: JsObject): JsObject {. importcpp: "(# -= #)", discardable .}
|
||||||
|
proc `*=` *(x, y: JsObject): JsObject {. importcpp: "(# *= #)", discardable .}
|
||||||
|
proc `/=` *(x, y: JsObject): JsObject {. importcpp: "(# /= #)", discardable .}
|
||||||
|
proc `%=` *(x, y: JsObject): JsObject {. importcpp: "(# %= #)", discardable .}
|
||||||
|
proc `++` *(x: JsObject): JsObject {. importcpp: "(++#)" .}
|
||||||
|
proc `--` *(x: JsObject): JsObject {. importcpp: "(--#)" .}
|
||||||
|
# proc `==` *(x, y: JsObject): JsObject {. importcpp: "(# == #)" .}
|
||||||
|
# proc `===`*(x, y: JsObject): JsObject {. importcpp: "(# === #)" .}
|
||||||
|
# proc `!=` *(x, y: JsObject): JsObject {. importcpp: "(# != #)" .}
|
||||||
|
# proc `!==`*(x, y: JsObject): JsObject {. importcpp: "(# !== #)" .}
|
||||||
|
proc `>` *(x, y: JsObject): JsObject {. importcpp: "(# > #)" .}
|
||||||
|
proc `<` *(x, y: JsObject): JsObject {. importcpp: "(# < #)" .}
|
||||||
|
proc `>=` *(x, y: JsObject): JsObject {. importcpp: "(# >= #)" .}
|
||||||
|
proc `<=` *(x, y: JsObject): JsObject {. importcpp: "(# <= #)" .}
|
||||||
|
proc `and`*(x, y: JsObject): JsObject {. importcpp: "(# && #)" .}
|
||||||
|
proc `or` *(x, y: JsObject): JsObject {. importcpp: "(# || #)" .}
|
||||||
|
proc `not`*(x: JsObject): JsObject {. importcpp: "(!#)" .}
|
||||||
|
proc `in` *(x, y: JsObject): JsObject {. importcpp: "(# in #)" .}
|
||||||
|
|
||||||
proc `[]`*(obj: JsObject, field: cstring): JsObject {. importcpp: getImpl .}
|
proc `[]`*(obj: JsObject, field: cstring): JsObject {. importcpp: getImpl .}
|
||||||
## Return the value of a property of name `field` from a JsObject `obj`.
|
## Return the value of a property of name `field` from a JsObject `obj`.
|
||||||
|
|
||||||
|
proc `[]`*(obj: JsObject, field: int): JsObject {. importcpp: getImpl .}
|
||||||
|
## Return the value of a property of name `field` from a JsObject `obj`.
|
||||||
|
|
||||||
proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {. importcpp: setImpl .}
|
proc `[]=`*[T](obj: JsObject, field: cstring, 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 `[]=`*[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: NotString, V](obj: JsAssoc[K, V], field: K): V
|
proc `[]`*[K: NotString, 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`.
|
||||||
|
|
@ -171,8 +218,9 @@ macro `.=`*(obj: JsObject, field: static[cstring], value: untyped): untyped =
|
||||||
{. importcpp: `importString`, gensym .}
|
{. importcpp: `importString`, gensym .}
|
||||||
helper(`obj`, `value`)
|
helper(`obj`, `value`)
|
||||||
|
|
||||||
macro `.()`*(obj: JsObject, field: static[cstring],
|
macro `.()`*(obj: JsObject,
|
||||||
args: varargs[JsObject, toJs]): JsObject =
|
field: static[cstring],
|
||||||
|
args: varargs[JsObject, toJs]): JsObject =
|
||||||
## Experimental "method call" operator for type JsObject.
|
## Experimental "method call" operator for type JsObject.
|
||||||
## Takes the name of a method of the JavaScript object (`field`) and calls
|
## Takes the name of a method of the JavaScript object (`field`) and calls
|
||||||
## it with `args` as arguments, returning a JsObject (which may be discarded,
|
## it with `args` as arguments, returning a JsObject (which may be discarded,
|
||||||
|
|
@ -198,7 +246,7 @@ macro `.()`*(obj: JsObject, field: static[cstring],
|
||||||
importString = "#." & mangledNames[$field] & "(@)"
|
importString = "#." & mangledNames[$field] & "(@)"
|
||||||
result = quote do:
|
result = quote do:
|
||||||
proc helper(o: JsObject): JsObject
|
proc helper(o: JsObject): JsObject
|
||||||
{. importcpp: `importString`, gensym .}
|
{. importcpp: `importString`, gensym, discardable .}
|
||||||
helper(`obj`)
|
helper(`obj`)
|
||||||
for idx in 0 ..< args.len:
|
for idx in 0 ..< args.len:
|
||||||
let paramName = newIdentNode(!("param" & $idx))
|
let paramName = newIdentNode(!("param" & $idx))
|
||||||
|
|
@ -206,7 +254,7 @@ macro `.()`*(obj: JsObject, field: static[cstring],
|
||||||
result[1].add args[idx].copyNimTree
|
result[1].add args[idx].copyNimTree
|
||||||
|
|
||||||
macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||||
field: static[cstring]): V =
|
field: static[cstring]): 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`.
|
||||||
var importString: string
|
var importString: string
|
||||||
|
|
@ -222,7 +270,8 @@ macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||||
helper(`obj`)
|
helper(`obj`)
|
||||||
|
|
||||||
macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||||
field: static[cstring], value: V): untyped =
|
field: static[cstring],
|
||||||
|
value: V): untyped =
|
||||||
## Experimental dot accessor (set) for type JsAssoc.
|
## Experimental dot accessor (set) for type JsAssoc.
|
||||||
## Sets the value of a property of name `field` in a JsObject `x` to `value`.
|
## Sets the value of a property of name `field` in a JsObject `x` to `value`.
|
||||||
var importString: string
|
var importString: string
|
||||||
|
|
@ -238,7 +287,8 @@ macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
|
||||||
helper(`obj`, `value`)
|
helper(`obj`, `value`)
|
||||||
|
|
||||||
macro `.()`*[K: string | cstring, V: proc](obj: JsAssoc[K, V],
|
macro `.()`*[K: string | cstring, V: proc](obj: JsAssoc[K, V],
|
||||||
field: static[cstring], args: varargs[untyped]): auto =
|
field: static[cstring],
|
||||||
|
args: varargs[untyped]): auto =
|
||||||
## Experimental "method call" operator for type JsAssoc.
|
## Experimental "method call" operator for type JsAssoc.
|
||||||
## Takes the name of a method of the JavaScript object (`field`) and calls
|
## Takes the name of a method of the JavaScript object (`field`) and calls
|
||||||
## it with `args` as arguments. Here, everything is typechecked, so you do not
|
## it with `args` as arguments. Here, everything is typechecked, so you do not
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,15 @@ true
|
||||||
true
|
true
|
||||||
true
|
true
|
||||||
true
|
true
|
||||||
true'''
|
true
|
||||||
|
3
|
||||||
|
2
|
||||||
|
12
|
||||||
|
Event { name: 'click: test' }
|
||||||
|
Event { name: 'reloaded: test' }'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import macros, jsffi
|
import macros, jsffi, jsconsole
|
||||||
|
|
||||||
# Tests for JsObject
|
# Tests for JsObject
|
||||||
# Test JsObject []= and []
|
# Test JsObject []= and []
|
||||||
|
|
@ -55,8 +60,8 @@ block:
|
||||||
block:
|
block:
|
||||||
proc test(): bool =
|
proc test(): bool =
|
||||||
let obj = newJsObject()
|
let obj = newJsObject()
|
||||||
obj.`?!$` = proc(x, y, z: int, t: string): string = t & $(x + y + z)
|
obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z)
|
||||||
obj.`?!$`(1, 2, 3, "Result is: ").to(string) == "Result is: 6"
|
obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == "Result is: 6"
|
||||||
echo test()
|
echo test()
|
||||||
|
|
||||||
# Test JsObject []()
|
# Test JsObject []()
|
||||||
|
|
@ -265,3 +270,42 @@ block:
|
||||||
let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever))
|
let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever))
|
||||||
obj.onWhatever(1) == 10
|
obj.onWhatever(1) == 10
|
||||||
echo test()
|
echo test()
|
||||||
|
|
||||||
|
block:
|
||||||
|
{.emit: "function jsProc(n) { return n; }" .}
|
||||||
|
proc jsProc(x: int32): JsObject {.importc: "jsProc".}
|
||||||
|
|
||||||
|
proc test() =
|
||||||
|
var x = jsProc(1)
|
||||||
|
var y = jsProc(2)
|
||||||
|
console.log x + y
|
||||||
|
console.log ++x
|
||||||
|
|
||||||
|
x += jsProc(10)
|
||||||
|
console.log x
|
||||||
|
|
||||||
|
test()
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
|
block:
|
||||||
|
{.emit:
|
||||||
|
"""
|
||||||
|
function Event(name) { this.name = name; }
|
||||||
|
function on(eventName, eventHandler) { eventHandler(new Event(eventName + ": test")); }
|
||||||
|
var jslib = { "on": on };
|
||||||
|
"""
|
||||||
|
.}
|
||||||
|
|
||||||
|
type Event = object
|
||||||
|
name: cstring
|
||||||
|
|
||||||
|
proc on(event: cstring, handler: proc) {.importc: "on".}
|
||||||
|
var jslib {.importc: "jslib", nodecl.}: JsObject
|
||||||
|
|
||||||
|
on("click") do (e: Event):
|
||||||
|
console.log e
|
||||||
|
|
||||||
|
jslib.on("reloaded") do:
|
||||||
|
console.log jsarguments[0]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue