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