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 java.base/java.lang.reflect.code.parser
 27  * @run testng TestParse
 28  */
 29 
 30 import org.testng.Assert;
 31 import org.testng.annotations.Test;
 32 
 33 import java.lang.reflect.code.Block;
 34 import java.lang.reflect.code.op.CoreOp;
 35 import java.lang.reflect.code.Op;
 36 import java.lang.reflect.code.type.MethodRef;
 37 import java.lang.reflect.code.parser.OpParser;
 38 import java.util.List;
 39 import java.util.function.IntUnaryOperator;
 40 
 41 import static java.lang.reflect.code.op.CoreOp._return;
 42 import static java.lang.reflect.code.op.CoreOp.add;
 43 import static java.lang.reflect.code.op.CoreOp.constant;
 44 import static java.lang.reflect.code.op.CoreOp.func;
 45 import static java.lang.reflect.code.op.CoreOp.lambda;
 46 import static java.lang.reflect.code.type.FunctionType.functionType;
 47 import static java.lang.reflect.code.type.JavaType.INT;
 48 import static java.lang.reflect.code.type.JavaType.type;
 49 
 50 public class TestParse {
 51 
 52     static final MethodRef INT_UNARY_OPERATOR_METHOD = MethodRef.method(
 53             IntUnaryOperator.class, "applyAsInt",
 54             int.class, int.class);
 55 
 56     @Test
 57     public void testParseLambdaOp() {
 58         // functional type = (int)int
 59         CoreOp.FuncOp f = func("f", functionType(INT, INT))
 60                 .body(block -> {
 61                     Block.Parameter i = block.parameters().get(0);
 62 
 63                     // functional type = (int)int
 64                     // op type = ()IntUnaryOperator
 65                     //   captures i
 66                     CoreOp.LambdaOp lambda = lambda(block.parentBody(),
 67                             functionType(INT, INT), type(IntUnaryOperator.class))
 68                             .body(lbody -> {
 69                                 Block.Builder lblock = lbody.entryBlock();
 70                                 Block.Parameter li = lblock.parameters().get(0);
 71 
 72                                 lblock.op(_return(
 73                                         lblock.op(add(i, li))));
 74                             });
 75 
 76                     Op.Result fi = block.op(lambda);
 77                     Op.Result fortyTwo = block.op(constant(INT, 42));
 78                     Op.Result or = block.op(CoreOp.invoke(INT_UNARY_OPERATOR_METHOD, fi, fortyTwo));
 79                     block.op(_return(or));
 80                 });
 81 
 82         List<Op> ops = OpParser.fromString(CoreOp.FACTORY, f.toText());
 83         assertTextEquals(f, ops.get(0));
 84     }
 85 
 86 
 87     static final String NAMED_BODY = """
 88             func @"test" ^body1(%0 : int, %1 : int)int -> {
 89                 %2 : int = constant @"5";
 90                 %3 : int = constant @"2";
 91                 branch ^b1(%2, %3);
 92 
 93               ^b1(%0 : int, %1 : int):
 94                 return %0;
 95             };
 96             """;
 97     @Test
 98     void testParseNamedBody() {
 99         Op opE = OpParser.fromString(CoreOp.FACTORY, NAMED_BODY).get(0);
100         Op opA = OpParser.fromString(CoreOp.FACTORY, opE.toText()).get(0);
101         assertTextEquals(opA, opE);
102     }
103 
104 
105     static final String ESCAPED_STRING = """
106             func @"test" ()String -> {
107                 %0 : java.lang.String = constant @"\\b \\f \\n \\r \\t \\' \\" \\\\";
108                 return %0;
109             };
110             """;
111     @Test
112     void testEscapedString() {
113         Op opE = OpParser.fromString(CoreOp.FACTORY, ESCAPED_STRING).get(0);
114         Op opA = OpParser.fromString(CoreOp.FACTORY, opE.toText()).get(0);
115         assertTextEquals(opA, opE);
116 
117         CoreOp.ConstantOp cop = (CoreOp.ConstantOp) opE.bodies().get(0).entryBlock().firstOp();
118         String v = (String) cop.value();
119         Assert.assertEquals(v, "\b \f \n \r \t \' \" \\");
120     }
121 
122     static void assertTextEquals(Op a, Op b) {
123         Assert.assertEquals(a.toText(), b.toText());
124     }
125 }