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