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.Function; 30 31 import static java.util.stream.Collectors.toList; 32 33 /** 34 * A context utilized when transforming code models. 35 * <p> 36 * The context holds a mapping of input values to output values, input blocks to output block builders, 37 * and input block references to output block references. 38 * These mappings are built as an input model is transformed to produce an output model. Mappings are built implicitly 39 * when an operation is transformed by copying, and can be explicitly added by the transformation when removing or 40 * adding new operations. 41 * <p> 42 * Unless otherwise specified the passing of a {@code null} argument to the methods of this interface results in a 43 * {@code NullPointerException}. 44 */ 45 public sealed interface CopyContext permits CopyContextImpl { 46 47 // @@@ ? 48 // CopyContext parent(); 49 50 51 // Value mappings 52 53 /** 54 * {@return the output value mapped to the input value} 55 * <p> 56 * If this context is not isolated and there is no value mapping in this context then this method will return 57 * the result of calling {@code getValue} on the parent context, if present. Otherwise if this context is isolated 58 * or there is no parent context, then there is no mapping. 59 * 60 * @param input the input value 61 * @throws IllegalArgumentException if there is no mapping 62 */ 63 Value getValue(Value input); 64 65 /** 66 * {@return the output value mapped to the input value or a default value if no mapping} 67 * 68 * @param input the input value 69 * @param defaultValue the default value to return if no mapping 70 */ 71 Value getValueOrDefault(Value input, Value defaultValue); 72 73 /** 74 * Maps an input value to an output value. 75 * <p> 76 * Uses of the input value will be mapped to the output value when transforming. 77 * 78 * @param input the input value 79 * @param output the output value 80 * @throws IllegalArgumentException if the output value is already bound 81 */ 82 void mapValue(Value input, Value output); 83 84 /** 85 * Maps an input value to an output value, if no such mapping exists. 86 * <p> 87 * Uses of the input value will be mapped to the output value when transforming. 88 * 89 * @param input the input value 90 * @param output the output value 91 * @return the previous mapped value, or null of there was no mapping. 92 * @throws IllegalArgumentException if the output value is already bound 93 */ 94 // @@@ Is this needed? 95 Value mapValueIfAbsent(Value input, Value output); 96 97 /** 98 * Returns a list of mapped output values by obtaining, in order, the output value for each element in the list 99 * of input values. 100 * 101 * @param inputs the list of input values 102 * @return a modifiable list of output values 103 * @throws IllegalArgumentException if an input value has no mapping 104 */ 105 // @@@ If getValue is modified to return null then this method should fail on null 106 default List<Value> getValues(List<? extends Value> inputs) { 107 return inputs.stream().map(this::getValue).collect(toList()); 108 } 109 110 /** 111 * Maps the list of input values, in order, to the corresponding list of output values, up to the number of 112 * elements that is the minimum of the size of both lists. 113 * <p> 114 * Uses of an input value will be mapped to the corresponding output value when transforming. 115 * 116 * @param inputs the input values 117 * @param outputs the output values. 118 * @throws IllegalArgumentException if an output value is already bound 119 */ 120 default void mapValues(List<? extends Value> inputs, List<? extends Value> outputs) { 121 // @@@ sizes should be the same? 122 for (int i = 0; i < Math.min(inputs.size(), outputs.size()); i++) { 123 mapValue(inputs.get(i), outputs.get(i)); 124 } 125 } 126 127 128 // Block mappings 129 130 /** 131 * {@return the output block builder mapped to the input block, otherwise null if no mapping} 132 * 133 * @param input the input block 134 */ 135 Block.Builder getBlock(Block input); 136 137 /** 138 * Maps an input block to an output block builder. 139 * <p> 140 * Uses of the input block will be mapped to the output block builder when transforming. 141 * 142 * @param input the input block 143 * @param output the output block builder 144 * @throws IllegalArgumentException if the output block is already bound 145 */ 146 void mapBlock(Block input, Block.Builder output); 147 148 149 // Successor mappings 150 151 /** 152 * {@return the output block reference mapped to the input block reference, 153 * otherwise null if no mapping} 154 * 155 * @param input the input reference 156 */ 157 Block.Reference getSuccessor(Block.Reference input); 158 159 /** 160 * Maps an input block reference to an output block reference. 161 * <p> 162 * Uses of the input block reference will be mapped to the output block reference when transforming. 163 * 164 * @param input the input block reference 165 * @param output the output block reference 166 * @throws IllegalArgumentException if the output block builder associated with the block reference or any of its 167 * argument values are already bound 168 */ 169 void mapSuccessor(Block.Reference input, Block.Reference output); 170 171 /** 172 * Returns a mapped output block reference, if present, otherwise creates a new, unmapped, reference from the input 173 * block reference. 174 * <p> 175 * A new, unmapped reference, is created by obtaining the mapped output block builder from the input reference's 176 * target block, and creating a successor from the output block builder with arguments that is the result of 177 * obtaining the mapped values from the input reference's arguments. 178 * 179 * @param input the input block reference 180 * @return the output block reference, if present, otherwise a created block reference 181 * @throws IllegalArgumentException if a new reference is to be created and there is no mapped output block builder 182 */ 183 default Block.Reference getSuccessorOrCreate(Block.Reference input) { 184 Block.Reference successor = getSuccessor(input); 185 if (successor != null) { 186 return successor; 187 } 188 189 // Create successor 190 Block.Builder outputBlock = getBlock(input.targetBlock()); 191 if (outputBlock == null) { 192 throw new IllegalArgumentException("No mapping for input reference target block" + input.targetBlock()); 193 } 194 return outputBlock.successor(getValues(input.arguments())); 195 } 196 197 198 // Properties mappings 199 200 /** 201 * {@return an object associated with a property key} 202 * 203 * @param key the property key 204 */ 205 Object getProperty(Object key); 206 207 /** 208 * Associates an object with a property key. 209 * 210 * @param key the property key 211 * @param value the associated object 212 * @return the current associated object, or null if not associated 213 */ 214 Object putProperty(Object key, Object value); 215 216 /** 217 * If the property key is not already associated with an object, attempts to compute the object using the 218 * mapping function and associates it unless {@code null}. 219 * 220 * @param key the property key 221 * @param mappingFunction the mapping function 222 * @return the current (existing or computed) object associated with the property key, 223 * or null if the computed object is null 224 */ 225 Object computePropertyIfAbsent(Object key, Function<Object, Object> mappingFunction); 226 227 228 // Factories 229 230 /** 231 * {@return a new isolated context initialized with no mappings and no parent } 232 */ 233 static CopyContext create() { 234 return new CopyContextImpl(null); 235 } 236 237 /** 238 * {@return a new non-isolated context initialized with no mappings and a parent } 239 * The returned context will query value and property mappings in the parent context 240 * if a query of its value and property mappings yields no result. 241 */ 242 static CopyContext create(CopyContext parent) { 243 return new CopyContextImpl((CopyContextImpl) parent); 244 } 245 }