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