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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.incubator.code; 27 28 import java.util.List; 29 import java.util.function.BiFunction; 30 import java.util.function.Predicate; 31 import java.util.stream.Stream; 32 33 /** 34 * A code element, one of {@link Body body}, {@link Block block}, or {@link Op operation}. 35 * <p> 36 * A code element may have child code elements, and so on, to form a tree. A (root) code element and all its descendants 37 * can be traversed. 38 * 39 * @param <E> the code element type 40 * @param <C> the child code element type. 41 * @sealedGraph 42 */ 43 // @@@ E may not be needed 44 public sealed interface CodeElement< 45 E extends CodeElement<E, C>, 46 C extends CodeElement<C, ?>> 47 extends CodeItem 48 permits Body, Block, Op { 49 50 /** 51 * {@return a stream of code elements sorted topologically in pre-order traversal.} 52 */ 53 // Code copied into the compiler cannot depend on new gatherer API 54 default Stream<CodeElement<?, ?>> elements() { 55 return Stream.of(Void.class).gather(() -> (_, _, downstream) -> traversePreOrder(downstream::push)); 56 } 57 58 // private boolean traversePreOrder(Gatherer.Downstream<? super CodeElement<?, ?>> v) { 59 private boolean traversePreOrder(Predicate<? super CodeElement<?, ?>> v) { 60 if (!v.test(this)) { 61 return false; 62 } 63 for (C c : children()) { 64 if (!((CodeElement<?, ?>) c).traversePreOrder(v)) { 65 return false; 66 } 67 } 68 return true; 69 } 70 71 /** 72 * Traverses this code element and any descendant code elements. 73 * <p> 74 * Traversal is performed in pre-order, reporting each code element to the visitor. 75 * 76 * @param t the traversing accumulator 77 * @param v the code element visitor 78 * @param <T> accumulator type 79 * @return the traversing accumulator 80 */ 81 default <T> T traverse(T t, BiFunction<T, CodeElement<?, ?>, T> v) { 82 t = v.apply(t, this); 83 for (C r : children()) { 84 t = r.traverse(t, v); 85 } 86 87 return t; 88 } 89 90 /** 91 * Creates a visiting function for bodies. 92 * 93 * @param v the body visitor 94 * @param <T> accumulator type 95 * @return the visiting function for bodies 96 */ 97 static <T> BiFunction<T, CodeElement<?, ?>, T> bodyVisitor(BiFunction<T, Body, T> v) { 98 return (t, e) -> e instanceof Body f 99 ? v.apply(t, f) 100 : t; 101 } 102 103 /** 104 * Creates a visiting function for blocks. 105 * 106 * @param v the block visitor 107 * @param <T> accumulator type 108 * @return the visiting function for blocks 109 */ 110 static <T> BiFunction<T, CodeElement<?, ?>, T> blockVisitor(BiFunction<T, Block, T> v) { 111 return (t, e) -> e instanceof Block f 112 ? v.apply(t, f) 113 : t; 114 } 115 116 /** 117 * Creates a visiting function for operations. 118 * 119 * @param v the operation visitor 120 * @param <T> accumulator type 121 * @return the visiting function for operations 122 */ 123 static <T> BiFunction<T, CodeElement<?, ?>, T> opVisitor(BiFunction<T, Op, T> v) { 124 return (t, e) -> e instanceof Op f 125 ? v.apply(t, f) 126 : t; 127 } 128 129 /** 130 * Returns the parent code element. 131 * <p> 132 * If this element is an instance of {@code Op} then the parent may be {@code null} 133 * if operation is not assigned to a block. 134 * 135 * @return the parent code element 136 */ 137 CodeElement<?, E> parent(); 138 139 /** 140 * Returns the child code elements, as an unmodifiable list. 141 * 142 * @return the child code elements 143 */ 144 List<C> children(); 145 }