Add hasClosure to std/effecttraits

This commit is contained in:
flywind
2021-03-25 10:32:45 +08:00
parent b816979a46
commit b7b90f2c1a
4 changed files with 109 additions and 1 deletions

View File

@@ -244,6 +244,8 @@
- Added dollar `$` and `len` for `jsre.RegExp`.
- Added `hasClosure` to `std/effecttraits`.
## Language changes

View File

@@ -316,3 +316,7 @@ proc registerAdditionalOps*(c: PCtx) =
let fn = getNode(a, 0)
setResult(a, (fn.typ != nil and tfNoSideEffect in fn.typ.flags) or
(fn.kind == nkSym and fn.sym.kind == skFunc))
registerCallback c, "stdlib.effecttraits.hasClosureImpl", proc (a: VmArgs) =
let fn = getNode(a, 0)
setResult(a, fn.kind == nkClosure or (fn.typ != nil and fn.typ.callConv == ccClosure))

View File

@@ -14,12 +14,14 @@
## One can test for the existance of this standard module
## via `defined(nimHasEffectTraitsModule)`.
import macros
import std/macros
import std/private/since
proc getRaisesListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim"
proc getTagsListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim"
proc isGcSafeImpl(n: NimNode): bool = discard "see compiler/vmops.nim"
proc hasNoSideEffectsImpl(n: NimNode): bool = discard "see compiler/vmops.nim"
proc hasClosureImpl(n: NimNode): bool = discard "see compiler/vmops.nim"
proc getRaisesList*(fn: NimNode): NimNode =
## Extracts the `.raises` list of the func/proc/etc `fn`.
@@ -52,3 +54,11 @@ proc hasNoSideEffects*(fn: NimNode): bool =
## arguments and not `untyped` arguments.
expectKind fn, nnkSym
result = hasNoSideEffectsImpl(fn)
proc hasClosure*(fn: NimNode): bool {.since: (1, 5, 1).} =
## Return true if the func/proc/etc `fn` has `closure`.
## `fn` has to be a resolved symbol of kind `nnkSym`. This
## implies that the macro that calls this proc should accept `typed`
## arguments and not `untyped` arguments.
expectKind fn, nnkSym
result = hasClosureImpl(fn)

View File

@@ -0,0 +1,92 @@
discard """
targets: "c cpp js"
"""
import std/effecttraits
macro testClosure(fn: typed, flag: static bool) =
if flag:
doAssert hasClosure(fn)
else:
doAssert not hasClosure(fn)
block:
proc h1() =
echo 1
testClosure(h1, false)
proc h2() {.nimcall.} =
echo 2
testClosure(h2, false)
block:
proc fn(): auto =
proc hello() {.nimcall.} =
echo 3
hello
let name = fn()
testClosure(name, false)
block:
proc fn(): auto =
proc hello() =
echo 3
hello
let name = fn()
testClosure(name, false)
block:
proc fn(): auto =
var x = 0
proc hello() =
echo 3
inc x
hello
let name = fn()
testClosure(name, true)
block:
proc fn(): auto =
var x = 0
proc hello() {.closure.} =
echo 3
inc x
hello
let name = fn()
testClosure(name, true)
block:
proc fn(): auto =
var x = 0
proc hello() {.closure.} =
echo 3
inc x
hello
let name = fn()
testClosure(name, true)
let name2 = name
testClosure(name2, true)
block:
iterator hello(): int =
yield 1
testClosure(hello, false)
when not defined(js):
block:
iterator hello(): int {.closure.}=
yield 1
testClosure(hello, true)