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 }