Skip to content

better importjs: func fn(a: var int, b: int) {.importjs: "$2 = $3 + $2".} #315

Open
@timotheecour

Description

@timotheecour

problem 1: var params

when var params are involved, the wrappers in std/jsbigints are more complicated than they should, and maybe even create overhead:

func inc*(this: var JsBigInt; amount: JsBigInt) {.importjs: "([#][0][0] += #)".} =

problem 2: referring to arguments out of order or multiple times

importjs doesn't allow referring to arguments by position, creating more complex and potentially less efficient wrappers:

func wrapToUint*(this: JsBigInt; bits: Natural): JsBigInt {.importjs:
  "(() => { const i = #, b = #; return BigInt.asUintN(b, i) })()".} =

proposal

  • P1 extent the $1 notation (which maps to the proc name) to allow referring to params (eg: $2 is 1st param)
    example:
func wrapToUint*(this: JsBigInt; bits: Natural): JsBigInt {.importjs:
  "(() => { const i = #, b = #; return BigInt.asUintN(b, i) })()".} =
=>
func wrapToUint*(this: JsBigInt; bits: Natural): JsBigInt {.importjs: "BigInt.asUintN($3, $2)"
  • P2 make the dereferencing for var params implicit: $2 maps to ($2)[0] in js
    example:
func inc*(this: var JsBigInt; amount: JsBigInt) {.importjs: "([#][0][0] += #)".}
=>
func inc*(this: var JsBigInt; amount: JsBigInt) {.importjs: "$2 += $3".}

example with a var param and a param referred to more than once:

func myFun*(a: var int, b: int) {.importjs: "$2 = $2 + $3".}
  • P3 make jsgen auto-insert () around each param so these don't need to appear in declaration (to prevent
    example:
func `**`*(x, y: JsBigInt): JsBigInt {.importjs: "((#) $1 #)".}
=>
func `**`*(x, y: JsBigInt): JsBigInt {.importjs: "$2 $1 $3".}
# instead of
func `**`*(x, y: JsBigInt): JsBigInt {.importjs: "($2) $1 $3".}

note: see nim-lang/Nim#16409 (comment) as to why parens are needed in the first place

  • P4 (implicitly assumed in above examples): don't require a () wrapping the whole importjs expression, as soon as at least one un-escaped $ is detected; this is not the same as P3.
func `==`*(x, y: JsBigInt): bool {.importjs: "(# == #)".}
=>
func `==`*(x, y: JsBigInt): bool {.importjs: "$2 == $3".}
# instead of:
func `==`*(x, y: JsBigInt): bool {.importjs: "($2 == $3)".}

TODO

figure out what to do with:

func debugger*() {.importjs: "debugger".} # should codegen as `debugger;`, not `debugger();`

refs nim-lang/Nim#17296 (comment)
can this work non-ambiguously?

func debugger*() {.importjs: "debugger".}
func debugger*() {.importjs: "$1".} # or even this

Using importjs there gives importjs for routines requires a pattern errors, since apparently importjs doesn't behave the same as importc and importcpp. Should I open an issue for this or just add patterns for the imports (in a future PR)?

links

importjs pragma is underdocumented and buggy · Issue #488 · timotheecour/Nim

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions