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 TestLambdaOps
28 */
29
30 import jdk.incubator.code.*;
31 import jdk.incubator.code.Reflect;
32 import jdk.incubator.code.dialect.core.CoreOp;
33 import jdk.incubator.code.dialect.java.JavaOp;
34 import jdk.incubator.code.dialect.java.JavaOp.LambdaOp;
35 import jdk.incubator.code.dialect.java.MethodRef;
36 import jdk.incubator.code.interpreter.Interpreter;
37 import org.junit.jupiter.api.Assertions;
38 import org.junit.jupiter.api.Test;
39
40 import java.lang.invoke.MethodHandles;
41 import java.lang.reflect.Method;
42 import java.util.ArrayList;
43 import java.util.List;
44 import java.util.Optional;
45 import java.util.function.BiFunction;
46 import java.util.function.Function;
47 import java.util.function.IntSupplier;
48 import java.util.function.IntUnaryOperator;
49 import java.util.stream.Stream;
50
51 import static jdk.incubator.code.dialect.core.CoreOp.*;
52 import static jdk.incubator.code.dialect.core.CoreType.functionType;
53 import static jdk.incubator.code.dialect.java.JavaType.INT;
54 import static jdk.incubator.code.dialect.java.JavaType.type;
55
56 public class TestLambdaOps {
57 static class Builder {
58 static final MethodRef ACCEPT_METHOD = MethodRef.method(type(Builder.class), "accept",
59 INT, CoreOp.QuotedOp.QUOTED_TYPE);
60
61 static int accept(Quoted l) {
62 Assertions.assertEquals(l.capturedValues().size(), 1);
63 Assertions.assertEquals(l.capturedValues().values().iterator().next(), 1);
64
65 List<Object> arguments = new ArrayList<>();
66 arguments.add(42);
67 arguments.addAll(l.capturedValues().values());
68 int r = (int) Interpreter.invoke(MethodHandles.lookup(), (Op & Op.Invokable) l.op(),
69 arguments);
70 return r;
71 }
72 }
73
74 @Test
75 public void testQuotedWithCapture() {
76 // functional type = (int)int
77 FuncOp f = func("f", functionType(INT, INT))
78 .body(block -> {
79 Block.Parameter i = block.parameters().get(0);
80
81 // functional type = (int)int
82 // op type = ()Quoted<LambdaOp>
83 QuotedOp qop = quoted(block.parentBody(), qblock -> {
84 return JavaOp.lambda(qblock.parentBody(),
85 functionType(INT, INT), type(IntUnaryOperator.class))
86 .body(lblock -> {
87 Block.Parameter li = lblock.parameters().get(0);
88
89 lblock.op(return_(
90 // capture i from function's body
91 lblock.op(JavaOp.add(i, li))
92 ));
93 });
94 });
95 Op.Result lquoted = block.op(qop);
96
97 Op.Result or = block.op(JavaOp.invoke(Builder.ACCEPT_METHOD, lquoted));
98 block.op(return_(or));
99 });
100
101 System.out.println(f.toText());
102
103 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1);
104 Assertions.assertEquals(43, ir);
105 }
106
107 static final MethodRef INT_UNARY_OPERATOR_METHOD = MethodRef.method(
108 IntUnaryOperator.class, "applyAsInt",
109 int.class, int.class);
110
111 @Test
112 public void testWithCapture() {
113 // functional type = (int)int
114 FuncOp f = func("f", functionType(INT, INT))
115 .body(block -> {
116 Block.Parameter i = block.parameters().get(0);
117
118 // functional type = (int)int
119 // op type = ()IntUnaryOperator
120 // captures i
121 LambdaOp lambda = JavaOp.lambda(block.parentBody(),
122 functionType(INT, INT), type(IntUnaryOperator.class))
123 .body(lblock -> {
124 Block.Parameter li = lblock.parameters().get(0);
125
126 lblock.op(return_(
127 lblock.op(JavaOp.add(i, li))));
128 });
129 Op.Result fi = block.op(lambda);
130
131 Op.Result fortyTwo = block.op(constant(INT, 42));
132 Op.Result or = block.op(JavaOp.invoke(INT_UNARY_OPERATOR_METHOD, fi, fortyTwo));
133 block.op(return_(or));
134 });
135
136 System.out.println(f.toText());
137
138 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1);
139 Assertions.assertEquals(43, ir);
140 }
141
142 static int f(int i) {
143 IntUnaryOperator fi = li -> {
144 return i + li;
145 };
146
147 int fortyTwo = 42;
148 int or = fi.applyAsInt(fortyTwo);
149 return or;
150 }
151
152 @Test
153 public void testQuotableModel() {
154 Runnable quotable = (@Reflect Runnable) () -> {};
155 Op qop = Op.ofQuotable(quotable).get().op();
156 Op top = qop.ancestorOp().ancestorOp();
157 Assertions.assertTrue(top instanceof CoreOp.FuncOp);
158
159 CoreOp.FuncOp fop = (CoreOp.FuncOp) top;
160 Assertions.assertEquals(fop.invokableType().returnType(), type(Quoted.class));
161 }
162
163 @Reflect
164 static IntSupplier quote(int i) {
165 return () -> i;
166 }
167
168 @Test
169 public void testQuote() {
170 FuncOp g = getFuncOp("quote");
171 System.out.println(g.toText());
172
173 {
174 IntSupplier op = (IntSupplier) Interpreter.invoke(MethodHandles.lookup(), g, 42);
175 Assertions.assertEquals(42, op.getAsInt());
176
177 Quoted q = Op.ofQuotable(op).get();
178 System.out.println(q.op().toText());
179 Assertions.assertEquals(1, q.capturedValues().size());
180 Assertions.assertEquals(42, ((Var<?>)q.capturedValues().values().iterator().next()).value());
181
182 int r = (int) Interpreter.invoke(MethodHandles.lookup(), (LambdaOp) q.op(),
183 new ArrayList<>(q.capturedValues().sequencedValues()));
184 Assertions.assertEquals(42, r);
185
186 r = (int) Interpreter.invoke(MethodHandles.lookup(), (LambdaOp) q.op(),
187 List.of(CoreOp.Var.of(0)));
188 Assertions.assertEquals(0, r);
189 }
190
191 {
192 IntSupplier op = quote(42);
193 Assertions.assertEquals(42, op.getAsInt());
194
195 Quoted q = Op.ofQuotable(op).get();
196 System.out.println(q.op().toText());
197 System.out.print(q.capturedValues().values());
198 Assertions.assertEquals(1, q.capturedValues().size());
199 Assertions.assertEquals(42, ((Var<?>)q.capturedValues().values().iterator().next()).value());
200
201 int r = (int) Interpreter.invoke(MethodHandles.lookup(), (LambdaOp) q.op(),
202 new ArrayList<>(q.capturedValues().sequencedValues()));
203 Assertions.assertEquals(42, r);
204
205 r = (int) Interpreter.invoke(MethodHandles.lookup(), (LambdaOp) q.op(),
206 List.of(CoreOp.Var.of(0)));
207 Assertions.assertEquals(0, r);
208 }
209 }
210
211 static CoreOp.FuncOp getFuncOp(String name) {
212 Optional<Method> om = Stream.of(TestLambdaOps.class.getDeclaredMethods())
213 .filter(m -> m.getName().equals(name))
214 .findFirst();
215
216 Method m = om.get();
217 return Op.ofMethod(m).get();
218 }
219 }