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