From 3a55bae53fe80728ce625dd5366aee5da9cf6463 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Mon, 9 Sep 2024 20:20:40 +0800 Subject: [PATCH] enable closures tests for JS & implement `finished` for JS (#23521) --- changelog.md | 3 +++ compiler/jsgen.nim | 22 ++++++++++++---------- lib/system.nim | 10 ++++++++-- tests/closure/t8550.nim | 1 + tests/closure/tnested.nim | 35 +++++++++++++++++++++++++++-------- tests/iter/t1550.nim | 4 ++++ tests/iter/t21306.nim | 4 ++++ tests/iter/t2771.nim | 4 ++++ tests/iter/tanoniter1.nim | 1 + tests/iter/tclosureiters.nim | 20 ++++++++++++-------- tests/iter/titer11.nim | 1 + tests/iter/titer12.nim | 1 + tests/iter/titer_issues.nim | 1 + 13 files changed, 79 insertions(+), 28 deletions(-) diff --git a/changelog.md b/changelog.md index 67b6c74f8b..46bc1a8724 100644 --- a/changelog.md +++ b/changelog.md @@ -19,6 +19,8 @@ - JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behavior. +- JS backend now supports closure iterators. + - `owner` in `std/macros` is deprecated. - Ambiguous type symbols in generic procs and templates now generate symchoice nodes. @@ -51,6 +53,7 @@ let baz = a # error ``` + ## Standard library additions and changes [//]: # "Changes:" diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 91862777a8..713944defb 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -611,6 +611,17 @@ template unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = r.res = frmt % [a, tmp] r.kind = resExpr +proc genBreakState(p: PProc, n: PNode, r: var TCompRes) = + var a: TCompRes = default(TCompRes) + # mangle `:state` properly somehow + if n.kind == nkClosure: + gen(p, n[1], a) + r.res = "(($1).HEX3Astate < 0)" % [rdLoc(a)] + else: + gen(p, n, a) + r.res = "((($1.ClE_0).HEX3Astate) < 0)" % [rdLoc(a)] + r.kind = resExpr + proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = var x, y: TCompRes = default(TCompRes) @@ -3054,16 +3065,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = of nkGotoState, nkState: globalError(p.config, n.info, "not implemented") of nkBreakState: - var a: TCompRes = default(TCompRes) - if n[0].kind == nkClosure: - gen(p, n[0][1], a) - let sym = n[0][1].typ[0].n[0].sym - r.res = "(($1).$2 < 0)" % [rdLoc(a), mangleName(p.module, sym)] - else: - gen(p, n[0], a) - let sym = n[0].typ[0].n[0].sym - r.res = "((($1.ClE_0).$2) < 0)" % [rdLoc(a), mangleName(p.module, sym)] - r.kind = resExpr + genBreakState(p, n[0], r) of nkPragmaBlock: gen(p, n.lastSon, r) of nkComesFrom: discard "XXX to implement for better stack traces" diff --git a/lib/system.nim b/lib/system.nim index aeeda831fd..5f4847b7d2 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2350,8 +2350,14 @@ when notJSnotNims: `result` = `x`.ClE_0; """.} - proc finished*[T: iterator {.closure.}](x: T): bool {.noSideEffect, inline, magic: "Finished".} = - ## It can be used to determine if a first class iterator has finished. +proc finished*[T: iterator {.closure.}](x: T): bool {.noSideEffect, inline, magic: "Finished".} = + ## It can be used to determine if a first class iterator has finished. + when defined(js): + # TODO: mangle `:state` + {.emit: """ + `result` = (`x`.ClE_0).HEX3Astate < 0; + """.} + else: {.emit: """ `result` = ((NI*) `x`.ClE_0)[1] < 0; """.} diff --git a/tests/closure/t8550.nim b/tests/closure/t8550.nim index 153246f085..a07f45cdc9 100644 --- a/tests/closure/t8550.nim +++ b/tests/closure/t8550.nim @@ -1,4 +1,5 @@ discard """ + targets: "c js" output: "@[\"42\"]" """ diff --git a/tests/closure/tnested.nim b/tests/closure/tnested.nim index 31963ea863..ec5af9b135 100644 --- a/tests/closure/tnested.nim +++ b/tests/closure/tnested.nim @@ -1,4 +1,5 @@ discard """ +targets: "c js" output: ''' foo88 23 24foo 88 @@ -183,14 +184,32 @@ block tclosure2: import typetraits -proc myDiscard[T](a: T) = discard +block: + proc myDiscard[T](a: T) = discard -proc foo() = - let a = 5 - let f = (proc() = - myDiscard (proc() = echo a) - ) - echo name(typeof(f)) + proc foo() = + let a = 5 + let f = (proc() = + myDiscard (proc() = echo a) + ) + echo name(typeof(f)) -foo() + foo() + +block: + iterator foo: int {.closure.} = + yield 1 + yield 2 + yield 3 + + proc pork = + let call = foo + for i in call(): + discard i + + let call2 = foo + while not finished(call2): + discard call2() + + pork() diff --git a/tests/iter/t1550.nim b/tests/iter/t1550.nim index 8ad96f0dac..c971943ee3 100644 --- a/tests/iter/t1550.nim +++ b/tests/iter/t1550.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c js" +""" + type A[T] = iterator(x: T): T {.gcsafe, closure.} diff --git a/tests/iter/t21306.nim b/tests/iter/t21306.nim index 43fea9c80c..4d03962940 100644 --- a/tests/iter/t21306.nim +++ b/tests/iter/t21306.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c js" +""" + # bug #21306 type FutureState {.pure.} = enum diff --git a/tests/iter/t2771.nim b/tests/iter/t2771.nim index 49befb0a97..71a8a9dcdc 100644 --- a/tests/iter/t2771.nim +++ b/tests/iter/t2771.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c js" +""" + template t1(i: int): int= i+1 template t2(i: int): int= diff --git a/tests/iter/tanoniter1.nim b/tests/iter/tanoniter1.nim index 9f0d0a74bc..fee16497f0 100644 --- a/tests/iter/tanoniter1.nim +++ b/tests/iter/tanoniter1.nim @@ -1,4 +1,5 @@ discard """ + targets: "c js" output: '''1 2 3 diff --git a/tests/iter/tclosureiters.nim b/tests/iter/tclosureiters.nim index 85611373ce..4a26398523 100644 --- a/tests/iter/tclosureiters.nim +++ b/tests/iter/tclosureiters.nim @@ -1,4 +1,5 @@ discard """ + targets: "c js" output: '''0 1 2 @@ -152,15 +153,18 @@ iterator filesIt(path: string): auto {.closure.} = yield prefix / f # bug #13815 -var love = iterator: int {.closure.} = - yield cast[type( - block: - var a = 0 - yield a - a)](0) +when not defined(js): + var love = iterator: int {.closure.} = + yield cast[type( + block: + var a = 0 + yield a + a)](0) -for i in love(): - echo i + for i in love(): + echo i +else: + echo 0 # bug #18474 iterator pairs(): (int, int) {.closure.} = diff --git a/tests/iter/titer11.nim b/tests/iter/titer11.nim index 2b39c74f7d..153b3c29a7 100644 --- a/tests/iter/titer11.nim +++ b/tests/iter/titer11.nim @@ -1,4 +1,5 @@ discard """ +targets: "c js" output: ''' [ 1 diff --git a/tests/iter/titer12.nim b/tests/iter/titer12.nim index f7fc64da4e..f264a0e828 100644 --- a/tests/iter/titer12.nim +++ b/tests/iter/titer12.nim @@ -1,4 +1,5 @@ discard """ +targets: "c js" output: ''' Selecting 2 1.0 diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index b553251b51..c82b3902d4 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -1,4 +1,5 @@ discard """ + target: "c js" output: ''' 0 1