mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
204 lines
7.5 KiB
Java
204 lines
7.5 KiB
Java
/*
|
|
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package java.lang.runtime;
|
|
|
|
import java.lang.invoke.MethodHandle;
|
|
import java.lang.invoke.MethodHandles;
|
|
import java.lang.invoke.MethodType;
|
|
import java.lang.invoke.StringConcatException;
|
|
import java.lang.invoke.StringConcatFactory;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* This class synthesizes {@link StringTemplate StringTemplates} based on
|
|
* fragments and bootstrap method type. Usage is primarily from
|
|
* {@link java.lang.runtime.TemplateRuntime}.
|
|
*
|
|
* @since 21
|
|
*
|
|
* Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES.
|
|
* Do not rely on its availability.
|
|
*/
|
|
final class StringTemplateImplFactory {
|
|
|
|
/**
|
|
* Private constructor.
|
|
*/
|
|
StringTemplateImplFactory() {
|
|
throw new AssertionError("private constructor");
|
|
}
|
|
|
|
/*
|
|
* {@link StringTemplateImpl} constructor MethodHandle.
|
|
*/
|
|
private static final MethodHandle CONSTRUCTOR;
|
|
|
|
|
|
/*
|
|
* Frequently used method types.
|
|
*/
|
|
private static final MethodType MT_STRING_STIMPL =
|
|
MethodType.methodType(String.class, StringTemplateImpl.class);
|
|
private static final MethodType MT_LIST_STIMPL =
|
|
MethodType.methodType(List.class, StringTemplateImpl.class);
|
|
|
|
/**
|
|
* List (for nullable) of MethodHandle;
|
|
*/
|
|
private static final MethodHandle TO_LIST;
|
|
|
|
static {
|
|
try {
|
|
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
|
|
|
MethodType mt = MethodType.methodType(void.class, int.class, int.class, List.class,
|
|
MethodHandle.class, MethodHandle.class);
|
|
CONSTRUCTOR = lookup.findConstructor(StringTemplateImpl.class, mt)
|
|
.asType(mt.changeReturnType(Carriers.CarrierObject.class));
|
|
|
|
mt = MethodType.methodType(List.class, Object[].class);
|
|
TO_LIST = lookup.findStatic(StringTemplateImplFactory.class, "toList", mt);
|
|
} catch(ReflectiveOperationException ex) {
|
|
throw new AssertionError("carrier static init fail", ex);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a new {@link StringTemplateImpl} constructor.
|
|
*
|
|
* @param fragments string template fragments
|
|
* @param type values types with StringTemplate return
|
|
*
|
|
* @return {@link MethodHandle} that can construct a {@link StringTemplateImpl} with arguments
|
|
* used as values.
|
|
*/
|
|
static MethodHandle createStringTemplateImplMH(List<String> fragments, MethodType type) {
|
|
Carriers.CarrierElements elements = Carriers.CarrierFactory.of(type);
|
|
MethodHandle[] components = elements
|
|
.components()
|
|
.stream()
|
|
.map(c -> c.asType(c.type().changeParameterType(0, StringTemplateImpl.class)))
|
|
.toArray(MethodHandle[]::new);
|
|
Class<?>[] ptypes = elements
|
|
.components()
|
|
.stream()
|
|
.map(c -> c.type().returnType())
|
|
.toArray(Class<?>[]::new);
|
|
int[] permute = new int[ptypes.length];
|
|
|
|
MethodHandle interpolateMH;
|
|
MethodType mt;
|
|
try {
|
|
interpolateMH = StringConcatFactory.makeConcatWithTemplate(fragments, List.of(ptypes));
|
|
} catch (StringConcatException ex) {
|
|
throw new RuntimeException("constructing internal string template", ex);
|
|
}
|
|
interpolateMH = MethodHandles.filterArguments(interpolateMH, 0, components);
|
|
interpolateMH = MethodHandles.permuteArguments(interpolateMH, MT_STRING_STIMPL, permute);
|
|
|
|
mt = MethodType.methodType(List.class, ptypes);
|
|
MethodHandle valuesMH = TO_LIST.asCollector(Object[].class, components.length).asType(mt);
|
|
valuesMH = MethodHandles.filterArguments(valuesMH, 0, components);
|
|
valuesMH = MethodHandles.permuteArguments(valuesMH, MT_LIST_STIMPL, permute);
|
|
|
|
MethodHandle constructor = MethodHandles.insertArguments(CONSTRUCTOR, 0,
|
|
elements.primitiveCount(), elements.objectCount(),
|
|
fragments, valuesMH, interpolateMH);
|
|
constructor = MethodHandles.foldArguments(elements.initializer(), 0, constructor);
|
|
|
|
mt = MethodType.methodType(StringTemplate.class, ptypes);
|
|
constructor = constructor.asType(mt);
|
|
|
|
return constructor;
|
|
}
|
|
|
|
/**
|
|
* Generic {@link StringTemplate}.
|
|
*
|
|
* @param fragments immutable list of string fragments from string template
|
|
* @param values immutable list of expression values
|
|
*/
|
|
private record SimpleStringTemplate(List<String> fragments, List<Object> values)
|
|
implements StringTemplate {
|
|
@Override
|
|
public String toString() {
|
|
return StringTemplate.toString(this);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a new StringTemplate composed from fragments and values.
|
|
*
|
|
* @param fragments array of string fragments
|
|
* @param values array of expression values
|
|
*
|
|
* @return StringTemplate composed from fragments and values
|
|
*/
|
|
static StringTemplate newTrustedStringTemplate(String[] fragments, Object[] values) {
|
|
return new SimpleStringTemplate(List.of(fragments), toList(values));
|
|
}
|
|
|
|
/**
|
|
* Returns a new StringTemplate composed from fragments and values.
|
|
*
|
|
* @param fragments list of string fragments
|
|
* @param values array of expression values
|
|
*
|
|
* @return StringTemplate composed from fragments and values
|
|
*/
|
|
static StringTemplate newTrustedStringTemplate(List<String> fragments, Object[] values) {
|
|
return new SimpleStringTemplate(List.copyOf(fragments), toList(values));
|
|
}
|
|
|
|
/**
|
|
* Returns a new StringTemplate composed from fragments and values.
|
|
*
|
|
* @param fragments list of string fragments
|
|
* @param values list of expression values
|
|
*
|
|
* @return StringTemplate composed from fragments and values
|
|
*/
|
|
|
|
static StringTemplate newStringTemplate(List<String> fragments, List<?> values) {
|
|
@SuppressWarnings("unchecked")
|
|
List<Object> copy = (List<Object>)values.stream().toList();
|
|
return new SimpleStringTemplate(List.copyOf(fragments), copy);
|
|
}
|
|
|
|
/**
|
|
* Collect nullable elements from an array into a unmodifiable list.
|
|
* Elements are guaranteed to be safe.
|
|
*
|
|
* @param elements elements to place in list
|
|
*
|
|
* @return unmodifiable list.
|
|
*/
|
|
private static List<Object> toList(Object[] elements) {
|
|
return Arrays.stream(elements).toList();
|
|
}
|
|
|
|
}
|