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 TestClosureOps 28 */ 29 30 import jdk.incubator.code.dialect.java.JavaOp; 31 import org.testng.Assert; 32 import org.testng.annotations.Test; 33 34 import jdk.incubator.code.Block; 35 import jdk.incubator.code.dialect.core.CoreOp; 36 import jdk.incubator.code.Op; 37 import jdk.incubator.code.Quoted; 38 import jdk.incubator.code.dialect.java.MethodRef; 39 import jdk.incubator.code.interpreter.Interpreter; 40 41 import java.lang.invoke.MethodHandles; 42 import jdk.incubator.code.dialect.java.JavaType; 43 import java.util.ArrayList; 44 import java.util.List; 45 46 import static jdk.incubator.code.dialect.core.CoreOp.return_; 47 import static jdk.incubator.code.dialect.java.JavaOp.add; 48 import static jdk.incubator.code.dialect.core.CoreOp.closure; 49 import static jdk.incubator.code.dialect.core.CoreOp.closureCall; 50 import static jdk.incubator.code.dialect.core.CoreOp.constant; 51 import static jdk.incubator.code.dialect.core.CoreOp.func; 52 import static jdk.incubator.code.dialect.core.CoreOp.quoted; 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 public class TestClosureOps { 58 59 static class Builder { 60 static final MethodRef ACCEPT_METHOD = MethodRef.method(type(TestClosureOps.Builder.class), "accept", 61 INT, CoreOp.QuotedOp.QUOTED_TYPE); 62 63 static int accept(Quoted c) { 64 Assert.assertEquals(1, c.capturedValues().size()); 65 Assert.assertEquals(1, c.capturedValues().values().iterator().next()); 66 67 List<Object> arguments = new ArrayList<>(); 68 arguments.add(42); 69 arguments.addAll(c.capturedValues().values()); 70 int r = (int) Interpreter.invoke(MethodHandles.lookup(), (Op & Op.Invokable) c.op(), 71 arguments); 72 return r; 73 } 74 } 75 76 @Test 77 public void testQuotedWithCapture() { 78 // functional type = (int)int 79 CoreOp.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 descriptor = ()Quoted<ClosureOp> 85 CoreOp.QuotedOp qop = quoted(block.parentBody(), qblock -> { 86 return closure(qblock.parentBody(), functionType(INT, INT)) 87 .body(cblock -> { 88 Block.Parameter ci = cblock.parameters().get(0); 89 90 cblock.op(return_( 91 // capture i from function's body 92 cblock.op(add(i, ci)) 93 )); 94 }); 95 }); 96 Op.Result cquoted = block.op(qop); 97 98 Op.Result or = block.op(JavaOp.invoke(TestClosureOps.Builder.ACCEPT_METHOD, cquoted)); 99 block.op(return_(or)); 100 }); 101 102 System.out.println(f.toText()); 103 104 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1); 105 Assert.assertEquals(ir, 43); 106 } 107 108 @Test 109 public void testWithCapture() { 110 // functional type = (int)int 111 CoreOp.FuncOp f = func("f", functionType(INT, INT)) 112 .body(block -> { 113 Block.Parameter i = block.parameters().get(0); 114 115 // functional type = (int)int 116 // captures i 117 CoreOp.ClosureOp closure = CoreOp.closure(block.parentBody(), 118 functionType(INT, INT)) 119 .body(cblock -> { 120 Block.Parameter ci = cblock.parameters().get(0); 121 122 cblock.op(return_( 123 cblock.op(add(i, ci)))); 124 }); 125 Op.Result c = block.op(closure); 126 127 Op.Result fortyTwo = block.op(constant(INT, 42)); 128 Op.Result or = block.op(closureCall(c, fortyTwo)); 129 block.op(return_(or)); 130 }); 131 132 System.out.println(f.toText()); 133 134 int ir = (int) Interpreter.invoke(MethodHandles.lookup(), f, 1); 135 Assert.assertEquals(ir, 43); 136 } 137 138 @Test 139 public void testQuotableModel() { 140 Quoted quoted = () -> {}; 141 Op qop = quoted.op(); 142 Op top = qop.ancestorOp().ancestorOp(); 143 Assert.assertTrue(top instanceof CoreOp.FuncOp); 144 145 CoreOp.FuncOp fop = (CoreOp.FuncOp) top; 146 Assert.assertEquals(JavaType.type(Quoted.class), fop.invokableType().returnType()); 147 } 148 }