1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /*
25 * @test
26 * @modules jdk.incubator.code
27 * @run junit TestClosureOps
28 */
29
30 import jdk.incubator.code.Block;
31 import jdk.incubator.code.Op;
32 import jdk.incubator.code.Quoted;
33 import jdk.incubator.code.dialect.core.CoreOp;
34 import jdk.incubator.code.dialect.java.JavaOp;
35 import jdk.incubator.code.dialect.java.JavaType;
36 import jdk.incubator.code.dialect.java.MethodRef;
37 import jdk.incubator.code.interpreter.Interpreter;
38 import org.junit.jupiter.api.Assertions;
39 import org.junit.jupiter.api.Test;
40
41 import java.lang.invoke.MethodHandles;
42 import java.util.ArrayList;
43 import java.util.List;
44
45 import static jdk.incubator.code.dialect.core.CoreOp.*;
46 import static jdk.incubator.code.dialect.core.CoreType.functionType;
47 import static jdk.incubator.code.dialect.java.JavaOp.add;
48 import static jdk.incubator.code.dialect.java.JavaType.INT;
49 import static jdk.incubator.code.dialect.java.JavaType.type;
50
51 public class TestClosureOps {
52
53 static class Builder {
54 static final MethodRef ACCEPT_METHOD = MethodRef.method(type(TestClosureOps.Builder.class), "accept",
55 INT, CoreOp.QuotedOp.QUOTED_TYPE);
56
57 static int accept(Quoted c) {
58 Assertions.assertEquals(c.capturedValues().size(), 1);
59 Assertions.assertEquals(c.capturedValues().values().iterator().next(), 1);
60
61 List<Object> arguments = new ArrayList<>();
62 arguments.add(42);
63 arguments.addAll(c.capturedValues().values());
64 int r = (int) Interpreter.invoke(MethodHandles.lookup(), (Op & Op.Invokable) c.op(),
65 arguments);
66 return r;
67 }
68 }
69
70 @Test
71 public void testQuotedWithCapture() {
72 // functional type = (int)int
73 CoreOp.FuncOp f = func("f", functionType(INT, INT))
74 .body(block -> {
75 Block.Parameter i = block.parameters().get(0);
76
77 // functional type = (int)int
78 // op descriptor = ()Quoted<ClosureOp>
79 CoreOp.QuotedOp qop = quoted(block.parentBody(), qblock -> {
80 return closure(qblock.parentBody(), functionType(INT, INT))
81 .body(cblock -> {
82 Block.Parameter ci = cblock.parameters().get(0);
83
84 cblock.op(return_(
85 // capture i from function's body
86 cblock.op(add(i, ci))
87 ));
88 });
89 });
90 Op.Result cquoted = block.op(qop);
91
92 Op.Result or = block.op(JavaOp.invoke(TestClosureOps.Builder.ACCEPT_METHOD, cquoted));
93 block.op(return_(or));
94 });
95
96 System.out.println(f.toText());
97
98 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1);
99 Assertions.assertEquals(43, ir);
100 }
101
102 @Test
103 public void testWithCapture() {
104 // functional type = (int)int
105 CoreOp.FuncOp f = func("f", functionType(INT, INT))
106 .body(block -> {
107 Block.Parameter i = block.parameters().get(0);
108
109 // functional type = (int)int
110 // captures i
111 CoreOp.ClosureOp closure = CoreOp.closure(block.parentBody(),
112 functionType(INT, INT))
113 .body(cblock -> {
114 Block.Parameter ci = cblock.parameters().get(0);
115
116 cblock.op(return_(
117 cblock.op(add(i, ci))));
118 });
119 Op.Result c = block.op(closure);
120
121 Op.Result fortyTwo = block.op(constant(INT, 42));
122 Op.Result or = block.op(closureCall(c, fortyTwo));
123 block.op(return_(or));
124 });
125
126 System.out.println(f.toText());
127
128 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1);
129 Assertions.assertEquals(43, ir);
130 }
131
132 @Test
133 public void testQuotableModel() {
134 Quoted quoted = () -> {};
135 Op qop = quoted.op();
136 Op top = qop.ancestorOp().ancestorOp();
137 Assertions.assertTrue(top instanceof CoreOp.FuncOp);
138
139 CoreOp.FuncOp fop = (CoreOp.FuncOp) top;
140 Assertions.assertEquals(fop.invokableType().returnType(), JavaType.type(Quoted.class));
141 }
142 }