diff --git a/src/main/java/suite/funp/P0.java b/src/main/java/suite/funp/P0.java index fe1317d03..f4c6cbf59 100644 --- a/src/main/java/suite/funp/P0.java +++ b/src/main/java/suite/funp/P0.java @@ -697,6 +697,7 @@ public enum Fct { // function capture type MANUAL, // capture the variables and allocate a capture frame, to be uncaptured (freed) manually NOSCOP, // no access to variables of outer scope ONCE__, // capture the variables and allocate a capture frame, which is to be freed after first call; lambda cannot be called twice + SINGLE, // pass one variable STACKF, // pass the stack frame, no need to capture; lambda lifetime equals to stack frame lifetime } diff --git a/src/main/java/suite/funp/P2.java b/src/main/java/suite/funp/P2.java index 8f945473a..8cf762637 100644 --- a/src/main/java/suite/funp/P2.java +++ b/src/main/java/suite/funp/P2.java @@ -290,19 +290,43 @@ public R apply(FixieFun5 fun) { } } + public static class FunpLambdaCapSingle implements Funp, P2.End { + public FunpVariable fpIn; + public FunpVariable frameVar; + public Funp frameValue; + public String vn; + public Funp expr; + public Fct fct; + + public static FunpLambdaCapSingle of(FunpVariable fpIn, FunpVariable frameVar, Funp frameValue, String vn, Funp expr, Fct fct) { + var f = new FunpLambdaCapSingle(); + f.fpIn = fpIn; + f.frameVar = frameVar; + f.frameValue = frameValue; + f.vn = vn; + f.expr = expr; + f.fct = fct; + return f; + } + + public R apply(FixieFun6 fun) { + return fun.apply(fpIn, frameVar, frameValue, vn, expr, fct); + } + } + public static class FunpLambdaCapture implements Funp, P2.End { public FunpVariable fpIn; public FunpVariable frameVar; - public Funp struct; + public Funp frameValue; public String vn; public Funp expr; public Fct fct; - public static FunpLambdaCapture of(FunpVariable fpIn, FunpVariable frameVar, Funp struct, String vn, Funp expr, Fct fct) { + public static FunpLambdaCapture of(FunpVariable fpIn, FunpVariable frameVar, Funp frameValue, String vn, Funp expr, Fct fct) { var f = new FunpLambdaCapture(); f.fpIn = fpIn; f.frameVar = frameVar; - f.struct = struct; + f.frameValue = frameValue; f.vn = vn; f.expr = expr; f.fct = fct; @@ -310,7 +334,7 @@ public static FunpLambdaCapture of(FunpVariable fpIn, FunpVariable frameVar, Fun } public R apply(FixieFun6 fun) { - return fun.apply(fpIn, frameVar, struct, vn, expr, fct); + return fun.apply(fpIn, frameVar, frameValue, vn, expr, fct); } } diff --git a/src/main/java/suite/funp/p2/P21CaptureLambda.java b/src/main/java/suite/funp/p2/P21CaptureLambda.java index 038ae9638..5632989cb 100644 --- a/src/main/java/suite/funp/p2/P21CaptureLambda.java +++ b/src/main/java/suite/funp/p2/P21CaptureLambda.java @@ -27,6 +27,8 @@ import suite.funp.P0.FunpReference; import suite.funp.P0.FunpStruct; import suite.funp.P0.FunpVariable; +import suite.funp.P2; +import suite.funp.P2.FunpLambdaCapSingle; import suite.funp.P2.FunpLambdaCapture; import suite.funp.P2.FunpTypeAssign; import suite.inspect.Inspect; @@ -120,6 +122,12 @@ else if (lambda.fct == Fct.MANUAL || lambda.fct == Fct.ONCE__) { // access from if (li.captureSet.add(vn)) li.captures.add(Pair.of(vn, access(lambdaByFunp.get(lambda)))); return FunpField.of(FunpReference.of(li.cap), vn); + } + else if (lambda.fct == Fct.SINGLE) { // access from frame variable + var li = infoByLambda.get(lambda); + if (li.captureSet.add(vn)) + li.captures.add(Pair.of(vn, access(lambdaByFunp.get(lambda)))); + return li.cap; } else if (lambda.fct == Fct.STACKF) // accessible through stack frame return access(lambdaByFunp.get(lambda)); else @@ -178,6 +186,11 @@ private Funp c_(Funp n) { yield Funp_.fail(f, "scopeless lambda <" + vn + "> capturing variables " + li.captureSet); } case ONCE__ -> capturef.apply(false); + case SINGLE -> { + var capture = Read.from(captures).uniqueResult(); + var pcap = FunpVariable.of(capture.k); + yield FunpLambdaCapSingle.of(pcap, li.cap, capture.v, vn, c(expr), fct); + } case STACKF -> null; default -> fail(); }; diff --git a/src/main/java/suite/funp/p2/P22InferType.java b/src/main/java/suite/funp/p2/P22InferType.java index dfde9dcab..109f50490 100644 --- a/src/main/java/suite/funp/p2/P22InferType.java +++ b/src/main/java/suite/funp/p2/P22InferType.java @@ -333,9 +333,9 @@ else if (coerce == Coerce.POINTER) .fold(PerMap.empty(), (e, p) -> e.put(p.k, p.v)); var env2 = env1.replace(vn, Pair.of(Fdt.L_MONO, tv)); return typeLambdaOf(tv, new Infer(env2, checks0, checks1, me).infer(expr)); - })).applyIf(FunpLambdaCapture.class, f -> f.apply((fpIn, frameVar, frame, vn, expr, fct) -> { + })).applyIf(FunpLambdaCapture.class, f -> f.apply((fpIn, frameVar, frameValue, vn, expr, fct) -> { var tv = new Reference(); - var tf = infer(frame); + var tf = infer(frameValue); var tr = typeRefOf(tf); unify(f, tr, infer(fpIn)); var env1 = PerMap // @@ -674,8 +674,8 @@ else if (Fdt.isSubs(fdt)) { var expr2 = isPassByReg ? FunpAllocReg.of(lt.is, FunpDontCare.of(), expr1, opArg) : expr1; var expr3 = f.name != null ? FunpRemark.of(f.name, expr2) : expr2; return eraseRoutine(lt, frame, expr3); - })).applyIf(FunpLambdaCapture.class, f -> f.apply((fp0, frameVar, frame, vn, expr, fct) -> { - var size = getTypeSize(typeOf(frame)); + })).applyIf(FunpLambdaCapture.class, f -> f.apply((fp0, frameVar, frameValue, vn, expr, fct) -> { + var size = getTypeSize(typeOf(frameValue)); var b = ps + ps; // return address and EBP var lt = new LambdaType(f); var isPassByReg = lt.isPassByReg; @@ -698,6 +698,8 @@ else if (fct == Fct.ONCE__) // the capture would free itself upon first call, therefore should not be called // for the second time expr3 = FunpHeapDealloc.of(false, size, FunpMemory.of(FunpFramePointer.of(), 0, ps), expr2); + else if (fct == Fct.SINGLE) + expr3 = expr2; else return fail(); diff --git a/src/main/resources/suite/funp/iter.fp b/src/main/resources/suite/funp/iter.fp index 866a2b7a9..b30932086 100644 --- a/src/main/resources/suite/funp/iter.fp +++ b/src/main/resources/suite/funp/iter.fp @@ -50,7 +50,8 @@ define-global list-iter! list := do type list = type-list ~ let { elems ~ size ~ } := list ~ let i := new! 0 ~ - let has-next := () => capture (i* < size) ~ + let cap := new! { elems, i, size, } ~ + let has.next := () => capture (i* < size) ~ let next! := () => capture do let i_ := i* ~ assign! i* := i_ + 1 ~ @@ -60,6 +61,7 @@ define-global list-iter! list := do free! := () => capture1 do uncapture has-next ~ uncapture next! ~ + delete! cap ~ delete! i ~ () ~