1 package jdk.incubator.code.extern;
  2 
  3 import jdk.incubator.code.*;
  4 
  5 import java.util.List;
  6 import java.util.Map;
  7 import java.util.function.Function;
  8 
  9 /**
 10  * An operation's externalized state (a record) that can be utilized to construct an instance
 11  * of an {@link Op} associated with that state, such as the operation's name.
 12  *
 13  * @param name            the operation name
 14  * @param location        the source location associated with the operation, may be null
 15  * @param operands        the list of operands
 16  * @param successors      the list of successors
 17  * @param resultType      the operation result type
 18  * @param attributes      the operation's specific state as a map of attributes
 19  * @param bodyDefinitions the list of body builders for building the operation's bodies
 20  * @apiNote Deserializers of operations may utilize this record to construct operations,
 21  * thereby separating the specifics of deserializing from construction.
 22  */
 23 public record ExternalizedOp(String name,
 24                              Op.Location location,
 25                              List<Value> operands,
 26                              List<Block.Reference> successors,
 27                              TypeElement resultType,
 28                              Map<String, Object> attributes,
 29                              List<Body.Builder> bodyDefinitions) {
 30 
 31     /**
 32      * The attribute value that represents the external null value.
 33      */
 34     public static final Object NULL_ATTRIBUTE_VALUE = new Object();
 35 
 36     /**
 37      * Constructs a new externalized operation
 38      * @param name            the operation name
 39      * @param location        the source location associated with the operation, may be null
 40      * @param operands        the list of operands
 41      * @param successors      the list of successors
 42      * @param resultType      the operation result type
 43      * @param attributes      the operation's specific state as a map of attributes
 44      * @param bodyDefinitions the list of body builders for building the operation's bodies
 45      */
 46     public ExternalizedOp {
 47         attributes = Map.copyOf(attributes);
 48     }
 49 
 50     /**
 51      * Gets an attribute value from the attributes map, converts the value by applying it
 52      * to mapping function, and returns the result.
 53      *
 54      * <p>If the attribute is a default attribute then this method first attempts to
 55      * get the attribute whose name is the empty string, otherwise if there is no such
 56      * attribute present or the attribute is not a default attribute then this method
 57      * attempts to get the attribute with the given name.
 58      *
 59      * <p>On successfully obtaining the attribute its value is converted by applying the value
 60      * to the mapping function. A {@code null} value is represented by the value
 61      * {@link ExternalizedOp#NULL_ATTRIBUTE_VALUE}.
 62      *
 63      * <p>If no attribute is present the {@code null} value is applied to the mapping function.
 64      *
 65      * @param name      the attribute name.
 66      * @param isDefault true if the attribute is a default attribute
 67      * @param mapper    the function used to convert the attribute value
 68      * @param <T>       the converted attribute value type
 69      * @return the converted attribute value
 70      */
 71     public <T> T extractAttributeValue(String name, boolean isDefault, Function<Object, T> mapper) {
 72         Object value = null;
 73         if (isDefault && attributes.containsKey("")) {
 74             value = attributes.get("");
 75             assert value != null;
 76         }
 77 
 78         if (value == null && attributes.containsKey(name)) {
 79             value = attributes.get(name);
 80             assert value != null;
 81         }
 82 
 83         return mapper.apply(value);
 84     }
 85 
 86     /**
 87      * Externalizes an operation's content.
 88      * <p>
 89      * If the operation is an instanceof {@code ExternalizableOp} then the operation's
 90      * specific content is externalized to an attribute map, otherwise the attribute map
 91      * is empty.
 92      *
 93      * @param cc the code context
 94      * @param op the operation
 95      * @return the operation's content.
 96      */
 97     public static ExternalizedOp externalizeOp(CodeContext cc, Op op) {
 98         return new ExternalizedOp(
 99                 op.externalizeOpName(),
100                 op.location(),
101                 cc.getValues(op.operands()),
102                 op.successors().stream().map(cc::getSuccessorOrCreate).toList(),
103                 op.resultType(),
104                 op.externalize(),
105                 op.bodies().stream().map(b -> b.copy(cc)).toList()
106         );
107     }
108 }