From 03e84178ebfd2ca48b89d65d8f3c291e0c622fb5 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Wed, 17 Apr 2024 14:10:28 +0000 Subject: [PATCH] 8329948: Remove string template feature Reviewed-by: jlahoda --- .../classes/java/lang/StringConcatHelper.java | 123 --- .../classes/java/lang/StringTemplate.java | 622 ------------ .../share/classes/java/lang/System.java | 29 +- .../java/lang/invoke/StringConcatFactory.java | 318 +----- .../java/lang/runtime/StringTemplateImpl.java | 134 --- .../runtime/StringTemplateImplFactory.java | 204 ---- .../java/lang/runtime/TemplateRuntime.java | 269 ----- .../java/lang/runtime/TemplateSupport.java | 152 --- .../share/classes/java/util/FormatItem.java | 540 ---------- .../classes/java/util/FormatProcessor.java | 299 ------ .../share/classes/java/util/Formatter.java | 1 - .../classes/java/util/FormatterBuilder.java | 489 --------- .../jdk/internal/access/JavaLangAccess.java | 37 +- .../internal/access/JavaTemplateAccess.java | 78 -- .../jdk/internal/access/SharedSecrets.java | 16 - .../jdk/internal/util/DecimalDigits.java | 77 +- .../classes/jdk/internal/util/Digits.java | 61 -- .../jdk/internal/util/FormatConcatItem.java | 58 -- .../classes/jdk/internal/util/HexDigits.java | 76 +- .../jdk/internal/util/OctalDigits.java | 77 +- .../sun/source/tree/StringTemplateTree.java | 59 -- .../classes/com/sun/source/tree/Tree.java | 9 - .../com/sun/source/tree/TreeVisitor.java | 12 - .../sun/source/util/SimpleTreeVisitor.java | 15 - .../com/sun/source/util/TreeScanner.java | 19 - .../com/sun/tools/javac/code/Preview.java | 1 - .../com/sun/tools/javac/code/Source.java | 1 - .../com/sun/tools/javac/code/Symtab.java | 14 +- .../com/sun/tools/javac/comp/Attr.java | 28 +- .../com/sun/tools/javac/comp/Check.java | 22 +- .../sun/tools/javac/comp/CompileStates.java | 9 +- .../com/sun/tools/javac/comp/Flow.java | 9 - .../sun/tools/javac/comp/TransLiterals.java | 348 ------- .../com/sun/tools/javac/comp/TransTypes.java | 10 +- .../com/sun/tools/javac/comp/TypeEnter.java | 24 - .../sun/tools/javac/main/JavaCompiler.java | 6 - .../sun/tools/javac/parser/JavaTokenizer.java | 223 +--- .../sun/tools/javac/parser/JavacParser.java | 73 -- .../tools/javac/resources/compiler.properties | 16 - .../com/sun/tools/javac/tree/JCTree.java | 63 +- .../com/sun/tools/javac/tree/Pretty.java | 17 +- .../com/sun/tools/javac/tree/TreeCopier.java | 10 +- .../com/sun/tools/javac/tree/TreeInfo.java | 7 +- .../com/sun/tools/javac/tree/TreeMaker.java | 10 +- .../com/sun/tools/javac/tree/TreeScanner.java | 7 +- .../sun/tools/javac/tree/TreeTranslator.java | 9 +- .../com/sun/tools/javac/util/Names.java | 17 +- .../String/concat/MakeConcatWithTemplate.java | 139 --- test/jdk/java/lang/template/Basic.java | 504 --------- .../java/lang/template/FormatterBuilder.java | 961 ------------------ .../lang/template/StringTemplateTest.java | 304 ------ test/jdk/java/lang/template/T8313809.java | 43 - .../jdk/jshell/CompletenessTest.java | 11 +- .../javac/diags/examples/StringTemplate.java | 33 - .../examples/StringTemplateNoProcessor.java | 34 - .../examples/StringTemplateNotProcessor.java | 39 - .../examples/StringTemplateRawProcessor.java | 44 - .../StringTemplateUnclosedString.java | 37 - .../StringTemplateUnclosedTextBlock.java | 42 - .../tools/javac/parser/JavacParserTest.java | 103 -- .../langtools/tools/javac/template/Basic.java | 240 ----- .../tools/javac/template/T8312814.java | 39 - .../tools/javac/template/TreeScannerTest.java | 107 -- .../tools/javac/tree/TreeKindTest.java | 4 - .../tools/jdeps/listdeps/ListModuleDeps.java | 1 - .../bench/java/lang/StringTemplateFMT.java | 78 -- 66 files changed, 183 insertions(+), 7278 deletions(-) delete mode 100644 src/java.base/share/classes/java/lang/StringTemplate.java delete mode 100644 src/java.base/share/classes/java/lang/runtime/StringTemplateImpl.java delete mode 100644 src/java.base/share/classes/java/lang/runtime/StringTemplateImplFactory.java delete mode 100644 src/java.base/share/classes/java/lang/runtime/TemplateRuntime.java delete mode 100644 src/java.base/share/classes/java/lang/runtime/TemplateSupport.java delete mode 100644 src/java.base/share/classes/java/util/FormatItem.java delete mode 100644 src/java.base/share/classes/java/util/FormatProcessor.java delete mode 100644 src/java.base/share/classes/java/util/FormatterBuilder.java delete mode 100644 src/java.base/share/classes/jdk/internal/access/JavaTemplateAccess.java delete mode 100644 src/java.base/share/classes/jdk/internal/util/Digits.java delete mode 100644 src/java.base/share/classes/jdk/internal/util/FormatConcatItem.java delete mode 100644 src/jdk.compiler/share/classes/com/sun/source/tree/StringTemplateTree.java delete mode 100644 src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransLiterals.java delete mode 100644 test/jdk/java/lang/String/concat/MakeConcatWithTemplate.java delete mode 100644 test/jdk/java/lang/template/Basic.java delete mode 100644 test/jdk/java/lang/template/FormatterBuilder.java delete mode 100644 test/jdk/java/lang/template/StringTemplateTest.java delete mode 100644 test/jdk/java/lang/template/T8313809.java delete mode 100644 test/langtools/tools/javac/diags/examples/StringTemplate.java delete mode 100644 test/langtools/tools/javac/diags/examples/StringTemplateNoProcessor.java delete mode 100644 test/langtools/tools/javac/diags/examples/StringTemplateNotProcessor.java delete mode 100644 test/langtools/tools/javac/diags/examples/StringTemplateRawProcessor.java delete mode 100644 test/langtools/tools/javac/diags/examples/StringTemplateUnclosedString.java delete mode 100644 test/langtools/tools/javac/diags/examples/StringTemplateUnclosedTextBlock.java delete mode 100644 test/langtools/tools/javac/template/Basic.java delete mode 100644 test/langtools/tools/javac/template/T8312814.java delete mode 100644 test/langtools/tools/javac/template/TreeScannerTest.java delete mode 100644 test/micro/org/openjdk/bench/java/lang/StringTemplateFMT.java diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index 28b9b754bbd..49f556e5aa6 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -26,8 +26,6 @@ package java.lang; import jdk.internal.misc.Unsafe; -import jdk.internal.javac.PreviewFeature; -import jdk.internal.util.FormatConcatItem; import jdk.internal.vm.annotation.ForceInline; import java.lang.invoke.MethodHandle; @@ -127,20 +125,6 @@ final class StringConcatHelper { return checkOverflow(lengthCoder); } - /** - * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder - * @since 21 - */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - static long mix(long lengthCoder, FormatConcatItem value) { - lengthCoder = value.mix(lengthCoder); - return checkOverflow(lengthCoder); - } - /** * Prepends the stringly representation of boolean value into buffer, * given the coder and final index. Index is measured in chars, not in bytes! @@ -344,48 +328,6 @@ final class StringConcatHelper { return indexCoder; } - /** - * Prepends the stringly representation of FormatConcatItem value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value String value to encode - * @return updated index (coder value retained) - * @since 21 - */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - static long prepend(long indexCoder, byte[] buf, FormatConcatItem value) { - try { - return value.prepend(indexCoder, buf); - } catch (Error ex) { - throw ex; - } catch (Throwable ex) { - throw new AssertionError("FormatConcatItem prepend error", ex); - } - } - - /** - * Prepends constant and the stringly representation of value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value boolean value to encode - * @param prefix a constant to prepend before value - * @return updated index (coder value retained) - * @since 21 - */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - static long prepend(long indexCoder, byte[] buf, - FormatConcatItem value, String prefix) { - indexCoder = prepend(indexCoder, buf, value); - indexCoder = prepend(indexCoder, buf, prefix); - return indexCoder; - } - /** * Instantiates the String with given buffer and coder * @param buf buffer to use @@ -517,71 +459,6 @@ final class StringConcatHelper { return String.COMPACT_STRINGS ? LATIN1 : UTF16; } - /* - * Initialize after phase1. - */ - private static class LateInit { - static final MethodHandle GETCHAR_LATIN1_MH; - - static final MethodHandle GETCHAR_UTF16_MH; - - static final MethodHandle PUTCHAR_LATIN1_MH; - - static final MethodHandle PUTCHAR_UTF16_MH; - - static { - MethodType getCharMT = - MethodType.methodType(char.class, - byte[].class, int.class); - MethodType putCharMT = - MethodType.methodType(void.class, - byte[].class, int.class, int.class); - GETCHAR_LATIN1_MH = lookupStatic("getCharLatin1", getCharMT); - GETCHAR_UTF16_MH = lookupStatic("getCharUTF16", getCharMT); - PUTCHAR_LATIN1_MH = lookupStatic("putCharLatin1", putCharMT); - PUTCHAR_UTF16_MH = lookupStatic("putCharUTF16", putCharMT); - } - - } - - @ForceInline - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - static char getCharLatin1(byte[] buffer, int index) { - return (char)buffer[index]; - } - - @ForceInline - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - static char getCharUTF16(byte[] buffer, int index) { - return StringUTF16.getChar(buffer, index); - } - - @ForceInline - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - static void putCharLatin1(byte[] buffer, int index, int ch) { - buffer[index] = (byte)ch; - } - - @ForceInline - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - static void putCharUTF16(byte[] buffer, int index, int ch) { - StringUTF16.putChar(buffer, index, ch); - } - - @ForceInline - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - static MethodHandle selectGetChar(long indexCoder) { - return indexCoder < UTF16 ? LateInit.GETCHAR_LATIN1_MH : - LateInit.GETCHAR_UTF16_MH; - } - - @ForceInline - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - static MethodHandle selectPutChar(long indexCoder) { - return indexCoder < UTF16 ? LateInit.PUTCHAR_LATIN1_MH : - LateInit.PUTCHAR_UTF16_MH; - } - static MethodHandle lookupStatic(String name, MethodType methodType) { try { return MethodHandles.lookup() diff --git a/src/java.base/share/classes/java/lang/StringTemplate.java b/src/java.base/share/classes/java/lang/StringTemplate.java deleted file mode 100644 index c14876130be..00000000000 --- a/src/java.base/share/classes/java/lang/StringTemplate.java +++ /dev/null @@ -1,622 +0,0 @@ -/* - * 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; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; -import java.util.FormatProcessor; -import java.util.function.Function; -import java.util.List; -import java.util.Objects; - -import jdk.internal.access.JavaTemplateAccess; -import jdk.internal.access.SharedSecrets; -import jdk.internal.javac.PreviewFeature; - -/** - * {@link StringTemplate} is the run-time representation of a string template or - * text block template in a template expression. - *

- * In the source code of a Java program, a string template or text block template - * contains an interleaved succession of fragment literals and embedded - * expressions. The {@link StringTemplate#fragments()} method returns the - * fragment literals, and the {@link StringTemplate#values()} method returns the - * results of evaluating the embedded expressions. {@link StringTemplate} does not - * provide access to the source code of the embedded expressions themselves; it is - * not a compile-time representation of a string template or text block template. - *

- * {@link StringTemplate} is primarily used in conjunction with a template processor - * to produce a string or other meaningful value. Evaluation of a template expression - * first produces an instance of {@link StringTemplate}, representing the right hand side - * of the template expression, and then passes the instance to the template processor - * given by the template expression. - *

- * For example, the following code contains a template expression that uses the template - * processor {@code RAW}, which simply yields the {@link StringTemplate} passed to it: - * {@snippet : - * int x = 10; - * int y = 20; - * StringTemplate st = RAW."\{x} + \{y} = \{x + y}"; - * List fragments = st.fragments(); - * List values = st.values(); - * } - * {@code fragments} will be equivalent to {@code List.of("", " + ", " = ", "")}, - * which includes the empty first and last fragments. {@code values} will be the - * equivalent of {@code List.of(10, 20, 30)}. - *

- * The following code contains a template expression with the same template but with a - * different template processor, {@code STR}: - * {@snippet : - * int x = 10; - * int y = 20; - * String s = STR."\{x} + \{y} = \{x + y}"; - * } - * When the template expression is evaluated, an instance of {@link StringTemplate} is - * produced that returns the same lists from {@link StringTemplate#fragments()} and - * {@link StringTemplate#values()} as shown above. The {@link StringTemplate#STR} template - * processor uses these lists to yield an interpolated string. The value of {@code s} will - * be equivalent to {@code "10 + 20 = 30"}. - *

- * The {@code interpolate()} method provides a direct way to perform string interpolation - * of a {@link StringTemplate}. Template processors can use the following code pattern: - * {@snippet : - * List fragments = st.fragments(); - * List values = st.values(); - * ... check or manipulate the fragments and/or values ... - * String result = StringTemplate.interpolate(fragments, values); - * } - * The {@link StringTemplate#process(Processor)} method, in conjunction with - * the {@link StringTemplate#RAW} processor, may be used to defer processing of a - * {@link StringTemplate}. - * {@snippet : - * StringTemplate st = RAW."\{x} + \{y} = \{x + y}"; - * ...other steps... - * String result = st.process(STR); - * } - * The factory methods {@link StringTemplate#of(String)} and - * {@link StringTemplate#of(List, List)} can be used to construct a {@link StringTemplate}. - * - * @see Processor - * @see java.util.FormatProcessor - * - * @implNote Implementations of {@link StringTemplate} must minimally implement the - * methods {@link StringTemplate#fragments()} and {@link StringTemplate#values()}. - * Instances of {@link StringTemplate} are considered immutable. To preserve the - * semantics of string templates and text block templates, the list returned by - * {@link StringTemplate#fragments()} must be one element larger than the list returned - * by {@link StringTemplate#values()}. - * - * @since 21 - * - * @jls 15.8.6 Process Template Expressions - */ -@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) -public interface StringTemplate { - /** - * Returns a list of fragment literals for this {@link StringTemplate}. - * The fragment literals are the character sequences preceding each of the embedded - * expressions in source code, plus the character sequence following the last - * embedded expression. Such character sequences may be zero-length if an embedded - * expression appears at the beginning or end of a template, or if two embedded - * expressions are directly adjacent in a template. - * In the example: {@snippet : - * String student = "Mary"; - * String teacher = "Johnson"; - * StringTemplate st = RAW."The student \{student} is in \{teacher}'s classroom."; - * List fragments = st.fragments(); // @highlight substring="fragments()" - * } - * {@code fragments} will be equivalent to - * {@code List.of("The student ", " is in ", "'s classroom.")} - * - * @return list of string fragments - * - * @implSpec the list returned is immutable - */ - List fragments(); - - /** - * Returns a list of embedded expression results for this {@link StringTemplate}. - * In the example: - * {@snippet : - * String student = "Mary"; - * String teacher = "Johnson"; - * StringTemplate st = RAW."The student \{student} is in \{teacher}'s classroom."; - * List values = st.values(); // @highlight substring="values()" - * } - * {@code values} will be equivalent to {@code List.of(student, teacher)} - * - * @return list of expression values - * - * @implSpec the list returned is immutable - */ - List values(); - - /** - * Returns the string interpolation of the fragments and values for this - * {@link StringTemplate}. - * @apiNote For better visibility and when practical, it is recommended to use the - * {@link StringTemplate#STR} processor instead of invoking the - * {@link StringTemplate#interpolate()} method. - * {@snippet : - * String student = "Mary"; - * String teacher = "Johnson"; - * StringTemplate st = RAW."The student \{student} is in \{teacher}'s classroom."; - * String result = st.interpolate(); // @highlight substring="interpolate()" - * } - * In the above example, the value of {@code result} will be - * {@code "The student Mary is in Johnson's classroom."}. This is - * produced by the interleaving concatenation of fragments and values from the supplied - * {@link StringTemplate}. To accommodate concatenation, values are converted to strings - * as if invoking {@link String#valueOf(Object)}. - * - * @return interpolation of this {@link StringTemplate} - * - * @implSpec The default implementation returns the result of invoking - * {@code StringTemplate.interpolate(this.fragments(), this.values())}. - */ - default String interpolate() { - return StringTemplate.interpolate(fragments(), values()); - } - - /** - * Returns the result of applying the specified processor to this {@link StringTemplate}. - * This method can be used as an alternative to string template expressions. For example, - * {@snippet : - * String student = "Mary"; - * String teacher = "Johnson"; - * String result1 = STR."The student \{student} is in \{teacher}'s classroom."; - * String result2 = RAW."The student \{student} is in \{teacher}'s classroom.".process(STR); // @highlight substring="process" - * } - * Produces an equivalent result for both {@code result1} and {@code result2}. - * - * @param processor the {@link Processor} instance to process - * - * @param Processor's process result type. - * @param Exception thrown type. - * - * @return constructed object of type {@code R} - * - * @throws E exception thrown by the template processor when validation fails - * @throws NullPointerException if processor is null - * - * @implSpec The default implementation returns the result of invoking - * {@code processor.process(this)}. If the invocation throws an exception that - * exception is forwarded to the caller. - */ - default R - process(Processor processor) throws E { - Objects.requireNonNull(processor, "processor should not be null"); - - return processor.process(this); - } - - /** - * Produces a diagnostic string that describes the fragments and values of the supplied - * {@link StringTemplate}. - * - * @param stringTemplate the {@link StringTemplate} to represent - * - * @return diagnostic string representing the supplied string template - * - * @throws NullPointerException if stringTemplate is null - */ - static String toString(StringTemplate stringTemplate) { - Objects.requireNonNull(stringTemplate, "stringTemplate should not be null"); - return "StringTemplate{ fragments = [ \"" + - String.join("\", \"", stringTemplate.fragments()) + - "\" ], values = " + - stringTemplate.values() + - " }"; - } - - /** - * Returns a {@link StringTemplate} as if constructed by invoking - * {@code StringTemplate.of(List.of(string), List.of())}. That is, a {@link StringTemplate} - * with one fragment and no values. - * - * @param string single string fragment - * - * @return StringTemplate composed from string - * - * @throws NullPointerException if string is null - */ - static StringTemplate of(String string) { - Objects.requireNonNull(string, "string must not be null"); - JavaTemplateAccess JTA = SharedSecrets.getJavaTemplateAccess(); - return JTA.of(List.of(string), List.of()); - } - - /** - * Returns a StringTemplate with the given fragments and values. - * - * @implSpec The {@code fragments} list size must be one more that the - * {@code values} list size. - * - * @param fragments list of string fragments - * @param values list of expression values - * - * @return StringTemplate composed from string - * - * @throws IllegalArgumentException if fragments list size is not one more - * than values list size - * @throws NullPointerException if fragments is null or values is null or if any fragment is null. - * - * @implNote Contents of both lists are copied to construct immutable lists. - */ - static StringTemplate of(List fragments, List values) { - Objects.requireNonNull(fragments, "fragments must not be null"); - Objects.requireNonNull(values, "values must not be null"); - if (values.size() + 1 != fragments.size()) { - throw new IllegalArgumentException( - "fragments list size is not one more than values list size"); - } - JavaTemplateAccess JTA = SharedSecrets.getJavaTemplateAccess(); - return JTA.of(fragments, values); - } - - /** - * Creates a string that interleaves the elements of values between the - * elements of fragments. To accommodate interpolation, values are converted to strings - * as if invoking {@link String#valueOf(Object)}. - * - * @param fragments list of String fragments - * @param values list of expression values - * - * @return String interpolation of fragments and values - * - * @throws IllegalArgumentException if fragments list size is not one more - * than values list size - * @throws NullPointerException fragments or values is null or if any of the fragments is null - */ - static String interpolate(List fragments, List values) { - Objects.requireNonNull(fragments, "fragments must not be null"); - Objects.requireNonNull(values, "values must not be null"); - int fragmentsSize = fragments.size(); - int valuesSize = values.size(); - if (fragmentsSize != valuesSize + 1) { - throw new IllegalArgumentException("fragments must have one more element than values"); - } - JavaTemplateAccess JTA = SharedSecrets.getJavaTemplateAccess(); - return JTA.interpolate(fragments, values); - } - - /** - * Combine zero or more {@link StringTemplate StringTemplates} into a single - * {@link StringTemplate}. - * {@snippet : - * StringTemplate st = StringTemplate.combine(RAW."\{a}", RAW."\{b}", RAW."\{c}"); - * assert st.interpolate().equals(STR."\{a}\{b}\{c}"); - * } - * Fragment lists from the {@link StringTemplate StringTemplates} are combined end to - * end with the last fragment from each {@link StringTemplate} concatenated with the - * first fragment of the next. To demonstrate, if we were to take two strings and we - * combined them as follows: {@snippet lang = "java": - * String s1 = "abc"; - * String s2 = "xyz"; - * String sc = s1 + s2; - * assert Objects.equals(sc, "abcxyz"); - * } - * the last character {@code "c"} from the first string is juxtaposed with the first - * character {@code "x"} of the second string. The same would be true of combining - * {@link StringTemplate StringTemplates}. - * {@snippet lang ="java": - * StringTemplate st1 = RAW."a\{}b\{}c"; - * StringTemplate st2 = RAW."x\{}y\{}z"; - * StringTemplate st3 = RAW."a\{}b\{}cx\{}y\{}z"; - * StringTemplate stc = StringTemplate.combine(st1, st2); - * - * assert Objects.equals(st1.fragments(), List.of("a", "b", "c")); - * assert Objects.equals(st2.fragments(), List.of("x", "y", "z")); - * assert Objects.equals(st3.fragments(), List.of("a", "b", "cx", "y", "z")); - * assert Objects.equals(stc.fragments(), List.of("a", "b", "cx", "y", "z")); - * } - * Values lists are simply concatenated to produce a single values list. - * The result is a well-formed {@link StringTemplate} with n+1 fragments and n values, where - * n is the total of number of values across all the supplied - * {@link StringTemplate StringTemplates}. - * - * @param stringTemplates zero or more {@link StringTemplate} - * - * @return combined {@link StringTemplate} - * - * @throws NullPointerException if stringTemplates is null or if any of the - * {@code stringTemplates} are null - * - * @implNote If zero {@link StringTemplate} arguments are provided then a - * {@link StringTemplate} with an empty fragment and no values is returned, as if invoking - * StringTemplate.of("") . If only one {@link StringTemplate} argument is provided - * then it is returned unchanged. - */ - static StringTemplate combine(StringTemplate... stringTemplates) { - JavaTemplateAccess JTA = SharedSecrets.getJavaTemplateAccess(); - return JTA.combine(stringTemplates); - } - - /** - * Combine a list of {@link StringTemplate StringTemplates} into a single - * {@link StringTemplate}. - * {@snippet : - * StringTemplate st = StringTemplate.combine(List.of(RAW."\{a}", RAW."\{b}", RAW."\{c}")); - * assert st.interpolate().equals(STR."\{a}\{b}\{c}"); - * } - * Fragment lists from the {@link StringTemplate StringTemplates} are combined end to - * end with the last fragment from each {@link StringTemplate} concatenated with the - * first fragment of the next. To demonstrate, if we were to take two strings and we - * combined them as follows: {@snippet lang = "java": - * String s1 = "abc"; - * String s2 = "xyz"; - * String sc = s1 + s2; - * assert Objects.equals(sc, "abcxyz"); - * } - * the last character {@code "c"} from the first string is juxtaposed with the first - * character {@code "x"} of the second string. The same would be true of combining - * {@link StringTemplate StringTemplates}. - * {@snippet lang ="java": - * StringTemplate st1 = RAW."a\{}b\{}c"; - * StringTemplate st2 = RAW."x\{}y\{}z"; - * StringTemplate st3 = RAW."a\{}b\{}cx\{}y\{}z"; - * StringTemplate stc = StringTemplate.combine(List.of(st1, st2)); - * - * assert Objects.equals(st1.fragments(), List.of("a", "b", "c")); - * assert Objects.equals(st2.fragments(), List.of("x", "y", "z")); - * assert Objects.equals(st3.fragments(), List.of("a", "b", "cx", "y", "z")); - * assert Objects.equals(stc.fragments(), List.of("a", "b", "cx", "y", "z")); - * } - * Values lists are simply concatenated to produce a single values list. - * The result is a well-formed {@link StringTemplate} with n+1 fragments and n values, where - * n is the total of number of values across all the supplied - * {@link StringTemplate StringTemplates}. - * - * @param stringTemplates list of {@link StringTemplate} - * - * @return combined {@link StringTemplate} - * - * @throws NullPointerException if stringTemplates is null or if any of the - * its elements are null - * - * @implNote If {@code stringTemplates.size() == 0} then a {@link StringTemplate} with - * an empty fragment and no values is returned, as if invoking - * StringTemplate.of("") . If {@code stringTemplates.size() == 1} - * then the first element of the list is returned unchanged. - */ - static StringTemplate combine(List stringTemplates) { - JavaTemplateAccess JTA = SharedSecrets.getJavaTemplateAccess(); - return JTA.combine(stringTemplates.toArray(new StringTemplate[0])); - } - - /** - * This {@link Processor} instance is conventionally used for the string interpolation - * of a supplied {@link StringTemplate}. - *

- * For better visibility and when practical, it is recommended that users use the - * {@link StringTemplate#STR} processor instead of invoking the - * {@link StringTemplate#interpolate()} method. - * Example: {@snippet : - * int x = 10; - * int y = 20; - * String result = STR."\{x} + \{y} = \{x + y}"; // @highlight substring="STR" - * } - * In the above example, the value of {@code result} will be {@code "10 + 20 = 30"}. This is - * produced by the interleaving concatenation of fragments and values from the supplied - * {@link StringTemplate}. To accommodate concatenation, values are converted to strings - * as if invoking {@link String#valueOf(Object)}. - * @apiNote {@link StringTemplate#STR} is statically imported implicitly into every - * Java compilation unit. - */ - Processor STR = StringTemplate::interpolate; - - /** - * This {@link Processor} instance is conventionally used to indicate that the - * processing of the {@link StringTemplate} is to be deferred to a later time. Deferred - * processing can be resumed by invoking the - * {@link StringTemplate#process(Processor)} or - * {@link Processor#process(StringTemplate)} methods. - * {@snippet : - * import static java.lang.StringTemplate.RAW; - * ... - * StringTemplate st = RAW."\{x} + \{y} = \{x + y}"; - * ...other steps... - * String result = STR.process(st); - * } - * @implNote Unlike {@link StringTemplate#STR}, {@link StringTemplate#RAW} must be - * statically imported explicitly. - */ - Processor RAW = st -> st; - - /** - * This interface describes the methods provided by a generalized string template processor. The - * primary method {@link Processor#process(StringTemplate)} is used to validate - * and compose a result using a {@link StringTemplate StringTemplate's} fragments and values lists. - *

- * For example: - * {@snippet : - * class MyProcessor implements Processor { - * @Override - * public String process(StringTemplate st) throws IllegalArgumentException { - * StringBuilder sb = new StringBuilder(); - * Iterator fragmentsIter = st.fragments().iterator(); - * - * for (Object value : st.values()) { - * sb.append(fragmentsIter.next()); - * - * if (value instanceof Boolean) { - * throw new IllegalArgumentException("I don't like Booleans"); - * } - * - * sb.append(value); - * } - * - * sb.append(fragmentsIter.next()); - * - * return sb.toString(); - * } - * } - * - * MyProcessor myProcessor = new MyProcessor(); - * try { - * int x = 10; - * int y = 20; - * String result = myProcessor."\{x} + \{y} = \{x + y}"; - * ... - * } catch (IllegalArgumentException ex) { - * ... - * } - * } - * Implementations of this interface may provide, but are not limited to, validating - * inputs, composing inputs into a result, and transforming an intermediate string - * result to a non-string value before delivering the final result. - *

- * The user has the option of validating inputs used in composition. For example an SQL - * processor could prevent injection vulnerabilities by sanitizing inputs or throwing an - * exception of type {@code E} if an SQL statement is a potential vulnerability. - *

- * Composing allows user control over how the result is assembled. Most often, a - * user will construct a new string from the string template, with placeholders - * replaced by string representations of value list elements. These string - * representations are created as if invoking {@link String#valueOf}. - *

- * Transforming allows the processor to return something other than a string. For - * instance, a JSON processor could return a JSON object, by parsing the string created - * by composition, instead of the composed string. - *

- * {@link Processor} is a {@link FunctionalInterface}. This permits - * declaration of a processor using lambda expressions; - * {@snippet : - * Processor processor = st -> { - * List fragments = st.fragments(); - * List values = st.values(); - * // check or manipulate the fragments and/or values - * ... - * return StringTemplate.interpolate(fragments, values); - * }; - * } - * The {@link StringTemplate#interpolate()} method is available for those processors - * that just need to work with the string interpolation; - * {@snippet : - * Processor processor = StringTemplate::interpolate; - * } - * or simply transform the string interpolation into something other than - * {@link String}; - * {@snippet : - * Processor jsonProcessor = st -> new JSONObject(st.interpolate()); - * } - * @implNote The Java compiler automatically imports {@link StringTemplate#STR} - * - * @param Processor's process result type - * @param Exception thrown type - * - * @see StringTemplate - * @see java.util.FormatProcessor - * - * @since 21 - * - * @jls 15.8.6 Process Template Expressions - */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - @FunctionalInterface - public interface Processor { - - /** - * Constructs a result based on the template fragments and values in the - * supplied {@link StringTemplate stringTemplate} object. - * @apiNote Processing of a {@link StringTemplate} may include validation according to the particular facts relating - * to each situation. The {@code E} type parameter indicates the type of checked exception that is thrown by - * {@link #process} if validation fails, ex. {@code java.sql.SQLException}. If no checked exception is expected - * then {@link RuntimeException} may be used. Note that unchecked exceptions, such as {@link RuntimeException}, - * {@link NullPointerException} or {@link IllegalArgumentException} may be thrown as part of the normal - * method arguments processing. Details of which exceptions are thrown will be found in the documentation - * of the specific implementation. - * - * @param stringTemplate a {@link StringTemplate} instance - * - * @return constructed object of type R - * - * @throws E exception thrown by the template processor when validation fails - */ - R process(StringTemplate stringTemplate) throws E; - - /** - * This factory method can be used to create a {@link Processor} containing a - * {@link Processor#process} method derived from a lambda expression. As an example; - * {@snippet : - * Processor mySTR = Processor.of(StringTemplate::interpolate); - * int x = 10; - * int y = 20; - * String str = mySTR."\{x} + \{y} = \{x + y}"; - * } - * The result type of the constructed {@link Processor} may be derived from - * the lambda expression, thus this method may be used in a var - * statement. For example, {@code mySTR} from above can also be declared using; - * {@snippet : - * var mySTR = Processor.of(StringTemplate::interpolate); - * } - * {@link RuntimeException} is the assumed exception thrown type. - * - * @param process a function that takes a {@link StringTemplate} as an argument - * and returns the inferred result type - * - * @return a {@link Processor} - * - * @param Processor's process result type - */ - static Processor of(Function process) { - return process::apply; - } - - /** - * Built-in policies using this additional interface have the flexibility to - * specialize the composition of the templated string by returning a customized - * {@link MethodHandle} from {@link Linkage#linkage linkage}. - * These specializations are typically implemented to improve performance; - * specializing value types or avoiding boxing and vararg arrays. - * - * @implNote This interface is sealed to only allow standard processors. - * - * @sealedGraph - * @since 21 - */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - public sealed interface Linkage permits FormatProcessor { - /** - * This method creates a {@link MethodHandle} that when invoked with arguments of - * those specified in {@code type} returns a result that equals that returned by - * the template processor's process method. The difference being that this method - * can preview the template's fragments and value types in advance of usage and - * thereby has the opportunity to produce a specialized implementation. - * - * @param fragments string template fragments - * @param type method type, includes the StringTemplate receiver as - * well as the value types - * - * @return {@link MethodHandle} for the processor applied to template - * - * @throws NullPointerException if any of the arguments are null - */ - MethodHandle linkage(List fragments, MethodType type); - } - } - -} diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index d6a0faa4200..3c80e82b138 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -80,7 +80,6 @@ import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; -import jdk.internal.javac.PreviewFeature; import jdk.internal.logger.LoggerFinderLoader; import jdk.internal.logger.LazyLoggers; import jdk.internal.logger.LocalizedLoggerWrapper; @@ -2490,6 +2489,9 @@ public final class System { public char getUTF16Char(byte[] bytes, int index) { return StringUTF16.getChar(bytes, index); } + public void putCharUTF16(byte[] bytes, int index, int ch) { + StringUTF16.putChar(bytes, index, ch); + } public byte[] getBytesNoRepl(String s, Charset cs) throws CharacterCodingException { return String.getBytesNoRepl(s, cs); } @@ -2530,6 +2532,10 @@ public final class System { return StringConcatHelper.lookupStatic(name, methodType); } + public long stringConcatHelperPrepend(long indexCoder, byte[] buf, String value) { + return StringConcatHelper.prepend(indexCoder, buf, value); + } + public long stringConcatInitialCoder() { return StringConcatHelper.initialCoder(); } @@ -2538,21 +2544,20 @@ public final class System { return StringConcatHelper.mix(lengthCoder, constant); } - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - public long stringConcatCoder(char value) { - return StringConcatHelper.coder(value); + public long stringConcatMix(long lengthCoder, char value) { + return StringConcatHelper.mix(lengthCoder, value); } - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - public long stringBuilderConcatMix(long lengthCoder, - StringBuilder sb) { - return sb.mix(lengthCoder); + public int stringSize(long i) { + return Long.stringSize(i); } - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - public long stringBuilderConcatPrepend(long lengthCoder, byte[] buf, - StringBuilder sb) { - return sb.prepend(lengthCoder, buf); + public int getCharsLatin1(long i, int index, byte[] buf) { + return StringLatin1.getChars(i, index, buf); + } + + public int getCharsUTF16(long i, int index, byte[] buf) { + return StringUTF16.getChars(i, index, buf); } public String join(String prefix, String suffix, String delimiter, String[] elements, int size) { diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index cc0abfef97c..b918b756332 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -28,7 +28,6 @@ package java.lang.invoke; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.javac.PreviewFeature; -import jdk.internal.util.FormatConcatItem; import jdk.internal.vm.annotation.Stable; import sun.invoke.util.Wrapper; @@ -115,14 +114,8 @@ public final class StringConcatFactory { * While the maximum number of argument slots that indy call can handle is 253, * we do not use all those slots, to let the strategies with MethodHandle * combinators to use some arguments. - * - * @since 21 */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - public static final int MAX_INDY_CONCAT_ARG_SLOTS; - // Use static initialize block to avoid MAX_INDY_CONCAT_ARG_SLOTS being treating - // as a constant for constant folding. - static { MAX_INDY_CONCAT_ARG_SLOTS = 200; } + private static final int MAX_INDY_CONCAT_ARG_SLOTS = 200; private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); @@ -712,9 +705,6 @@ public final class StringConcatFactory { int idx = classIndex(cl); MethodHandle prepend = PREPENDERS[idx]; if (prepend == null) { - if (idx == STRING_CONCAT_ITEM) { - cl = FormatConcatItem.class; - } PREPENDERS[idx] = prepend = JLA.stringConcatHelper("prepend", methodType(long.class, long.class, byte[].class, Wrapper.asPrimitiveType(cl), String.class)).rebind(); @@ -726,9 +716,6 @@ public final class StringConcatFactory { int idx = classIndex(cl); MethodHandle prepend = NO_PREFIX_PREPENDERS[idx]; if (prepend == null) { - if (idx == STRING_CONCAT_ITEM) { - cl = FormatConcatItem.class; - } NO_PREFIX_PREPENDERS[idx] = prepend = JLA.stringConcatHelper("prepend", methodType(long.class, long.class, byte[].class, Wrapper.asPrimitiveType(cl))).rebind(); @@ -741,15 +728,13 @@ public final class StringConcatFactory { LONG_IDX = 2, BOOLEAN_IDX = 3, STRING_IDX = 4, - STRING_CONCAT_ITEM = 5, - TYPE_COUNT = 6; + TYPE_COUNT = 5; private static int classIndex(Class cl) { if (cl == String.class) return STRING_IDX; if (cl == int.class) return INT_IDX; if (cl == boolean.class) return BOOLEAN_IDX; if (cl == char.class) return CHAR_IDX; if (cl == long.class) return LONG_IDX; - if (FormatConcatItem.class.isAssignableFrom(cl)) return STRING_CONCAT_ITEM; throw new IllegalArgumentException("Unexpected class: " + cl); } @@ -1047,303 +1032,4 @@ public final class StringConcatFactory { // no instantiation } - /** - * Simplified concatenation method to facilitate {@link StringTemplate} - * concatenation. This method returns a single concatenation method that - * interleaves fragments and values. fragment|value|fragment|value|...|value|fragment. - * The number of fragments must be one more that the number of ptypes. - * The total number of slots used by the ptypes must be less than or equal - * to {@link #MAX_INDY_CONCAT_ARG_SLOTS}. - * - * @param fragments list of string fragments - * @param ptypes list of expression types - * - * @return the {@link MethodHandle} for concatenation - * - * @throws StringConcatException If any of the linkage invariants are violated. - * @throws NullPointerException If any of the incoming arguments is null. - * @throws IllegalArgumentException If the number of value slots exceed {@link #MAX_INDY_CONCAT_ARG_SLOTS}. - * - * @since 21 - */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - public static MethodHandle makeConcatWithTemplate( - List fragments, - List> ptypes) - throws StringConcatException - { - Objects.requireNonNull(fragments, "fragments is null"); - Objects.requireNonNull(ptypes, "ptypes is null"); - ptypes = List.copyOf(ptypes); - - if (fragments.size() != ptypes.size() + 1) { - throw new IllegalArgumentException("fragments size not equal ptypes size plus one"); - } - - if (ptypes.isEmpty()) { - return MethodHandles.constant(String.class, fragments.get(0)); - } - - Class[] ttypes = new Class[ptypes.size()]; - MethodHandle[] filters = new MethodHandle[ptypes.size()]; - int slots = 0; - - int pos = 0; - for (Class ptype : ptypes) { - slots += ptype == long.class || ptype == double.class ? 2 : 1; - - if (MAX_INDY_CONCAT_ARG_SLOTS < slots) { - throw new StringConcatException("Too many concat argument slots: " + - slots + ", can only accept " + MAX_INDY_CONCAT_ARG_SLOTS); - } - - boolean isSpecialized = ptype.isPrimitive(); - boolean isFormatConcatItem = FormatConcatItem.class.isAssignableFrom(ptype); - Class ttype = isSpecialized ? promoteToIntType(ptype) : - isFormatConcatItem ? FormatConcatItem.class : Object.class; - MethodHandle filter = isFormatConcatItem ? null : stringifierFor(ttype); - - if (filter != null) { - filters[pos] = filter; - ttype = String.class; - } - - ttypes[pos++] = ttype; - } - - MethodHandle mh = MethodHandles.dropArguments(newString(), 2, ttypes); - - long initialLengthCoder = INITIAL_CODER; - pos = 0; - for (String fragment : fragments) { - initialLengthCoder = JLA.stringConcatMix(initialLengthCoder, fragment); - - if (ttypes.length <= pos) { - break; - } - - Class ttype = ttypes[pos]; - // (long,byte[],ttype) -> long - MethodHandle prepender = prepender(fragment, ttype); - // (byte[],long,ttypes...) -> String (unchanged) - mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,1, 0, 2 + pos); - - pos++; - } - - String lastFragment = fragments.getLast(); - initialLengthCoder -= lastFragment.length(); - MethodHandle newArrayCombinator = lastFragment.isEmpty() ? newArray() : - newArrayWithSuffix(lastFragment); - // (long,ttypes...) -> String - mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, newArrayCombinator, - 1 // index - ); - - pos = 0; - for (Class ttype : ttypes) { - // (long,ttype) -> long - MethodHandle mix = mixer(ttypes[pos]); - boolean lastPType = pos == ttypes.length - 1; - - if (lastPType) { - // (ttype) -> long - mix = MethodHandles.insertArguments(mix, 0, initialLengthCoder); - // (ttypes...) -> String - mh = MethodHandles.foldArgumentsWithCombiner(mh, 0, mix, - 1 + pos // selected argument - ); - } else { - // (long,ttypes...) -> String - mh = MethodHandles.filterArgumentsWithCombiner(mh, 0, mix, - 0, // old-index - 1 + pos // selected argument - ); - } - - pos++; - } - - mh = MethodHandles.filterArguments(mh, 0, filters); - MethodType mt = MethodType.methodType(String.class, ptypes); - mh = mh.viewAsType(mt, true); - - return mh; - } - - /** - * This method breaks up large concatenations into separate - * {@link MethodHandle MethodHandles} based on the number of slots required - * per {@link MethodHandle}. Each {@link MethodHandle} after the first will - * have an extra {@link String} slot for the result from the previous - * {@link MethodHandle}. - * {@link #makeConcatWithTemplate} - * is used to construct the {@link MethodHandle MethodHandles}. The total - * number of slots used by the ptypes is open ended. However, care must - * be given when combining the {@link MethodHandle MethodHandles} so that - * the combine total does not exceed the 255 slot limit. - * - * @param fragments list of string fragments - * @param ptypes list of expression types - * @param maxSlots maximum number of slots per {@link MethodHandle}. - * - * @return List of {@link MethodHandle MethodHandles} - * - * @throws IllegalArgumentException If maxSlots is not between 1 and - * MAX_INDY_CONCAT_ARG_SLOTS. - * @throws StringConcatException If any of the linkage invariants are violated. - * @throws NullPointerException If any of the incoming arguments is null. - * @throws IllegalArgumentException If the number of value slots exceed {@link #MAX_INDY_CONCAT_ARG_SLOTS}. - * - * @since 21 - */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - public static List makeConcatWithTemplateCluster( - List fragments, - List> ptypes, - int maxSlots) - throws StringConcatException - { - Objects.requireNonNull(fragments, "fragments is null"); - Objects.requireNonNull(ptypes, "ptypes is null"); - - if (fragments.size() != ptypes.size() + 1) { - throw new StringConcatException("fragments size not equal ptypes size plus one"); - } - - if (maxSlots < 1 || MAX_INDY_CONCAT_ARG_SLOTS < maxSlots) { - throw new IllegalArgumentException("maxSlots must be between 1 and " + - MAX_INDY_CONCAT_ARG_SLOTS); - - } - - if (ptypes.isEmpty()) { - return List.of(MethodHandles.constant(String.class, fragments.get(0))); - } - - List mhs = new ArrayList<>(); - List fragmentsSection = new ArrayList<>(); - List> ptypeSection = new ArrayList<>(); - int slots = 0; - - int pos = 0; - for (Class ptype : ptypes) { - boolean lastPType = pos == ptypes.size() - 1; - fragmentsSection.add(fragments.get(pos)); - ptypeSection.add(ptype); - - slots += ptype == long.class || ptype == double.class ? 2 : 1; - - if (maxSlots <= slots || lastPType) { - fragmentsSection.add(lastPType ? fragments.get(pos + 1) : ""); - MethodHandle mh = makeConcatWithTemplate(fragmentsSection, - ptypeSection); - mhs.add(mh); - fragmentsSection.clear(); - fragmentsSection.add(""); - ptypeSection.clear(); - ptypeSection.add(String.class); - slots = 1; - } - - pos++; - } - - return mhs; - } - - /** - * This method creates a {@link MethodHandle} expecting one input, the - * receiver of the supplied getters. This method uses - * {@link #makeConcatWithTemplateCluster} - * to create the intermediate {@link MethodHandle MethodHandles}. - * - * @param fragments list of string fragments - * @param getters list of getter {@link MethodHandle MethodHandles} - * @param maxSlots maximum number of slots per {@link MethodHandle} in - * cluster. - * - * @return the {@link MethodHandle} for concatenation - * - * @throws IllegalArgumentException If maxSlots is not between 1 and - * MAX_INDY_CONCAT_ARG_SLOTS or if the - * getters don't use the same argument type - * @throws StringConcatException If any of the linkage invariants are violated - * @throws NullPointerException If any of the incoming arguments is null - * @throws IllegalArgumentException If the number of value slots exceed {@link #MAX_INDY_CONCAT_ARG_SLOTS}. - * - * @since 21 - */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - public static MethodHandle makeConcatWithTemplateGetters( - List fragments, - List getters, - int maxSlots) - throws StringConcatException - { - Objects.requireNonNull(fragments, "fragments is null"); - Objects.requireNonNull(getters, "getters is null"); - - if (fragments.size() != getters.size() + 1) { - throw new StringConcatException("fragments size not equal getters size plus one"); - } - - if (maxSlots < 1 || MAX_INDY_CONCAT_ARG_SLOTS < maxSlots) { - throw new IllegalArgumentException("maxSlots must be between 1 and " + - MAX_INDY_CONCAT_ARG_SLOTS); - - } - - if (getters.size() == 0) { - throw new StringConcatException("no getters supplied"); - } - - Class receiverType = null; - List> ptypes = new ArrayList<>(); - - for (MethodHandle getter : getters) { - MethodType mt = getter.type(); - Class returnType = mt.returnType(); - - if (returnType == void.class || mt.parameterCount() != 1) { - throw new StringConcatException("not a getter " + mt); - } - - if (receiverType == null) { - receiverType = mt.parameterType(0); - } else if (receiverType != mt.parameterType(0)) { - throw new StringConcatException("not the same receiever type " + - mt + " needs " + receiverType); - } - - ptypes.add(returnType); - } - - MethodType resultType = MethodType.methodType(String.class, receiverType); - List clusters = makeConcatWithTemplateCluster(fragments, ptypes, - maxSlots); - - MethodHandle mh = null; - Iterator getterIterator = getters.iterator(); - - for (MethodHandle cluster : clusters) { - MethodType mt = cluster.type(); - MethodHandle[] filters = new MethodHandle[mt.parameterCount()]; - int pos = 0; - - if (mh != null) { - filters[pos++] = mh; - } - - while (pos < filters.length) { - filters[pos++] = getterIterator.next(); - } - - cluster = MethodHandles.filterArguments(cluster, 0, filters); - mh = MethodHandles.permuteArguments(cluster, resultType, - new int[filters.length]); - } - - return mh; - } } diff --git a/src/java.base/share/classes/java/lang/runtime/StringTemplateImpl.java b/src/java.base/share/classes/java/lang/runtime/StringTemplateImpl.java deleted file mode 100644 index be510fe62b0..00000000000 --- a/src/java.base/share/classes/java/lang/runtime/StringTemplateImpl.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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.util.List; -import java.util.Objects; - -/** - * This class implements specialized {@link StringTemplate StringTemplates} produced by - * string template bootstrap method callsites generated by the compiler. Instances of this - * class are produced by {@link StringTemplateImplFactory}. - *

- * Values are stored by subclassing {@link Carriers.CarrierObject}. This allows specializations - * and sharing of value shapes without creating a new class for each shape. - *

- * {@link StringTemplate} fragments are shared via binding to the - * {@link java.lang.invoke.CallSite CallSite's} {@link MethodHandle}. - *

- * The {@link StringTemplateImpl} instance also carries - * specialized {@link MethodHandle MethodHandles} for producing the values list and interpolation. - * These {@link MethodHandle MethodHandles} are also shared by binding to the - * {@link java.lang.invoke.CallSite CallSite}. - * - * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. - */ -final class StringTemplateImpl extends Carriers.CarrierObject implements StringTemplate { - /** - * List of string fragments for the string template. This value of this list is shared by - * all instances created at the {@link java.lang.invoke.CallSite CallSite}. - */ - private final List fragments; - - /** - * Specialized {@link MethodHandle} used to implement the {@link StringTemplate StringTemplate's} - * {@code values} method. This {@link MethodHandle} is shared by all instances created at the - * {@link java.lang.invoke.CallSite CallSite}. - */ - private final MethodHandle valuesMH; - - /** - * Specialized {@link MethodHandle} used to implement the {@link StringTemplate StringTemplate's} - * {@code interpolate} method. This {@link MethodHandle} is shared by all instances created at the - * {@link java.lang.invoke.CallSite CallSite}. - */ - private final MethodHandle interpolateMH; - - /** - * Constructor. - * - * @param primitiveCount number of primitive slots required (bound at callsite) - * @param objectCount number of object slots required (bound at callsite) - * @param fragments list of string fragments (bound in (bound at callsite) - * @param valuesMH {@link MethodHandle} to produce list of values (bound at callsite) - * @param interpolateMH {@link MethodHandle} to produce interpolation (bound at callsite) - */ - StringTemplateImpl(int primitiveCount, int objectCount, - List fragments, MethodHandle valuesMH, MethodHandle interpolateMH) { - super(primitiveCount, objectCount); - this.fragments = fragments; - this.valuesMH = valuesMH; - this.interpolateMH = interpolateMH; - } - - @Override - public List fragments() { - return fragments; - } - - @Override - public List values() { - try { - return (List)valuesMH.invokeExact(this); - } catch (RuntimeException | Error ex) { - throw ex; - } catch (Throwable ex) { - throw new RuntimeException("string template values failure", ex); - } - } - - @Override - public String interpolate() { - try { - return (String)interpolateMH.invokeExact(this); - } catch (RuntimeException | Error ex) { - throw ex; - } catch (Throwable ex) { - throw new RuntimeException("string template interpolate failure", ex); - } - } - - @Override - public boolean equals(Object other) { - return other instanceof StringTemplate st && - Objects.equals(fragments(), st.fragments()) && - Objects.equals(values(), st.values()); - } - - @Override - public int hashCode() { - return Objects.hash(fragments(), values()); - } - - @Override - public String toString() { - return StringTemplate.toString(this); - } -} diff --git a/src/java.base/share/classes/java/lang/runtime/StringTemplateImplFactory.java b/src/java.base/share/classes/java/lang/runtime/StringTemplateImplFactory.java deleted file mode 100644 index a8e1f1f347b..00000000000 --- a/src/java.base/share/classes/java/lang/runtime/StringTemplateImplFactory.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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 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 fragments, List 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 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 fragments, List values) { - @SuppressWarnings("unchecked") - List copy = (List)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 toList(Object[] elements) { - return Arrays.stream(elements).toList(); - } - -} diff --git a/src/java.base/share/classes/java/lang/runtime/TemplateRuntime.java b/src/java.base/share/classes/java/lang/runtime/TemplateRuntime.java deleted file mode 100644 index 5b41fdb506f..00000000000 --- a/src/java.base/share/classes/java/lang/runtime/TemplateRuntime.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * 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.CallSite; -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.StringTemplate.Processor; -import java.lang.StringTemplate.Processor.Linkage; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -import jdk.internal.access.JavaTemplateAccess; -import jdk.internal.access.SharedSecrets; -import jdk.internal.javac.PreviewFeature; - -/** - * Manages string template bootstrap methods. These methods may be used, for example, - * by Java compiler implementations to create {@link StringTemplate} instances. For example, - * the java compiler will translate the following code; - * {@snippet : - * int x = 10; - * int y = 20; - * StringTemplate st = RAW."\{x} + \{y} = \{x + y}"; - * } - * to byte code that invokes the {@link java.lang.runtime.TemplateRuntime#newStringTemplate} - * bootstrap method to construct a {@link CallSite} that accepts two integers and produces a new - * {@link StringTemplate} instance. - * {@snippet : - * MethodHandles.Lookup lookup = MethodHandles.lookup(); - * MethodType mt = MethodType.methodType(StringTemplate.class, int.class, int.class); - * CallSite cs = TemplateRuntime.newStringTemplate(lookup, "", mt, "", " + ", " = ", ""); - * ... - * int x = 10; - * int y = 20; - * StringTemplate st = (StringTemplate)cs.getTarget().invokeExact(x, y); - * } - * If the string template requires more than - * {@link java.lang.invoke.StringConcatFactory#MAX_INDY_CONCAT_ARG_SLOTS} value slots, - * then the java compiler will use the - * {@link java.lang.runtime.TemplateRuntime#newLargeStringTemplate} bootstrap method - * instead. For example, the java compiler will translate the following code; - * {@snippet : - * int[] a = new int[1000], b = new int[1000]; - * ... - * StringTemplate st = """ - * \{a[0]} - \{b[0]} - * \{a[1]} - \{b[1]} - * ... - * \{a[999]} - \{b[999]} - * """; - * } - * to byte code that invokes the {@link java.lang.runtime.TemplateRuntime#newLargeStringTemplate} - * bootstrap method to construct a {@link CallSite} that accepts an array of integers and produces a new - * {@link StringTemplate} instance. - * {@snippet : - * MethodType mt = MethodType.methodType(StringTemplate.class, String[].class, Object[].class); - * CallSite cs = TemplateRuntime.newStringTemplate(lookup, "", mt); - * ... - * int[] a = new int[1000], b = new int[1000]; - * ... - * StringTemplate st = (StringTemplate)cs.getTarget().invokeExact( - * new String[] { "", " - ", "\n", " - ", "\n", ... " - ", "\n" }, - * new Object[] { a[0], b[0], a[1], b[1], ..., a[999], b[999]} - * ); - * } - * - * @since 21 - */ -@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) -public final class TemplateRuntime { - private static final JavaTemplateAccess JTA = SharedSecrets.getJavaTemplateAccess(); - - /** - * {@link MethodHandle} to {@link TemplateRuntime#defaultProcess}. - */ - private static final MethodHandle DEFAULT_PROCESS_MH; - - /** - * {@link MethodHandle} to {@link TemplateRuntime#newTrustedStringTemplate}. - */ - private static final MethodHandle NEW_TRUSTED_STRING_TEMPLATE; - - /** - * Initialize {@link MethodHandle MethodHandles}. - */ - static { - try { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - - MethodType mt = MethodType.methodType(Object.class, - List.class, Processor.class, Object[].class); - DEFAULT_PROCESS_MH = - lookup.findStatic(TemplateRuntime.class, "defaultProcess", mt); - - mt = MethodType.methodType(StringTemplate.class, String[].class, Object[].class); - NEW_TRUSTED_STRING_TEMPLATE = - lookup.findStatic(StringTemplateImplFactory.class, "newTrustedStringTemplate", mt); - } catch (ReflectiveOperationException ex) { - throw new AssertionError("string bootstrap fail", ex); - } - } - - /** - * Private constructor. - */ - private TemplateRuntime() { - throw new AssertionError("private constructor"); - } - - /** - * String template bootstrap method for creating string templates. - * The static arguments include the fragments list. - * The non-static arguments are the values. - * - * @param lookup method lookup from call site - * @param name method name - not used - * @param type method type - * (ptypes...) -> StringTemplate - * @param fragments fragment array for string template - * - * @return {@link CallSite} to handle create string template - * - * @throws NullPointerException if any of the arguments is null - * @throws Throwable if linkage fails - */ - public static CallSite newStringTemplate(MethodHandles.Lookup lookup, - String name, - MethodType type, - String... fragments) throws Throwable { - Objects.requireNonNull(lookup, "lookup is null"); - Objects.requireNonNull(name, "name is null"); - Objects.requireNonNull(type, "type is null"); - Objects.requireNonNull(fragments, "fragments is null"); - - MethodHandle mh = StringTemplateImplFactory - .createStringTemplateImplMH(List.of(fragments), type).asType(type); - - return new ConstantCallSite(mh); - } - - /** - * String template bootstrap method for creating large string templates, - * i.e., when the number of value slots exceeds - * {@link java.lang.invoke.StringConcatFactory#MAX_INDY_CONCAT_ARG_SLOTS}. - * The non-static arguments are the fragments array and values array. - * - * @param lookup method lookup from call site - * @param name method name - not used - * @param type method type - * (String[], Object[]) -> StringTemplate - * - * @return {@link CallSite} to handle create large string template - * - * @throws NullPointerException if any of the arguments is null - * @throws Throwable if linkage fails - */ - public static CallSite newLargeStringTemplate(MethodHandles.Lookup lookup, - String name, - MethodType type) throws Throwable { - Objects.requireNonNull(lookup, "lookup is null"); - Objects.requireNonNull(name, "name is null"); - Objects.requireNonNull(type, "type is null"); - - return new ConstantCallSite(NEW_TRUSTED_STRING_TEMPLATE.asType(type)); - } - - /** - * String template bootstrap method for static final processors. - * The static arguments include the fragments array and a {@link MethodHandle} - * to retrieve the value of the static final processor. - * The non-static arguments are the values. - * - * @param lookup method lookup from call site - * @param name method name - not used - * @param type method type - * (ptypes...) -> Object - * @param processorGetter {@link MethodHandle} to get static final processor - * @param fragments fragments from string template - * - * @return {@link CallSite} to handle string template processing - * - * @throws NullPointerException if any of the arguments is null - * @throws Throwable if linkage fails - * - * @implNote this method is likely to be revamped before exiting preview. - */ - public static CallSite processStringTemplate(MethodHandles.Lookup lookup, - String name, - MethodType type, - MethodHandle processorGetter, - String... fragments) throws Throwable { - Objects.requireNonNull(lookup, "lookup is null"); - Objects.requireNonNull(name, "name is null"); - Objects.requireNonNull(type, "type is null"); - Objects.requireNonNull(processorGetter, "processorGetter is null"); - Objects.requireNonNull(fragments, "fragments is null"); - - Processor processor = (Processor)processorGetter.invoke(); - MethodHandle mh = processor instanceof Linkage linkage - ? linkage.linkage(List.of(fragments), type) - : defaultProcessMethodHandle(type, processor, List.of(fragments)); - - return new ConstantCallSite(mh); - } - - /** - * Creates a simple {@link StringTemplate} and then invokes the processor's process method. - * - * @param fragments fragments from string template - * @param processor {@link Processor} to process - * @param values array of expression values - * - * @return result of processing the string template - * - * @throws Throwable when {@link Processor#process(StringTemplate)} throws - */ - private static Object defaultProcess( - List fragments, - Processor processor, - Object[] values - ) throws Throwable { - return processor.process(StringTemplate.of(fragments, Arrays.stream(values).toList())); - } - - /** - * Generate a {@link MethodHandle} which is effectively invokes - * {@code processor.process(new StringTemplate(fragments, values...)}. - * - * @return default process {@link MethodHandle} - */ - private static MethodHandle defaultProcessMethodHandle( - MethodType type, - Processor processor, - List fragments - ) { - MethodHandle mh = MethodHandles.insertArguments(DEFAULT_PROCESS_MH, 0, fragments, processor); - return mh.asCollector(Object[].class, type.parameterCount()).asType(type); - } -} - diff --git a/src/java.base/share/classes/java/lang/runtime/TemplateSupport.java b/src/java.base/share/classes/java/lang/runtime/TemplateSupport.java deleted file mode 100644 index a754e69d794..00000000000 --- a/src/java.base/share/classes/java/lang/runtime/TemplateSupport.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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.util.Iterator; -import java.util.List; -import java.util.Objects; - -import jdk.internal.access.JavaLangAccess; -import jdk.internal.access.JavaTemplateAccess; -import jdk.internal.access.SharedSecrets; - -/** - * This class provides runtime support for string templates. The methods within - * are intended for internal use only. - * - * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. - */ -final class TemplateSupport implements JavaTemplateAccess { - - /** - * Private constructor. - */ - private TemplateSupport() { - } - - static { - SharedSecrets.setJavaTemplateAccess(new TemplateSupport()); - } - - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - - /** - * Returns a StringTemplate composed from fragments and values. - * - * @implSpec The {@code fragments} list size must be one more that the - * {@code values} list size. - * - * @param fragments list of string fragments - * @param values list of expression values - * - * @return StringTemplate composed from fragments and values - * - * @throws IllegalArgumentException if fragments list size is not one more - * than values list size - * @throws NullPointerException if fragments is null or values is null or if any fragment is null. - * - * @implNote Contents of both lists are copied to construct immutable lists. - */ - @Override - public StringTemplate of(List fragments, List values) { - return StringTemplateImplFactory.newStringTemplate(fragments, values); - } - - /** - * Creates a string that interleaves the elements of values between the - * elements of fragments. - * - * @param fragments list of String fragments - * @param values list of expression values - * - * @return String interpolation of fragments and values - */ - @Override - public String interpolate(List fragments, List values) { - int fragmentsSize = fragments.size(); - int valuesSize = values.size(); - if (fragmentsSize == 1) { - return fragments.get(0); - } - int size = fragmentsSize + valuesSize; - String[] strings = new String[size]; - int i = 0, j = 0; - for (; j < valuesSize; j++) { - strings[i++] = fragments.get(j); - strings[i++] = String.valueOf(values.get(j)); - } - strings[i] = fragments.get(j); - return JLA.join("", "", "", strings, size); - } - - /** - * Combine one or more {@link StringTemplate StringTemplates} to produce a combined {@link StringTemplate}. - * {@snippet : - * StringTemplate st = StringTemplate.combine("\{a}", "\{b}", "\{c}"); - * assert st.interpolate().equals("\{a}\{b}\{c}"); - * } - * - * @param sts zero or more {@link StringTemplate} - * - * @return combined {@link StringTemplate} - * - * @throws NullPointerException if sts is null or if any element of sts is null - */ - @Override - public StringTemplate combine(StringTemplate... sts) { - Objects.requireNonNull(sts, "sts must not be null"); - if (sts.length == 0) { - return StringTemplate.of(""); - } else if (sts.length == 1) { - return Objects.requireNonNull(sts[0], "string templates should not be null"); - } - int size = 0; - for (StringTemplate st : sts) { - Objects.requireNonNull(st, "string templates should not be null"); - size += st.values().size(); - } - String[] combinedFragments = new String[size + 1]; - Object[] combinedValues = new Object[size]; - combinedFragments[0] = ""; - int fragmentIndex = 1; - int valueIndex = 0; - for (StringTemplate st : sts) { - Iterator iterator = st.fragments().iterator(); - combinedFragments[fragmentIndex - 1] += iterator.next(); - while (iterator.hasNext()) { - combinedFragments[fragmentIndex++] = iterator.next(); - } - for (Object value : st.values()) { - combinedValues[valueIndex++] = value; - } - } - return StringTemplateImplFactory.newTrustedStringTemplate(combinedFragments, combinedValues); - } - -} diff --git a/src/java.base/share/classes/java/util/FormatItem.java b/src/java.base/share/classes/java/util/FormatItem.java deleted file mode 100644 index adf8ef9ddd3..00000000000 --- a/src/java.base/share/classes/java/util/FormatItem.java +++ /dev/null @@ -1,540 +0,0 @@ -/* - * 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.util; - -import java.io.IOException; -import java.lang.invoke.*; -import java.lang.invoke.MethodHandles.Lookup; -import java.nio.ByteOrder; -import java.nio.charset.StandardCharsets; -import java.text.DecimalFormatSymbols; -import java.util.Formatter.FormatSpecifier; - -import jdk.internal.access.JavaLangAccess; -import jdk.internal.access.SharedSecrets; -import jdk.internal.util.FormatConcatItem; -import jdk.internal.util.DecimalDigits; -import jdk.internal.util.HexDigits; -import jdk.internal.util.OctalDigits; - -import static java.lang.invoke.MethodType.methodType; - -/** - * A specialized objects used by FormatterBuilder that knows how to insert - * themselves into a concatenation performed by StringConcatFactory. - * - * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. - */ -class FormatItem { - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - - private static final MethodHandle CHAR_MIX = - JLA.stringConcatHelper("mix", - MethodType.methodType(long.class, long.class,char.class)); - - private static final MethodHandle STRING_PREPEND = - JLA.stringConcatHelper("prepend", - MethodType.methodType(long.class, long.class, byte[].class, - String.class)); - - private static final MethodHandle SELECT_GETCHAR_MH = - JLA.stringConcatHelper("selectGetChar", - MethodType.methodType(MethodHandle.class, long.class)); - - private static final MethodHandle SELECT_PUTCHAR_MH = - JLA.stringConcatHelper("selectPutChar", - MethodType.methodType(MethodHandle.class, long.class)); - - private static long charMix(long lengthCoder, char value) { - try { - return (long)CHAR_MIX.invokeExact(lengthCoder, value); - } catch (Error | RuntimeException ex) { - throw ex; - } catch (Throwable ex) { - throw new RuntimeException(ex); - } - } - - private static long stringMix(long lengthCoder, String value) { - return JLA.stringConcatMix(lengthCoder, value); - } - - private static long stringPrepend(long lengthCoder, byte[] buffer, - String value) throws Throwable { - return (long)STRING_PREPEND.invokeExact(lengthCoder, buffer, value); - } - - private static MethodHandle selectGetChar(long indexCoder) throws Throwable { - return (MethodHandle)SELECT_GETCHAR_MH.invokeExact(indexCoder); - } - - private static MethodHandle selectPutChar(long indexCoder) throws Throwable { - return (MethodHandle)SELECT_PUTCHAR_MH.invokeExact(indexCoder); - } - - private static final MethodHandle PUT_CHAR_DIGIT; - - static { - try { - Lookup lookup = MethodHandles.lookup(); - PUT_CHAR_DIGIT = lookup.findStatic(FormatItem.class, "putByte", - MethodType.methodType(void.class, - byte[].class, int.class, int.class)); - } catch (ReflectiveOperationException ex) { - throw new AssertionError("putByte lookup failed", ex); - } - } - - private static void putByte(byte[] buffer, int index, int ch) { - buffer[index] = (byte)ch; - } - - private FormatItem() { - throw new AssertionError("private constructor"); - } - - /** - * Decimal value format item. - */ - static final class FormatItemDecimal implements FormatConcatItem { - private final char groupingSeparator; - private final char zeroDigit; - private final char minusSign; - private final int digitOffset; - private final byte[] digits; - private final int length; - private final boolean isNegative; - private final int width; - private final byte prefixSign; - private final int groupSize; - private final long value; - private final boolean parentheses; - - FormatItemDecimal(DecimalFormatSymbols dfs, int width, char sign, - boolean parentheses, int groupSize, long value) throws Throwable { - this.groupingSeparator = dfs.getGroupingSeparator(); - this.zeroDigit = dfs.getZeroDigit(); - this.minusSign = dfs.getMinusSign(); - this.digitOffset = this.zeroDigit - '0'; - int length = DecimalDigits.INSTANCE.size(value); - this.digits = new byte[length]; - DecimalDigits.INSTANCE.digits(value, this.digits, length, PUT_CHAR_DIGIT); - this.isNegative = value < 0L; - this.length = this.isNegative ? length - 1 : length; - this.width = width; - this.groupSize = groupSize; - this.value = value; - this.parentheses = parentheses && isNegative; - this.prefixSign = (byte)(isNegative ? (parentheses ? '\0' : minusSign) : sign); - } - - private int signLength() { - return (prefixSign != '\0' ? 1 : 0) + (parentheses ? 2 : 0); - } - - private int groupLength() { - return 0 < groupSize ? (length - 1) / groupSize : 0; - } - - @Override - public long mix(long lengthCoder) { - return JLA.stringConcatCoder(zeroDigit) | - (lengthCoder + - Integer.max(length + signLength() + groupLength(), width)); - } - - @Override - public long prepend(long lengthCoder, byte[] buffer) throws Throwable { - MethodHandle putCharMH = selectPutChar(lengthCoder); - - if (parentheses) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)')'); - } - - if (0 < groupSize) { - int groupIndex = groupSize; - - for (int i = 1; i <= length; i++) { - if (groupIndex-- == 0) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, - (int)groupingSeparator); - groupIndex = groupSize - 1; - } - - putCharMH.invokeExact(buffer, (int)--lengthCoder, - digits[digits.length - i] + digitOffset); - } - } else { - for (int i = 1; i <= length; i++) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, - digits[digits.length - i] + digitOffset); - } - } - - for (int i = length + signLength() + groupLength(); i < width; i++) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'0'); - } - - if (parentheses) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'('); - } - if (prefixSign != '\0') { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)prefixSign); - } - - return lengthCoder; - } - } - - /** - * Hexadecimal format item. - */ - static final class FormatItemHexadecimal implements FormatConcatItem { - private final int width; - private final boolean hasPrefix; - private final long value; - private final int length; - - FormatItemHexadecimal(int width, boolean hasPrefix, long value) { - this.width = width; - this.hasPrefix = hasPrefix; - this.value = value; - this.length = HexDigits.INSTANCE.size(value); - } - - private int prefixLength() { - return hasPrefix ? 2 : 0; - } - - private int zeroesLength() { - return Integer.max(0, width - length - prefixLength()); - } - - @Override - public long mix(long lengthCoder) { - return lengthCoder + length + prefixLength() + zeroesLength(); - } - - @Override - public long prepend(long lengthCoder, byte[] buffer) throws Throwable { - MethodHandle putCharMH = selectPutChar(lengthCoder); - HexDigits.INSTANCE.digits(value, buffer, (int)lengthCoder, putCharMH); - lengthCoder -= length; - - for (int i = 0; i < zeroesLength(); i++) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'0'); - } - - if (hasPrefix) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'x'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'0'); - } - - return lengthCoder; - } - } - - /** - * Hexadecimal format item. - */ - static final class FormatItemOctal implements FormatConcatItem { - private final int width; - private final boolean hasPrefix; - private final long value; - private final int length; - - FormatItemOctal(int width, boolean hasPrefix, long value) { - this.width = width; - this.hasPrefix = hasPrefix; - this.value = value; - this.length = OctalDigits.INSTANCE.size(value); - } - - private int prefixLength() { - return hasPrefix && value != 0 ? 1 : 0; - } - - private int zeroesLength() { - return Integer.max(0, width - length - prefixLength()); - } - - @Override - public long mix(long lengthCoder) { - return lengthCoder + length + prefixLength() + zeroesLength(); - } - - @Override - public long prepend(long lengthCoder, byte[] buffer) throws Throwable { - MethodHandle putCharMH = selectPutChar(lengthCoder); - OctalDigits.INSTANCE.digits(value, buffer, (int)lengthCoder, putCharMH); - lengthCoder -= length; - - for (int i = 0; i < zeroesLength(); i++) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'0'); - } - - if (hasPrefix && value != 0) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'0'); - } - - return lengthCoder; - } - } - - /** - * Boolean format item. - */ - static final class FormatItemBoolean implements FormatConcatItem { - private final boolean value; - - FormatItemBoolean(boolean value) { - this.value = value; - } - - @Override - public long mix(long lengthCoder) { - return lengthCoder + (value ? "true".length() : "false".length()); - } - - @Override - public long prepend(long lengthCoder, byte[] buffer) throws Throwable { - MethodHandle putCharMH = selectPutChar(lengthCoder); - - if (value) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'e'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'u'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'r'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'t'); - } else { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'e'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'s'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'l'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'a'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'f'); - } - - return lengthCoder; - } - } - - /** - * Character format item. - */ - static final class FormatItemCharacter implements FormatConcatItem { - private final char value; - - FormatItemCharacter(char value) { - this.value = value; - } - - @Override - public long mix(long lengthCoder) { - return charMix(lengthCoder, value); - } - - @Override - public long prepend(long lengthCoder, byte[] buffer) throws Throwable { - MethodHandle putCharMH = selectPutChar(lengthCoder); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)value); - - return lengthCoder; - } - } - - /** - * String format item. - */ - static final class FormatItemString implements FormatConcatItem { - private String value; - - FormatItemString(String value) { - this.value = value; - } - - @Override - public long mix(long lengthCoder) { - return stringMix(lengthCoder, value); - } - - @Override - public long prepend(long lengthCoder, byte[] buffer) throws Throwable { - return stringPrepend(lengthCoder, buffer, value); - } - } - - /** - * FormatSpecifier format item. - */ - static final class FormatItemFormatSpecifier implements FormatConcatItem { - private StringBuilder sb; - - FormatItemFormatSpecifier(FormatSpecifier fs, Locale locale, Object value) { - this.sb = new StringBuilder(64); - Formatter formatter = new Formatter(this.sb, locale); - - try { - fs.print(formatter, value, locale); - } catch (IOException ex) { - throw new AssertionError("FormatItemFormatSpecifier IOException", ex); - } - } - - FormatItemFormatSpecifier(Locale locale, - int flags, int width, int precision, - Formattable formattable) { - this.sb = new StringBuilder(64); - Formatter formatter = new Formatter(this.sb, locale); - formattable.formatTo(formatter, flags, width, precision); - } - - @Override - public long mix(long lengthCoder) { - return JLA.stringBuilderConcatMix(lengthCoder, sb); - } - - @Override - public long prepend(long lengthCoder, byte[] buffer) throws Throwable { - return JLA.stringBuilderConcatPrepend(lengthCoder, buffer, sb); - } - } - - abstract static sealed class FormatItemModifier implements FormatConcatItem - permits FormatItemFillLeft, - FormatItemFillRight - { - private final long itemLengthCoder; - protected final FormatConcatItem item; - - FormatItemModifier(FormatConcatItem item) { - this.itemLengthCoder = item.mix(0L); - this.item = item; - } - - int length() { - return (int)itemLengthCoder; - } - - long coder() { - return itemLengthCoder & ~Integer.MAX_VALUE; - } - - @Override - public abstract long mix(long lengthCoder); - - @Override - public abstract long prepend(long lengthCoder, byte[] buffer) throws Throwable; - } - - /** - * Fill left format item. - */ - static final class FormatItemFillLeft extends FormatItemModifier - implements FormatConcatItem { - private final int width; - - FormatItemFillLeft(int width, FormatConcatItem item) { - super(item); - this.width = Integer.max(length(), width); - } - - @Override - public long mix(long lengthCoder) { - return (lengthCoder | coder()) + width; - } - - @Override - public long prepend(long lengthCoder, byte[] buffer) throws Throwable { - MethodHandle putCharMH = selectPutChar(lengthCoder); - lengthCoder = item.prepend(lengthCoder, buffer); - - for (int i = length(); i < width; i++) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)' '); - } - - return lengthCoder; - } - } - - /** - * Fill right format item. - */ - static final class FormatItemFillRight extends FormatItemModifier - implements FormatConcatItem { - private final int width; - - FormatItemFillRight(int width, FormatConcatItem item) { - super(item); - this.width = Integer.max(length(), width); - } - - @Override - public long mix(long lengthCoder) { - return (lengthCoder | coder()) + width; - } - - @Override - public long prepend(long lengthCoder, byte[] buffer) throws Throwable { - MethodHandle putCharMH = selectPutChar(lengthCoder); - - for (int i = length(); i < width; i++) { - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)' '); - } - - lengthCoder = item.prepend(lengthCoder, buffer); - - return lengthCoder; - } - } - - - /** - * Null format item. - */ - static final class FormatItemNull implements FormatConcatItem { - FormatItemNull() { - } - - @Override - public long mix(long lengthCoder) { - return lengthCoder + "null".length(); - } - - @Override - public long prepend(long lengthCoder, byte[] buffer) throws Throwable { - MethodHandle putCharMH = selectPutChar(lengthCoder); - - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'l'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'l'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'u'); - putCharMH.invokeExact(buffer, (int)--lengthCoder, (int)'n'); - - return lengthCoder; - } - } -} diff --git a/src/java.base/share/classes/java/util/FormatProcessor.java b/src/java.base/share/classes/java/util/FormatProcessor.java deleted file mode 100644 index 20fbc1cedcf..00000000000 --- a/src/java.base/share/classes/java/util/FormatProcessor.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023, Alibaba Group Holding Limited. 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.util; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.StringTemplate.Processor; -import java.lang.StringTemplate.Processor.Linkage; - -import jdk.internal.javac.PreviewFeature; - -/** - * This {@link Processor} constructs a {@link String} result using - * {@link Formatter} specifications and values found in the {@link StringTemplate}. - * Unlike {@link Formatter}, {@link FormatProcessor} uses the value from the - * embedded expression that immediately follows, without whitespace, the - * format specifier. - * For example: - * {@snippet : - * FormatProcessor fmt = FormatProcessor.create(Locale.ROOT); - * int x = 10; - * int y = 20; - * String result = fmt."%05d\{x} + %05d\{y} = %05d\{x + y}"; - * } - * In the above example, the value of {@code result} will be {@code "00010 + 00020 = 00030"}. - *

- * Embedded expressions without a preceeding format specifier, use {@code %s} - * by default. - * {@snippet : - * FormatProcessor fmt = FormatProcessor.create(Locale.ROOT); - * int x = 10; - * int y = 20; - * String result1 = fmt."\{x} + \{y} = \{x + y}"; - * String result2 = fmt."%s\{x} + %s\{y} = %s\{x + y}"; - * } - * In the above example, the value of {@code result1} and {@code result2} will - * both be {@code "10 + 20 = 30"}. - *

- * The {@link FormatProcessor} format specification used and exceptions thrown are the - * same as those of {@link Formatter}. - *

- * However, there are two significant differences related to the position of arguments. - * An explict {@code n$} and relative {@code <} index will cause an exception due to - * a missing argument list. - * Whitespace appearing between the specification and the embedded expression will - * also cause an exception. - *

- * {@link FormatProcessor} allows the use of different locales. For example: - * {@snippet : - * Locale locale = Locale.forLanguageTag("th-TH-u-nu-thai"); - * FormatProcessor thaiFMT = FormatProcessor.create(locale); - * int x = 10; - * int y = 20; - * String result = thaiFMT."%4d\{x} + %4d\{y} = %5d\{x + y}"; - * } - * In the above example, the value of {@code result} will be - * {@code " \u0E51\u0E50 + \u0E52\u0E50 = \u0E53\u0E50"}. - *

- * For day to day use, the predefined {@link FormatProcessor#FMT} {@link FormatProcessor} - * is available. {@link FormatProcessor#FMT} is defined using the {@link Locale#ROOT}. - * Example: {@snippet : - * int x = 10; - * int y = 20; - * String result = FMT."0x%04x\{x} + 0x%04x\{y} = 0x%04x\{x + y}"; // @highlight substring="FMT" - * } - * In the above example, the value of {@code result} will be {@code "0x000a + 0x0014 = 0x001E"}. - * - * @since 21 - * - * @see Processor - */ -@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) -public final class FormatProcessor implements Processor, Linkage { - /** - * {@link Locale} used to format - */ - private final Locale locale; - - /** - * Constructor. - * - * @param locale {@link Locale} used to format - */ - private FormatProcessor(Locale locale) { - this.locale = locale; - } - - /** - * Create a new {@link FormatProcessor} using the specified locale. - * - * @param locale {@link Locale} used to format - * - * @return a new instance of {@link FormatProcessor} - * - * @throws java.lang.NullPointerException if locale is null - */ - public static FormatProcessor create(Locale locale) { - Objects.requireNonNull(locale); - return new FormatProcessor(locale); - } - - /** - * Constructs a {@link String} based on the fragments, format - * specifications found in the fragments and values in the - * supplied {@link StringTemplate} object. This method constructs a - * format string from the fragments, gathers up the values and - * evaluates the expression asif evaulating - * {@code new Formatter(locale).format(format, values).toString()}. - *

- * If an embedded expression is not immediately preceded by a - * specifier then a {@code %s} is inserted in the format. - * - * @param stringTemplate a {@link StringTemplate} instance - * - * @return constructed {@link String} - - * @throws IllegalFormatException - * If a format specifier contains an illegal syntax, a format - * specifier that is incompatible with the given arguments, - * a specifier not followed immediately by an embedded expression or - * other illegal conditions. For specification of all possible - * formatting errors, see the - * details - * section of the formatter class specification. - * @throws NullPointerException if stringTemplate is null - * - * @see java.util.Formatter - */ - @Override - public final String process(StringTemplate stringTemplate) { - Objects.requireNonNull(stringTemplate); - String format = stringTemplateFormat(stringTemplate.fragments()); - Object[] values = stringTemplate.values().toArray(); - - return new Formatter(locale).format(format, values).toString(); - } - - /** - * Constructs a {@link MethodHandle} that when supplied with the values from - * a {@link StringTemplate} will produce a result equivalent to that provided by - * {@link FormatProcessor#process(StringTemplate)}. This {@link MethodHandle} - * is used by {@link FormatProcessor#FMT} and the ilk to perform a more - * specialized composition of a result. This specialization is done by - * prescanning the fragments and value types of a {@link StringTemplate}. - *

- * Process template expressions can be specialized when the processor is - * of type {@link Linkage} and fetched from a static constant as is - * {@link FormatProcessor#FMT} ({@code static final FormatProcessor}). - *

- * Other {@link FormatProcessor FormatProcessors} can be specialized when stored in a static - * final. - * For example: - * {@snippet : - * FormatProcessor THAI_FMT = FormatProcessor.create(Locale.forLanguageTag("th-TH-u-nu-thai")); - * } - * {@code THAI_FMT} will now produce specialized {@link MethodHandle MethodHandles} by way - * of {@link FormatProcessor#linkage(List, MethodType)}. - * - * See {@link FormatProcessor#process(StringTemplate)} for more information. - * - * @throws IllegalFormatException - * If a format specifier contains an illegal syntax, a format - * specifier that is incompatible with the given arguments, - * a specifier not followed immediately by an embedded expression or - * other illegal conditions. For specification of all possible - * formatting errors, see the - * details - * section of the formatter class specification. - * @throws NullPointerException if fragments or type is null - * - * @see java.util.Formatter - */ - @Override - public MethodHandle linkage(List fragments, MethodType type) { - Objects.requireNonNull(fragments); - Objects.requireNonNull(type); - String format = stringTemplateFormat(fragments); - Class[] ptypes = type.dropParameterTypes(0, 1).parameterArray(); - MethodHandle mh = new FormatterBuilder(format, locale, ptypes).build(); - mh = MethodHandles.dropArguments(mh, 0, type.parameterType(0)); - - return mh; - } - - /** - * Find a format specification at the end of a fragment. - * - * @param fragment fragment to check - * @param needed if the specification is needed - * - * @return true if the specification is found and needed - * - * @throws MissingFormatArgumentException if not at end or found and not needed - */ - private static boolean findFormat(String fragment, boolean needed) { - int max = fragment.length(); - for (int i = 0; i < max;) { - int n = fragment.indexOf('%', i); - if (n < 0) { - return false; - } - - i = n + 1; - if (i >= max) { - return false; - } - - char c = fragment.charAt(i); - if (c == '%' || c == 'n') { - i++; - continue; - } - int off = new Formatter.FormatSpecifierParser(null, c, i, fragment, max) - .parse(); - if (off == 0) { - return false; - } - if (i + off == max && needed) { - return true; - } - throw new MissingFormatArgumentException( - fragment.substring(i - 1, i + off) - + " is not immediately followed by an embedded expression"); - } - return false; - } - - /** - * Convert {@link StringTemplate} fragments, containing format specifications, - * to a form that can be passed on to {@link Formatter}. The method scans each fragment, - * matching up formatter specifications with the following expression. If no - * specification is found, the method inserts "%s". - * - * @param fragments string template fragments - * - * @return format string - */ - private static String stringTemplateFormat(List fragments) { - StringBuilder sb = new StringBuilder(); - int lastIndex = fragments.size() - 1; - List formats = fragments.subList(0, lastIndex); - String last = fragments.get(lastIndex); - - for (String format : formats) { - if (findFormat(format, true)) { - sb.append(format); - } else { - sb.append(format); - sb.append("%s"); - } - } - - if (!findFormat(last, false)) { - sb.append(last); - } - - return sb.toString(); - } - - /** - * This predefined {@link FormatProcessor} instance constructs a {@link String} result using - * the Locale.ROOT {@link Locale}. See {@link FormatProcessor} for more details. - * Example: {@snippet : - * int x = 10; - * int y = 20; - * String result = FMT."0x%04x\{x} + 0x%04x\{y} = 0x%04x\{x + y}"; // @highlight substring="FMT" - * } - * In the above example, the value of {@code result} will be {@code "0x000a + 0x0014 = 0x001E"}. - * - * @see java.util.FormatProcessor - */ - public static final FormatProcessor FMT = FormatProcessor.create(Locale.ROOT); - -} diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java index 3f37774469d..a7d95ee5780 100644 --- a/src/java.base/share/classes/java/util/Formatter.java +++ b/src/java.base/share/classes/java/util/Formatter.java @@ -61,7 +61,6 @@ import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQueries; import java.time.temporal.UnsupportedTemporalTypeException; -import jdk.internal.javac.PreviewFeature; import jdk.internal.math.DoubleConsts; import jdk.internal.math.FormattedFPDecimal; import sun.util.locale.provider.LocaleProviderAdapter; diff --git a/src/java.base/share/classes/java/util/FormatterBuilder.java b/src/java.base/share/classes/java/util/FormatterBuilder.java deleted file mode 100644 index 854fdfef68d..00000000000 --- a/src/java.base/share/classes/java/util/FormatterBuilder.java +++ /dev/null @@ -1,489 +0,0 @@ -/* - * 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.util; - -import java.io.IOException; -import java.lang.invoke.*; -import java.lang.invoke.MethodHandles.Lookup; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.text.NumberFormat; -import java.text.spi.NumberFormatProvider; -import java.util.FormatItem.*; -import java.util.Formatter.*; - -import jdk.internal.util.FormatConcatItem; - -import sun.invoke.util.Wrapper; -import sun.util.locale.provider.LocaleProviderAdapter; -import sun.util.locale.provider.ResourceBundleBasedAdapter; - -import static java.util.Formatter.Conversion.*; -import static java.util.Formatter.Flags.*; -import static java.lang.invoke.MethodHandles.*; -import static java.lang.invoke.MethodType.*; - -/** - * This package private class supports the construction of the {@link MethodHandle} - * used by {@link FormatProcessor}. - * - * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. - */ -final class FormatterBuilder { - private static final Lookup LOOKUP = lookup(); - - private final String format; - private final Locale locale; - private final Class[] ptypes; - private final DecimalFormatSymbols dfs; - private final boolean isGenericDFS; - - FormatterBuilder(String format, Locale locale, Class[] ptypes) { - this.format = format; - this.locale = locale; - this.ptypes = ptypes; - this.dfs = DecimalFormatSymbols.getInstance(locale); - this.isGenericDFS = isGenericDFS(this.dfs); - } - - private static boolean isGenericDFS(DecimalFormatSymbols dfs) { - return dfs.getZeroDigit() == '0' && - dfs.getDecimalSeparator() == '.' && - dfs.getGroupingSeparator() == ',' && - dfs.getMinusSign() == '-'; - } - - private static Class mapType(Class type) { - return type.isPrimitive() || type == String.class ? type : Object.class; - } - - private static MethodHandle findStringConcatItemConstructor(Class cls, - Class... ptypes) { - MethodType methodType = methodType(void.class, ptypes); - - try { - MethodHandle mh = LOOKUP.findConstructor(cls, methodType); - - return mh.asType(mh.type().changeReturnType(FormatConcatItem.class)); - } catch (ReflectiveOperationException e) { - throw new AssertionError("Missing constructor in " + - cls + ": " + methodType); - } - } - - private static MethodHandle findMethod(Class cls, String name, - Class rType, Class... ptypes) { - MethodType methodType = methodType(rType, ptypes); - - try { - return LOOKUP.findVirtual(cls, name, methodType); - } catch (ReflectiveOperationException e) { - throw new AssertionError("Missing method in " + - cls + ": " + name + " " + methodType); - } - } - - private static MethodHandle findStaticMethod(Class cls, String name, - Class rType, Class... ptypes) { - MethodType methodType = methodType(rType, ptypes); - - try { - return LOOKUP.findStatic(cls, name, methodType); - } catch (ReflectiveOperationException e) { - throw new AssertionError("Missing static method in " + - cls + ": " + name + " " + methodType); - } - } - - private static final MethodHandle FIDecimal_MH = - findStringConcatItemConstructor(FormatItemDecimal.class, - DecimalFormatSymbols.class, int.class, char.class, boolean.class, - int.class, long.class); - - private static final MethodHandle FIHexadecimal_MH = - findStringConcatItemConstructor(FormatItemHexadecimal.class, - int.class, boolean.class, long.class); - - private static final MethodHandle FIOctal_MH = - findStringConcatItemConstructor(FormatItemOctal.class, - int.class, boolean.class, long.class); - - private static final MethodHandle FIBoolean_MH = - findStringConcatItemConstructor(FormatItemBoolean.class, - boolean.class); - - private static final MethodHandle FICharacter_MH = - findStringConcatItemConstructor(FormatItemCharacter.class, - char.class); - - private static final MethodHandle FIString_MH = - findStringConcatItemConstructor(FormatItemString.class, - String.class); - - private static final MethodHandle FIFormatSpecifier_MH = - findStringConcatItemConstructor(FormatItemFormatSpecifier.class, - FormatSpecifier.class, Locale.class, Object.class); - - private static final MethodHandle FIFormattable_MH = - findStringConcatItemConstructor(FormatItemFormatSpecifier.class, - Locale.class, int.class, int.class, int.class, - Formattable.class); - - private static final MethodHandle FIFillLeft_MH = - findStringConcatItemConstructor(FormatItemFillLeft.class, - int.class, FormatConcatItem.class); - - private static final MethodHandle FIFillRight_MH = - findStringConcatItemConstructor(FormatItemFillRight.class, - int.class, FormatConcatItem.class); - - private static final MethodHandle FINull_MH = - findStringConcatItemConstructor(FormatItemNull.class); - - private static final MethodHandle NullCheck_MH = - findStaticMethod(FormatterBuilder.class, "nullCheck", boolean.class, - Object.class); - - private static final MethodHandle FormattableCheck_MH = - findStaticMethod(FormatterBuilder.class, "formattableCheck", boolean.class, - Object.class); - - private static final MethodHandle ToLong_MH = - findStaticMethod(java.util.FormatterBuilder.class, "toLong", long.class, - int.class); - - private static final MethodHandle ToString_MH = - findStaticMethod(String.class, "valueOf", String.class, - Object.class); - - private static final MethodHandle HashCode_MH = - findStaticMethod(Objects.class, "hashCode", int.class, - Object.class); - - private static boolean nullCheck(Object object) { - return object == null; - } - - private static boolean formattableCheck(Object object) { - return Formattable.class.isAssignableFrom(object.getClass()); - } - - private static long toLong(int value) { - return (long)value & 0xFFFFFFFFL; - } - - private static boolean isFlag(int value, int flags) { - return (value & flags) != 0; - } - - private static boolean validFlags(int value, int flags) { - return (value & ~flags) == 0; - } - - private static int groupSize(Locale locale, DecimalFormatSymbols dfs) { - if (isGenericDFS(dfs)) { - return 3; - } - - DecimalFormat df; - NumberFormat nf = NumberFormat.getNumberInstance(locale); - - if (nf instanceof DecimalFormat) { - df = (DecimalFormat)nf; - } else { - LocaleProviderAdapter adapter = LocaleProviderAdapter - .getAdapter(NumberFormatProvider.class, locale); - - if (!(adapter instanceof ResourceBundleBasedAdapter)) { - adapter = LocaleProviderAdapter.getResourceBundleBased(); - } - - String[] all = adapter.getLocaleResources(locale) - .getNumberPatterns(); - - df = new DecimalFormat(all[0], dfs); - } - - return df.isGroupingUsed() ? df.getGroupingSize() : 0; - } - - private MethodHandle formatSpecifier(FormatSpecifier fs, Class ptype) { - boolean isPrimitive = ptype.isPrimitive(); - MethodHandle mh = identity(ptype); - MethodType mt = mh.type(); - -//cannot cast to primitive types as it breaks null values formatting -// if (ptype == byte.class || ptype == short.class || -// ptype == Byte.class || ptype == Short.class || -// ptype == Integer.class) { -// mt = mt.changeReturnType(int.class); -// } else if (ptype == Long.class) { -// mt = mt.changeReturnType(long.class); -// } else if (ptype == float.class || ptype == Float.class || -// ptype == Double.class) { -// mt = mt.changeReturnType(double.class); -// } else if (ptype == Boolean.class) { -// mt = mt.changeReturnType(boolean.class); -// } else if (ptype == Character.class) { -// mt = mt.changeReturnType(char.class); -// } - - Class itype = mt.returnType(); - - if (itype != ptype) { - mh = explicitCastArguments(mh, mt); - } - - boolean handled = false; - int flags = fs.flags; - int width = fs.width; - int precision = fs.precision; - Character conv = fs.dt ? 't' : fs.c; - - switch (Character.toLowerCase(conv)) { - case BOOLEAN -> { - if (itype == boolean.class && precision == -1) { - if (flags == 0 && width == -1 && isPrimitive) { - return null; - } - - if (validFlags(flags, LEFT_JUSTIFY)) { - handled = true; - mh = filterReturnValue(mh, FIBoolean_MH); - } - } - } - case STRING -> { - if (flags == 0 && width == -1 && precision == -1) { - if (isPrimitive || ptype == String.class) { - return null; - } else if (itype.isPrimitive()) { - return mh; - } - } - - if (validFlags(flags, LEFT_JUSTIFY) && precision == -1) { - if (itype == String.class) { - handled = true; - mh = filterReturnValue(mh, FIString_MH); - } else if (!itype.isPrimitive()) { - handled = true; - MethodHandle test = FormattableCheck_MH; - test = test.asType(test.type().changeParameterType(0, ptype)); - MethodHandle pass = insertArguments(FIFormattable_MH, - 0, locale, flags, width, precision); - pass = pass.asType(pass.type().changeParameterType(0, ptype)); - MethodHandle fail = ToString_MH; - fail = filterReturnValue(fail, FIString_MH); - fail = fail.asType(fail.type().changeParameterType(0, ptype)); - mh = guardWithTest(test, pass, fail); - } - } - } - case CHARACTER -> { - if (itype == char.class && precision == -1) { - if (flags == 0 && width == -1) { - return isPrimitive ? null : mh; - } - - if (validFlags(flags, LEFT_JUSTIFY)) { - handled = true; - mh = filterReturnValue(mh, FICharacter_MH); - } - } - } - case DECIMAL_INTEGER -> { - if ((itype == int.class || itype == long.class) && precision == -1) { - if (itype == int.class) { - mh = explicitCastArguments(mh, - mh.type().changeReturnType(long.class)); - } - - if (flags == 0 && isGenericDFS && width == -1) { - return mh; - } else if (validFlags(flags, PLUS | LEADING_SPACE | - ZERO_PAD | GROUP | - PARENTHESES)) { - handled = true; - int zeroPad = isFlag(flags, ZERO_PAD) ? width : -1; - char sign = isFlag(flags, PLUS) ? '+' : - isFlag(flags, LEADING_SPACE) ? ' ' : '\0'; - boolean parentheses = isFlag(flags, PARENTHESES); - int groupSize = isFlag(flags, GROUP) ? - groupSize(locale, dfs) : 0; - mh = filterReturnValue(mh, - insertArguments(FIDecimal_MH, 0, dfs, zeroPad, - sign, parentheses, groupSize)); - } - } - } - case OCTAL_INTEGER -> { - if ((itype == int.class || itype == long.class) && - precision == -1 && - validFlags(flags, ZERO_PAD | ALTERNATE)) { - handled = true; - - if (itype == int.class) { - mh = filterReturnValue(mh, ToLong_MH); - } - - int zeroPad = isFlag(flags, ZERO_PAD) ? width : -1; - boolean hasPrefix = isFlag(flags, ALTERNATE); - mh = filterReturnValue(mh, - insertArguments(FIOctal_MH, 0, zeroPad, hasPrefix)); - } - } - case HEXADECIMAL_INTEGER -> { - if ((itype == int.class || itype == long.class) && - precision == -1 && - validFlags(flags, ZERO_PAD | ALTERNATE)) { - handled = true; - - if (itype == int.class) { - mh = filterReturnValue(mh, ToLong_MH); - } - - int zeroPad = isFlag(flags, ZERO_PAD) ? width : -1; - boolean hasPrefix = isFlag(flags, ALTERNATE); - mh = filterReturnValue(mh, - insertArguments(FIHexadecimal_MH, 0, zeroPad, hasPrefix)); - } - } - default -> { - // pass thru - } - } - - if (handled) { - if (!isPrimitive) { - MethodHandle test = NullCheck_MH.asType( - NullCheck_MH.type().changeParameterType(0, ptype)); - MethodHandle pass = dropArguments(FINull_MH, 0, ptype); - mh = guardWithTest(test, pass, mh); - } - - if (0 < width) { - if (isFlag(flags, LEFT_JUSTIFY)) { - mh = filterReturnValue(mh, - insertArguments(FIFillRight_MH, 0, width)); - } else { - mh = filterReturnValue(mh, - insertArguments(FIFillLeft_MH, 0, width)); - } - } - - if (!isFlag(flags, UPPERCASE)) { - return mh; - } - } - - mh = insertArguments(FIFormatSpecifier_MH, 0, fs, locale); - mh = mh.asType(mh.type().changeParameterType(0, ptype)); - - return mh; - } - - /** - * Construct concat {@link MethodHandle} for based on format. - * - * @param fsa list of specifiers - * - * @return concat {@link MethodHandle} for based on format - */ - private MethodHandle buildFilters(List fsa, - List segments, - MethodHandle[] filters) { - MethodHandle mh = null; - int iParam = 0; - StringBuilder segment = new StringBuilder(); - - for (FormatString fs : fsa) { - int index = fs.index(); - - switch (index) { - case -2: // fixed string, "%n", or "%%" - String string = fs.toString(); - - if ("%%".equals(string)) { - segment.append('%'); - } else if ("%n".equals(string)) { - segment.append(System.lineSeparator()); - } else { - segment.append(string); - } - break; - case 0: // ordinary index - segments.add(segment.toString()); - segment.setLength(0); - - if (iParam < ptypes.length) { - Class ptype = ptypes[iParam]; - filters[iParam++] = formatSpecifier((FormatSpecifier)fs, ptype); - } else { - throw new MissingFormatArgumentException(fs.toString()); - } - break; - case -1: // relative index - default: // explicit index - throw new IllegalFormatFlagsException("Indexing not allowed: " + fs.toString()); - } - } - - segments.add(segment.toString()); - - return mh; - } - - /** - * Build a {@link MethodHandle} to format arguments. - * - * @return new {@link MethodHandle} to format arguments - */ - MethodHandle build() { - List segments = new ArrayList<>(); - MethodHandle[] filters = new MethodHandle[ptypes.length]; - buildFilters(Formatter.parse(format), segments, filters); - Class[] ftypes = new Class[filters.length]; - - for (int i = 0; i < filters.length; i++) { - MethodHandle filter = filters[i]; - ftypes[i] = filter == null ? ptypes[i] : filter.type().returnType(); - } - - try { - MethodHandle mh = StringConcatFactory.makeConcatWithTemplate(segments, - List.of(ftypes)); - mh = filterArguments(mh, 0, filters); - - return mh; - } catch (StringConcatException ex) { - throw new AssertionError("concat fail", ex); - } - } -} diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index c6200520fdd..af7ff2e4aa2 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -364,6 +364,15 @@ public interface JavaLangAccess { */ char getUTF16Char(byte[] bytes, int index); + /** + * Put the char at index in a byte[] in internal UTF-16 representation, + * with no bounds checks. + * + * @param bytes the UTF-16 encoded bytes + * @param index of the char to retrieve, 0 <= index < (bytes.length >> 1) + */ + void putCharUTF16(byte[] bytes, int index, int ch); + /** * Encode the given string into a sequence of bytes using utf8. * @@ -417,6 +426,12 @@ public interface JavaLangAccess { */ MethodHandle stringConcatHelper(String name, MethodType methodType); + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + */ + long stringConcatHelperPrepend(long indexCoder, byte[] buf, String value); + /** * Get the string concat initial coder */ @@ -427,20 +442,10 @@ public interface JavaLangAccess { */ long stringConcatMix(long lengthCoder, String constant); - /** - * Get the coder for the supplied character. - */ - long stringConcatCoder(char value); - - /** - * Update lengthCoder for StringBuilder. - */ - long stringBuilderConcatMix(long lengthCoder, StringBuilder sb); - /** - * Prepend StringBuilder content. - */ - long stringBuilderConcatPrepend(long lengthCoder, byte[] buf, StringBuilder sb); + * Mix value length and coder into current length and coder. + */ + long stringConcatMix(long lengthCoder, char value); /** * Join strings @@ -454,6 +459,12 @@ public interface JavaLangAccess { */ Object classData(Class c); + int stringSize(long i); + + int getCharsLatin1(long i, int index, byte[] buf); + + int getCharsUTF16(long i, int index, byte[] buf); + long findNative(ClassLoader loader, String entry); /** diff --git a/src/java.base/share/classes/jdk/internal/access/JavaTemplateAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaTemplateAccess.java deleted file mode 100644 index da99f7806d1..00000000000 --- a/src/java.base/share/classes/jdk/internal/access/JavaTemplateAccess.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 jdk.internal.access; - -import java.util.List; - -public interface JavaTemplateAccess { - - /** - * Returns a StringTemplate composed from fragments and values. - * - * @implSpec The {@code fragments} list size must be one more that the - * {@code values} list size. - * - * @param fragments list of string fragments - * @param values list of expression values - * - * @return StringTemplate composed from fragments and values - * - * @throws IllegalArgumentException if fragments list size is not one more - * than values list size - * @throws NullPointerException if fragments is null or values is null or if any fragment is null. - * - * @implNote Contents of both lists are copied to construct immutable lists. - */ - StringTemplate of(List fragments, List values); - - /** - * Creates a string that interleaves the elements of values between the - * elements of fragments. - * - * @param fragments list of String fragments - * @param values list of expression values - * - * @return String interpolation of fragments and values - */ - String interpolate(List fragments, List values); - - /** - * Combine one or more {@link StringTemplate StringTemplates} to produce a combined {@link StringTemplate}. - * {@snippet : - * StringTemplate st = StringTemplate.combine("\{a}", "\{b}", "\{c}"); - * assert st.interpolate().equals("\{a}\{b}\{c}"); - * } - * - * @param sts zero or more {@link StringTemplate} - * - * @return combined {@link StringTemplate} - * - * @throws NullPointerException if sts is null or if any element of sts is null - */ - StringTemplate combine(StringTemplate... sts); - -} - diff --git a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java index eb0a7821d0d..0dacbef993a 100644 --- a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java +++ b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java @@ -91,7 +91,6 @@ public class SharedSecrets { private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess; private static JavaxCryptoSpecAccess javaxCryptoSpecAccess; private static JavaxSecurityAccess javaxSecurityAccess; - private static JavaTemplateAccess javaTemplateAccess; public static void setJavaUtilCollectionAccess(JavaUtilCollectionAccess juca) { javaUtilCollectionAccess = juca; @@ -532,21 +531,6 @@ public class SharedSecrets { return access; } - public static void setJavaTemplateAccess(JavaTemplateAccess jta) { - javaTemplateAccess = jta; - } - - public static JavaTemplateAccess getJavaTemplateAccess() { - var access = javaTemplateAccess; - if (access == null) { - try { - Class.forName("java.lang.runtime.TemplateSupport", true, null); - access = javaTemplateAccess; - } catch (ClassNotFoundException e) {} - } - return access; - } - private static void ensureClassInitialized(Class c) { try { MethodHandles.lookup().ensureInitialized(c); diff --git a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java index f078c7d5726..bdcbe15ea84 100644 --- a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java +++ b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java @@ -25,8 +25,6 @@ package jdk.internal.util; -import java.lang.invoke.MethodHandle; - import jdk.internal.vm.annotation.Stable; /** @@ -34,7 +32,7 @@ import jdk.internal.vm.annotation.Stable; * * @since 21 */ -public final class DecimalDigits implements Digits { +public final class DecimalDigits { /** * Each element of the array represents the packaging of two ascii characters based on little endian:

@@ -72,85 +70,12 @@ public final class DecimalDigits implements Digits { DIGITS = digits; } - /** - * Singleton instance of DecimalDigits. - */ - public static final Digits INSTANCE = new DecimalDigits(); - /** * Constructor. */ private DecimalDigits() { } - @Override - public int digits(long value, byte[] buffer, int index, - MethodHandle putCharMH) throws Throwable { - boolean negative = value < 0; - if (!negative) { - value = -value; - } - - long q; - int r; - while (value <= Integer.MIN_VALUE) { - q = value / 100; - r = (int)((q * 100) - value); - value = q; - int digits = DIGITS[r]; - - putCharMH.invokeExact(buffer, --index, digits >> 8); - putCharMH.invokeExact(buffer, --index, digits & 0xFF); - } - - int iq, ivalue = (int)value; - while (ivalue <= -100) { - iq = ivalue / 100; - r = (iq * 100) - ivalue; - ivalue = iq; - int digits = DIGITS[r]; - putCharMH.invokeExact(buffer, --index, digits >> 8); - putCharMH.invokeExact(buffer, --index, digits & 0xFF); - } - - if (ivalue < 0) { - ivalue = -ivalue; - } - - int digits = DIGITS[ivalue]; - putCharMH.invokeExact(buffer, --index, digits >> 8); - - if (9 < ivalue) { - putCharMH.invokeExact(buffer, --index, digits & 0xFF); - } - - if (negative) { - putCharMH.invokeExact(buffer, --index, (int)'-'); - } - - return index; - } - - @Override - public int size(long value) { - boolean negative = value < 0; - int sign = negative ? 1 : 0; - - if (!negative) { - value = -value; - } - - long precision = -10; - for (int i = 1; i < 19; i++) { - if (value > precision) - return i + sign; - - precision = 10 * precision; - } - - return 19 + sign; - } - /** * For values from 0 to 99 return a short encoding a pair of ASCII-encoded digit characters in little-endian * @param i value to convert diff --git a/src/java.base/share/classes/jdk/internal/util/Digits.java b/src/java.base/share/classes/jdk/internal/util/Digits.java deleted file mode 100644 index e301688ff4e..00000000000 --- a/src/java.base/share/classes/jdk/internal/util/Digits.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 jdk.internal.util; - -import java.lang.invoke.MethodHandle; - -/** - * Digits provides a fast methodology for converting integers and longs to - * ASCII strings. - * - * @since 21 - */ -public sealed interface Digits permits DecimalDigits, HexDigits, OctalDigits { - /** - * Insert digits for long value in buffer from high index to low index. - * - * @param value value to convert - * @param buffer byte buffer to copy into - * @param index insert point + 1 - * @param putCharMH method to put character - * - * @return the last index used - * - * @throws Throwable if putCharMH fails (unusual). - */ - int digits(long value, byte[] buffer, int index, - MethodHandle putCharMH) throws Throwable; - - /** - * Calculate the number of digits required to represent the long. - * - * @param value value to convert - * - * @return number of digits - */ - int size(long value); - -} diff --git a/src/java.base/share/classes/jdk/internal/util/FormatConcatItem.java b/src/java.base/share/classes/jdk/internal/util/FormatConcatItem.java deleted file mode 100644 index b4588968a3e..00000000000 --- a/src/java.base/share/classes/jdk/internal/util/FormatConcatItem.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 jdk.internal.util; - -/** - * Implementations of this class provide information necessary to - * assist {@link java.lang.invoke.StringConcatFactory} perform optimal - * insertion. - * - * @since 21 - * - * Warning: This class is part of PreviewFeature.Feature.STRING_TEMPLATES. - * Do not rely on its availability. - */ -public interface FormatConcatItem { - /** - * Calculate the length of the insertion. - * - * @param lengthCoder current value of the length + coder - * @return adjusted value of the length + coder - */ - long mix(long lengthCoder); - - /** - * Insert content into buffer prior to the current length. - * - * @param lengthCoder current value of the length + coder - * @param buffer buffer to append to - * - * @return adjusted value of the length + coder - * - * @throws Throwable if fails to prepend value (unusual). - */ - long prepend(long lengthCoder, byte[] buffer) throws Throwable; -} diff --git a/src/java.base/share/classes/jdk/internal/util/HexDigits.java b/src/java.base/share/classes/jdk/internal/util/HexDigits.java index 1adda90a65a..075443571e1 100644 --- a/src/java.base/share/classes/jdk/internal/util/HexDigits.java +++ b/src/java.base/share/classes/jdk/internal/util/HexDigits.java @@ -25,16 +25,19 @@ package jdk.internal.util; -import java.lang.invoke.MethodHandle; - +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.vm.annotation.Stable; /** - * Digits class for hexadecimal digits. + * Digits provides a fast methodology for converting integers and longs to + * hexadecimal digits ASCII strings. * * @since 21 */ -public final class HexDigits implements Digits { +public final class HexDigits { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + /** * Each element of the array represents the ascii encoded * hex relative to its index, for example:

@@ -65,11 +68,6 @@ public final class HexDigits implements Digits { @Stable private static final short[] DIGITS; - /** - * Singleton instance of HexDigits. - */ - public static final Digits INSTANCE = new HexDigits(); - static { short[] digits = new short[16 * 16]; @@ -136,28 +134,68 @@ public final class HexDigits implements Digits { | (((long) DIGITS[b3 & 0xff]) << 48); } - @Override - public int digits(long value, byte[] buffer, int index, - MethodHandle putCharMH) throws Throwable { + /** + * Insert digits for long value in buffer from high index to low index. + * + * @param value value to convert + * @param index insert point + 1 + * @param buffer byte buffer to copy into + * + * @return the last index used + */ + public static int getCharsLatin1(long value, int index, byte[] buffer) { while ((value & ~0xFF) != 0) { - int digits = DIGITS[(int) (value & 0xFF)]; + short pair = DIGITS[((int) value) & 0xFF]; + buffer[--index] = (byte)(pair >> 8); + buffer[--index] = (byte)(pair); value >>>= 8; - putCharMH.invokeExact(buffer, --index, digits >> 8); - putCharMH.invokeExact(buffer, --index, digits & 0xFF); } int digits = DIGITS[(int) (value & 0xFF)]; - putCharMH.invokeExact(buffer, --index, digits >> 8); + buffer[--index] = (byte) (digits >> 8); if (0xF < value) { - putCharMH.invokeExact(buffer, --index, digits & 0xFF); + buffer[--index] = (byte) (digits & 0xFF); } return index; } - @Override - public int size(long value) { + /** + * Insert digits for long value in buffer from high index to low index. + * + * @param value value to convert + * @param index insert point + 1 + * @param buffer byte buffer to copy into + * + * @return the last index used + */ + public static int getCharsUTF16(long value, int index, byte[] buffer) { + while ((value & ~0xFF) != 0) { + int pair = (int) DIGITS[((int) value) & 0xFF]; + JLA.putCharUTF16(buffer, --index, pair >> 8); + JLA.putCharUTF16(buffer, --index, pair & 0xFF); + value >>>= 8; + } + + int digits = DIGITS[(int) (value & 0xFF)]; + JLA.putCharUTF16(buffer, --index, (byte) (digits >> 8)); + + if (0xF < value) { + JLA.putCharUTF16(buffer, --index, (byte) (digits & 0xFF)); + } + + return index; + } + + /** + * Calculate the number of digits required to represent the long. + * + * @param value value to convert + * + * @return number of digits + */ + public static int stringSize(long value) { return value == 0 ? 1 : 67 - Long.numberOfLeadingZeros(value) >> 2; } diff --git a/src/java.base/share/classes/jdk/internal/util/OctalDigits.java b/src/java.base/share/classes/jdk/internal/util/OctalDigits.java index 785947442e8..97b1f882f59 100644 --- a/src/java.base/share/classes/jdk/internal/util/OctalDigits.java +++ b/src/java.base/share/classes/jdk/internal/util/OctalDigits.java @@ -25,8 +25,8 @@ package jdk.internal.util; -import java.lang.invoke.MethodHandle; - +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.vm.annotation.Stable; /** @@ -34,15 +34,12 @@ import jdk.internal.vm.annotation.Stable; * * @since 21 */ -public final class OctalDigits implements Digits { +public final class OctalDigits { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + @Stable private static final short[] DIGITS; - /** - * Singleton instance of OctalDigits. - */ - public static final Digits INSTANCE = new OctalDigits(); - static { short[] digits = new short[8 * 8]; @@ -64,28 +61,70 @@ public final class OctalDigits implements Digits { private OctalDigits() { } - @Override - public int digits(long value, byte[] buffer, int index, - MethodHandle putCharMH) throws Throwable { + /** + * Insert digits for long value in buffer from high index to low index. + * + * @param value value to convert + * @param index insert point + 1 + * @param buffer byte buffer to copy into + * + * @return the last index used + */ + public static int getCharsLatin1(long value, int index, byte[] buffer){ while ((value & ~0x3F) != 0) { - int digits = DIGITS[(int) (value & 0x3F)]; + int digits = DIGITS[((int) value) & 0x3F]; value >>>= 6; - putCharMH.invokeExact(buffer, --index, digits >> 8); - putCharMH.invokeExact(buffer, --index, digits & 0xFF); + buffer[--index] = (byte) (digits >> 8); + buffer[--index] = (byte) (digits & 0xFF); } int digits = DIGITS[(int) (value & 0x3F)]; - putCharMH.invokeExact(buffer, --index, digits >> 8); + buffer[--index] = (byte) (digits >> 8); if (7 < value) { - putCharMH.invokeExact(buffer, --index, digits & 0xFF); + buffer[--index] = (byte) (digits & 0xFF); } return index; } - @Override - public int size(long value) { - return (66 - Long.numberOfLeadingZeros(value)) / 3; + + /** + * This is a variant of {@link OctalDigits#getCharsLatin1(long, int, byte[])}, but for + * UTF-16 coder. + * + * @param value value to convert + * @param index insert point + 1 + * @param buffer byte buffer to copy into + * + * @return the last index used + */ + public static int getCharsUTF16(long value, int index, byte[] buffer){ + while ((value & ~0x3F) != 0) { + int pair = (int) DIGITS[((int) value) & 0x3F]; + JLA.putCharUTF16(buffer, --index, pair >> 8); + JLA.putCharUTF16(buffer, --index, pair & 0xFF); + value >>>= 6; + } + + int digits = DIGITS[(int) (value & 0x3F)]; + JLA.putCharUTF16(buffer, --index, digits >> 8); + + if (7 < value) { + JLA.putCharUTF16(buffer, --index, digits & 0xFF); + } + + return index; + } + + /** + * Calculate the number of digits required to represent the long. + * + * @param value value to convert + * + * @return number of digits + */ + public static int stringSize(long value) { + return value == 0 ? 1 : ((66 - Long.numberOfLeadingZeros(value)) / 3); } } diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/StringTemplateTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/StringTemplateTree.java deleted file mode 100644 index 9cf94d1cbd3..00000000000 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/StringTemplateTree.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 com.sun.source.tree; - -import java.util.List; - -import jdk.internal.javac.PreviewFeature; - -/** - * A tree node for a string template expression. - * - * @since 21 - */ -@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true) -public interface StringTemplateTree extends ExpressionTree { - /** - * Returns templated string processor (may be qualified) or null. - * - * @return templated string processor - */ - ExpressionTree getProcessor(); - - /** - * Returns string fragments. - * - * @return string fragments - */ - List getFragments(); - - /** - * Returns list of expressions. - * - * @return list of expressions - */ - List getExpressions(); -} diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java index 9150c4cf4b0..0bd3823307b 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java @@ -25,8 +25,6 @@ package com.sun.source.tree; -import jdk.internal.javac.PreviewFeature; - /** * Common interface for all nodes in an abstract syntax tree. * @@ -175,13 +173,6 @@ public interface Tree { */ INSTANCE_OF(InstanceOfTree.class), - /** - * Used for instances of {@link StringTemplateTree}. - * @since 21 - */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true) - TEMPLATE(StringTemplateTree.class), - /** * Used for instances of {@link LabeledStatementTree}. */ diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java index d01625ff4b0..3f7a683350c 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java @@ -25,8 +25,6 @@ package com.sun.source.tree; -import jdk.internal.javac.PreviewFeature; - /** * A visitor of trees, in the style of the visitor design pattern. * Classes implementing this interface are used to operate @@ -259,16 +257,6 @@ public interface TreeVisitor { */ R visitLiteral(LiteralTree node, P p); - /** - * Visits a StringTemplateTree node. - * @param node the node being visited - * @param p a parameter value - * @return a result value - * @since 21 - */ - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true) - R visitStringTemplate(StringTemplateTree node, P p); - /** * Visits a {@code AnyPatternTree} node. * @param node the node being visited diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java index 22a2e479a80..5179061b4bb 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java @@ -26,7 +26,6 @@ package com.sun.source.util; import com.sun.source.tree.*; -import jdk.internal.javac.PreviewFeature; /** * A simple visitor for tree nodes. @@ -628,20 +627,6 @@ public class SimpleTreeVisitor implements TreeVisitor { return defaultAction(node, p); } - /** - * {@inheritDoc} This implementation calls {@code defaultAction}. - * - * @param node {@inheritDoc} - * @param p {@inheritDoc} - * @return the result of {@code defaultAction} - * @since 21 - */ - @Override - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true) - public R visitStringTemplate(StringTemplateTree node, P p) { - return defaultAction(node, p); - } - /** * {@inheritDoc} * diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java index fc3a7823914..49bec302100 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java @@ -26,7 +26,6 @@ package com.sun.source.util; import com.sun.source.tree.*; -import jdk.internal.javac.PreviewFeature; /** * A TreeVisitor that visits all the child tree nodes. @@ -775,24 +774,6 @@ public class TreeScanner implements TreeVisitor { return null; } - /** - * {@inheritDoc} - * - * @implSpec This implementation scans the children in left to right order. - * - * @param node {@inheritDoc} - * @param p {@inheritDoc} - * @return the result of scanning - * @since 21 - */ - @Override - @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true) - public R visitStringTemplate(StringTemplateTree node, P p) { - R r = scan(node.getProcessor(), p); - r = scanAndReduce(node.getExpressions(), p, r); - return r; - } - /** * {@inheritDoc} * diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java index 32a7d068715..1572973179b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java @@ -207,7 +207,6 @@ public class Preview { */ public boolean isPreview(Feature feature) { return switch (feature) { - case STRING_TEMPLATES -> true; case IMPLICIT_CLASSES -> true; case SUPER_INIT -> true; case PRIMITIVE_PATTERNS -> true; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java index 54e5cfec32a..80f60aa7209 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java @@ -250,7 +250,6 @@ public enum Source { REDUNDANT_STRICTFP(JDK17), UNCONDITIONAL_PATTERN_IN_INSTANCEOF(JDK21, Fragments.FeatureUnconditionalPatternsInInstanceof, DiagKind.PLURAL), RECORD_PATTERNS(JDK21, Fragments.FeatureDeconstructionPatterns, DiagKind.PLURAL), - STRING_TEMPLATES(JDK21, Fragments.FeatureStringTemplates, DiagKind.PLURAL), IMPLICIT_CLASSES(JDK21, Fragments.FeatureImplicitClasses, DiagKind.PLURAL), WARN_ON_ILLEGAL_UTF8(MIN, JDK21), UNNAMED_VARIABLES(JDK22, Fragments.FeatureUnnamedVariables, DiagKind.PLURAL), diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java index b1dd2186d7e..89de932ab72 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -242,12 +242,6 @@ public class Symtab { public final Type objectInputType; public final Type objectOutputType; - // For string templates - public final Type stringTemplateType; - public final Type templateRuntimeType; - public final Type processorType; - public final Type linkageType; - /** The symbol representing the length field of an array. */ public final VarSymbol lengthVar; @@ -641,12 +635,6 @@ public class Symtab { synthesizeBoxTypeIfMissing(floatType); synthesizeBoxTypeIfMissing(voidType); - // For string templates - stringTemplateType = enterClass("java.lang.StringTemplate"); - templateRuntimeType = enterClass("java.lang.runtime.TemplateRuntime"); - processorType = enterClass("java.lang.StringTemplate$Processor"); - linkageType = enterClass("java.lang.StringTemplate$Processor$Linkage"); - // Enter a synthetic class that is used to mark internal // proprietary classes in ct.sym. This class does not have a // class file. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 65da42f3fbc..0d6e39c8b06 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -4992,32 +4992,6 @@ public class Attr extends JCTree.Visitor { return (tag == CLASS) ? syms.stringType : syms.typeOfTag[tag.ordinal()]; } - public void visitStringTemplate(JCStringTemplate tree) { - JCExpression processor = tree.processor; - Type processorType = attribTree(processor, env, new ResultInfo(KindSelector.VAL, Type.noType)); - chk.checkProcessorType(processor, processorType, env); - Type processMethodType = getProcessMethodType(tree, processorType); - tree.processMethodType = processMethodType; - Type resultType = processMethodType.getReturnType(); - - Env localEnv = env.dup(tree, env.info.dup()); - - for (JCExpression arg : tree.expressions) { - chk.checkNonVoid(arg.pos(), attribExpr(arg, localEnv)); - } - - tree.type = resultType; - result = resultType; - check(tree, resultType, KindSelector.VAL, resultInfo); - } - - private Type getProcessMethodType(JCStringTemplate tree, Type processorType) { - MethodSymbol processSymbol = rs.resolveInternalMethod(tree.pos(), - env, types.skipTypeVars(processorType, false), - names.process, List.of(syms.stringTemplateType), List.nil()); - return types.memberType(processorType, processSymbol); - } - public void visitTypeIdent(JCPrimitiveTypeTree tree) { result = check(tree, syms.typeOfTag[tree.typetag.ordinal()], KindSelector.TYP, resultInfo); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index 834d976a7c8..1e717b2b034 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -4475,26 +4475,6 @@ public class Check { } } - public Type checkProcessorType(JCExpression processor, Type resultType, Env env) { - Type processorType = processor.type; - Type interfaceType = types.asSuper(processorType, syms.processorType.tsym); - - if (interfaceType != null) { - List typeArguments = interfaceType.getTypeArguments(); - - if (typeArguments.size() == 2) { - resultType = typeArguments.head; - } else { - resultType = syms.objectType; - } - } else { - log.error(DiagnosticFlag.RESOLVE_ERROR, processor.pos, - Errors.NotAProcessorType(processorType.tsym)); - } - - return resultType; - } - public void checkLeaksNotAccessible(Env env, JCClassDecl check) { JCCompilationUnit toplevel = env.toplevel; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java index 0f808af0308..b044f956fdf 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java @@ -59,11 +59,10 @@ public class CompileStates extends HashMap, CompileStates.Compi ATTR(4), FLOW(5), TRANSTYPES(6), - TRANSLITERALS(7), - TRANSPATTERNS(8), - UNLAMBDA(9), - LOWER(10), - GENERATE(11); + TRANSPATTERNS(7), + UNLAMBDA(8), + LOWER(9), + GENERATE(10); CompileState(int value) { this.value = value; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index 98a060d6bf8..4c9a28102e0 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -1744,15 +1744,6 @@ public class Flow { } } - @Override - public void visitStringTemplate(JCStringTemplate tree) { - for (Type thrown : tree.processMethodType.getThrownTypes()) { - markThrown(tree, thrown); - } - - scan(tree.expressions); - } - void checkCaughtType(DiagnosticPosition pos, Type exc, List thrownInTry, List caughtInTry) { if (chk.subset(exc, caughtInTry)) { log.error(pos, Errors.ExceptAlreadyCaught(exc)); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransLiterals.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransLiterals.java deleted file mode 100644 index fef3a6c0526..00000000000 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransLiterals.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * 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 com.sun.tools.javac.comp; - -import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symbol.ClassSymbol; -import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; -import com.sun.tools.javac.code.Symbol.MethodSymbol; -import com.sun.tools.javac.code.Symbol.VarSymbol; -import com.sun.tools.javac.code.Symtab; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.code.Type.*; -import com.sun.tools.javac.code.Types; -import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.*; -import com.sun.tools.javac.tree.TreeInfo; -import com.sun.tools.javac.tree.TreeMaker; -import com.sun.tools.javac.tree.TreeTranslator; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Name; -import com.sun.tools.javac.util.Names; - -import java.util.Iterator; - -/** This pass translates constructed literals (string templates, ...) to conventional Java. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public final class TransLiterals extends TreeTranslator { - /** - * The context key for the TransTypes phase. - */ - protected static final Context.Key transLiteralsKey = new Context.Key<>(); - - /** - * Get the instance for this context. - */ - public static TransLiterals instance(Context context) { - TransLiterals instance = context.get(transLiteralsKey); - if (instance == null) - instance = new TransLiterals(context); - return instance; - } - - private final Symtab syms; - private final Resolve rs; - private final Types types; - private final Operators operators; - private final Names names; - private TreeMaker make = null; - private Env env = null; - private ClassSymbol currentClass = null; - private MethodSymbol currentMethodSym = null; - - protected TransLiterals(Context context) { - context.put(transLiteralsKey, this); - syms = Symtab.instance(context); - rs = Resolve.instance(context); - make = TreeMaker.instance(context); - types = Types.instance(context); - operators = Operators.instance(context); - names = Names.instance(context); - } - - JCExpression makeLit(Type type, Object value) { - return make.Literal(type.getTag(), value).setType(type.constType(value)); - } - - JCExpression makeString(String string) { - return makeLit(syms.stringType, string); - } - - List makeStringList(List strings) { - List exprs = List.nil(); - for (String string : strings) { - exprs = exprs.append(makeString(string)); - } - return exprs; - } - - JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) { - JCBinary tree = make.Binary(optag, lhs, rhs); - tree.operator = operators.resolveBinary(tree, optag, lhs.type, rhs.type); - tree.type = tree.operator.type.getReturnType(); - return tree; - } - - MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List args) { - return rs.resolveInternalMethod(pos, env, qual, name, args, List.nil()); - } - - @Override - public void visitClassDef(JCClassDecl tree) { - ClassSymbol prevCurrentClass = currentClass; - try { - currentClass = tree.sym; - super.visitClassDef(tree); - } finally { - currentClass = prevCurrentClass; - } - } - - @Override - public void visitMethodDef(JCMethodDecl tree) { - MethodSymbol prevMethodSym = currentMethodSym; - try { - currentMethodSym = tree.sym; - super.visitMethodDef(tree); - } finally { - currentMethodSym = prevMethodSym; - } - } - - final class TransStringTemplate { - final JCStringTemplate tree; - final JCExpression processor; - final List fragments; - final List expressions; - final List expressionTypes; - final boolean useValuesList; - - TransStringTemplate(JCStringTemplate tree) { - this.tree = tree; - this.processor = tree.processor; - this.fragments = tree.fragments; - this.expressions = translate(tree.expressions); - this.expressionTypes = expressions.stream() - .map(arg -> arg.type == syms.botType ? syms.objectType : arg.type) - .collect(List.collector()); - int slots = expressionTypes.stream() - .mapToInt(t -> types.isSameType(t, syms.longType) || - types.isSameType(t, syms.doubleType) ? 2 : 1).sum(); - this.useValuesList = 200 < slots; // StringConcatFactory.MAX_INDY_CONCAT_ARG_SLOTS - } - - JCExpression concatExpression(List fragments, List expressions) { - JCExpression expr = null; - Iterator iterator = expressions.iterator(); - for (String fragment : fragments) { - expr = expr == null ? makeString(fragment) - : makeBinary(Tag.PLUS, expr, makeString(fragment)); - if (iterator.hasNext()) { - JCExpression expression = iterator.next(); - Type expressionType = expression.type; - expr = makeBinary(Tag.PLUS, expr, expression.setType(expressionType)); - } - } - return expr; - } - - JCExpression bsmCall(Name name, Name bootstrapName, Type type, - List args, - List argTypes, - List staticArgValues, - List staticArgsTypes) { - Symbol bsm = rs.resolveQualifiedMethod(tree.pos(), env, - syms.templateRuntimeType, bootstrapName, staticArgsTypes, List.nil()); - MethodType indyType = new MethodType(argTypes, type, List.nil(), syms.methodClass); - DynamicMethodSymbol dynSym = new DynamicMethodSymbol( - name, - syms.noSymbol, - ((MethodSymbol)bsm).asHandle(), - indyType, - staticArgValues.toArray(new LoadableConstant[0]) - ); - JCFieldAccess qualifier = make.Select(make.Type(syms.processorType), dynSym.name); - qualifier.sym = dynSym; - qualifier.type = type; - JCMethodInvocation apply = make.Apply(List.nil(), qualifier, args); - apply.type = type; - return apply; - } - - JCExpression processCall(JCExpression stringTemplate) { - MethodSymbol appyMeth = lookupMethod(tree.pos(), names.process, - syms.processorType, List.of(syms.stringTemplateType)); - JCExpression applySelect = make.Select(processor, appyMeth); - JCExpression process = make.Apply(null, applySelect, List.of(stringTemplate)) - .setType(syms.objectType); - JCTypeCast cast = make.TypeCast(tree.type, process); - return cast; - } - - JCExpression newStringTemplate() { - List staticArgValues = List.nil(); - List staticArgsTypes = - List.of(syms.methodHandleLookupType, syms.stringType, - syms.methodTypeType); - if (useValuesList) { - JCNewArray fragmentArray = make.NewArray(make.Type(syms.stringType), - List.nil(), makeStringList(fragments)); - fragmentArray.type = new ArrayType(syms.stringType, syms.arrayClass); - JCNewArray valuesArray = make.NewArray(make.Type(syms.objectType), - List.nil(), expressions); - valuesArray.type = new ArrayType(syms.objectType, syms.arrayClass); - return bsmCall(names.process, names.newLargeStringTemplate, syms.stringTemplateType, - List.of(fragmentArray, valuesArray), - List.of(fragmentArray.type, valuesArray.type), - staticArgValues, staticArgsTypes); - } else { - for (String fragment : fragments) { - staticArgValues = staticArgValues.append(LoadableConstant.String(fragment)); - staticArgsTypes = staticArgsTypes.append(syms.stringType); - } - return bsmCall(names.process, names.newStringTemplate, syms.stringTemplateType, - expressions, expressionTypes, staticArgValues, staticArgsTypes); - } - } - - JCExpression bsmProcessCall() { - List args = expressions.prepend(processor); - List argTypes = expressionTypes.prepend(processor.type); - VarSymbol processorSym = (VarSymbol)TreeInfo.symbol(processor); - List staticArgValues = List.of(processorSym.asMethodHandle(true)); - List staticArgsTypes = - List.of(syms.methodHandleLookupType, syms.stringType, - syms.methodTypeType, syms.methodHandleType); - for (String fragment : fragments) { - staticArgValues = staticArgValues.append(LoadableConstant.String(fragment)); - staticArgsTypes = staticArgsTypes.append(syms.stringType); - } - return bsmCall(names.process, names.processStringTemplate, tree.type, - args, argTypes, staticArgValues, staticArgsTypes); - } - - boolean isNamedProcessor(Name name) { - Symbol sym = switch (processor) { - case JCIdent ident -> ident.sym; - case JCFieldAccess access -> access.sym; - default -> null; - }; - if (sym instanceof VarSymbol varSym) { - if (varSym.flags() == (Flags.PUBLIC | Flags.FINAL | Flags.STATIC) && - varSym.name == name && - types.isSameType(varSym.owner.type, syms.stringTemplateType)) { - return true; - } - } - return false; - } - - boolean isLinkageProcessor() { - return !useValuesList && - types.isSubtype(processor.type, syms.linkageType) && - processor.type.isFinal() && - TreeInfo.symbol(processor) instanceof VarSymbol varSymbol && - varSymbol.isStatic() && - varSymbol.isFinal(); - } - - JCExpression visit() { - JCExpression result; - make.at(tree.pos); - - if (isNamedProcessor(names.RAW)) { - result = newStringTemplate(); - } else if (isNamedProcessor(names.STR)) { - result = concatExpression(fragments, expressions); - } else if (isLinkageProcessor()) { - result = bsmProcessCall(); - } else { - result = processCall(newStringTemplate()); - } - - return result; - } - } - - public void visitStringTemplate(JCStringTemplate tree) { - int prevPos = make.pos; - try { - tree.processor = translate(tree.processor); - tree.expressions = translate(tree.expressions); - - TransStringTemplate transStringTemplate = new TransStringTemplate(tree); - - result = transStringTemplate.visit(); - } catch (Throwable ex) { - ex.printStackTrace(); - throw ex; - } finally { - make.at(prevPos); - } - } - - public void visitVarDef(JCVariableDecl tree) { - MethodSymbol prevMethodSym = currentMethodSym; - try { - tree.mods = translate(tree.mods); - tree.vartype = translate(tree.vartype); - if (currentMethodSym == null) { - // A class or instance field initializer. - currentMethodSym = - new MethodSymbol((tree.mods.flags& Flags.STATIC) | Flags.BLOCK, - names.empty, null, - currentClass); - } - if (tree.init != null) tree.init = translate(tree.init); - result = tree; - } finally { - currentMethodSym = prevMethodSym; - } - } - - public JCTree translateTopLevelClass(Env env, JCTree cdef, TreeMaker make) { - try { - this.make = make; - this.env = env; - translate(cdef); - } finally { - this.make = null; - this.env = null; - } - - return cdef; - } - -} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java index 36d3a2b24bd..fd3b507b038 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -837,14 +837,6 @@ public class TransTypes extends TreeTranslator { } } - public void visitStringTemplate(JCStringTemplate tree) { - tree.processor = translate(tree.processor, erasure(tree.processor.type)); - tree.expressions = tree.expressions.stream() - .map(e -> translate(e, erasure(e.type))).collect(List.collector()); - tree.type = erasure(tree.type); - result = tree; - } - public void visitSelect(JCFieldAccess tree) { Type t = types.skipTypeVars(tree.selected.type, false); if (t.isCompound()) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java index a421bd6bca4..af5f3dccdd6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java @@ -340,29 +340,6 @@ public class TypeEnter implements Completer { javaLang, env); } - private void staticImports(JCCompilationUnit tree, Env env, ImportFilter staticImportFilter) { - if (preview.isEnabled() && preview.isPreview(Feature.STRING_TEMPLATES)) { - Lint prevLint = chk.setLint(lint.suppress(LintCategory.DEPRECATION, LintCategory.REMOVAL, LintCategory.PREVIEW)); - boolean prevPreviewCheck = chk.disablePreviewCheck; - - try { - chk.disablePreviewCheck = true; - String autoImports = """ - import static java.lang.StringTemplate.STR; - """; - Parser parser = parserFactory.newParser(autoImports, false, false, false, false); - JCCompilationUnit importTree = parser.parseCompilationUnit(); - - for (JCImport imp : importTree.getImports()) { - doImport(imp); - } - } finally { - chk.setLint(prevLint); - chk.disablePreviewCheck = prevPreviewCheck; - } - } - } - private void resolveImports(JCCompilationUnit tree, Env env) { if (tree.starImportScope.isFilled()) { // we must have already processed this toplevel @@ -386,7 +363,6 @@ public class TypeEnter implements Completer { chk.importAccessible(sym, packge); importJavaLang(tree, env, typeImportFilter); - staticImports(tree, env, staticImportFilter); JCModuleDecl decl = tree.getModuleDecl(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 63950ed2f68..9d5def3f781 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -1612,12 +1612,6 @@ public class JavaCompiler { env.tree = transTypes.translateTopLevelClass(env.tree, localMake); compileStates.put(env, CompileState.TRANSTYPES); - if (shouldStop(CompileState.TRANSLITERALS)) - return; - - env.tree = TransLiterals.instance(context).translateTopLevelClass(env, env.tree, localMake); - compileStates.put(env, CompileState.TRANSLITERALS); - if (shouldStop(CompileState.TRANSPATTERNS)) return; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index 406ed328769..88de2333069 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -99,16 +99,6 @@ public class JavaTokenizer extends UnicodeReader { */ protected final StringBuilder sb; - /** - * Tokens pending to be read from string template embedded expressions. - */ - protected List pendingTokens; - - /** - * String template fragment ranges; end-endPos pairs. - */ - protected List fragmentRanges; - /** * The token kind, set by nextToken(). */ @@ -139,16 +129,6 @@ public class JavaTokenizer extends UnicodeReader { */ protected boolean hasEscapeSequences; - /** - * true if contains templated string escape sequences, set by nextToken(). - */ - protected boolean isStringTemplate; - - /** - * true if errors are pending from embedded expressions. - */ - protected boolean hasStringTemplateErrors; - /** * The set of lint options currently in effect. It is initialized * from the context, and then is set/reset as needed by Attr as it @@ -183,8 +163,6 @@ public class JavaTokenizer extends UnicodeReader { this.preview = fac.preview; this.lint = fac.lint; this.sb = new StringBuilder(256); - this.pendingTokens = List.nil(); - this.fragmentRanges = List.nil(); } /** @@ -339,86 +317,6 @@ public class JavaTokenizer extends UnicodeReader { processLineTerminator(start, position()); } - /** - * Scan the content of a string template expression. - * - * @param pos start of literal - * @param endPos start of embedded expression - */ - private void scanEmbeddedExpression(int pos, int endPos) { - // If first embedded expression. - if (!isStringTemplate) { - checkSourceLevel(pos, Feature.STRING_TEMPLATES); - fragmentRanges = fragmentRanges.append(pos); - isStringTemplate = true; - } - // Track end of previous fragment. - fragmentRanges = fragmentRanges.append(endPos); - // Keep backslash and add rest of placeholder. - sb.append("{}"); - - // Separate tokenizer for the embedded expression. - JavaTokenizer tokenizer = new JavaTokenizer(fac, buffer(), length()); - tokenizer.reset(position()); - - // Track brace depth. - int braceCount = 0; - - // Accumulate tokens. - List tokens = List.nil(); - - // Stash first left brace. - Token token = tokenizer.readToken(); - tokens = tokens.append(token); - - while (isAvailable()) { - // Read and stash next token. - token = tokenizer.readToken(); - tokens = tokens.append(token); - - // Intercept errors - if (token.kind == TokenKind.ERROR) { - // Track start of next fragment. - if (isTextBlock) { - reset(length()); - } else { - skipToEOLN(); - } - hasStringTemplateErrors = true; - return; - } - - if (token.kind == TokenKind.RBRACE) { - // Potential closing brace. - if (braceCount == 0) { - break; - } - - braceCount--; - } else if (token.kind == TokenKind.LBRACE) { - // Nesting deeper. - braceCount++; - } else if (token.kind == TokenKind.STRINGFRAGMENT) { - tokens = tokens.appendList(tokenizer.pendingTokens); - tokenizer.pendingTokens = List.nil(); - } else if (token.kind == TokenKind.EOF) { - break; - } - } - - // If no closing brace will be picked up as an unterminated string. - - // Set main tokenizer to continue at next position. - int position = tokenizer.position(); - reset(position); - - // Track start of next fragment. - fragmentRanges = fragmentRanges.append(position); - - // Pend the expression tokens after the STRINGFRAGMENT. - pendingTokens = pendingTokens.appendList(tokens); - } - /** * Processes the current character and places in the literal buffer. If the current * character is a backslash then the next character is assumed to be a proper @@ -480,17 +378,6 @@ public class JavaTokenizer extends UnicodeReader { } break; - case '{': - if (isString) { - scanEmbeddedExpression(pos, backslash); - if (hasStringTemplateErrors) { - return; - } - } else { - lexError(position(), Errors.IllegalEscChar); - } - break; - default: lexError(position(), Errors.IllegalEscChar); break; @@ -530,13 +417,7 @@ public class JavaTokenizer extends UnicodeReader { // While characters are available. while (isAvailable()) { - if (hasStringTemplateErrors) { - break; - } else if (accept("\"\"\"")) { - if (isStringTemplate && tk == TokenKind.STRINGLITERAL) { - tk = TokenKind.STRINGFRAGMENT; - } - + if (accept("\"\"\"")) { return; } @@ -560,12 +441,7 @@ public class JavaTokenizer extends UnicodeReader { // While characters are available. while (isAvailable()) { - if (hasStringTemplateErrors) { - break; - } else if (accept('\"')) { - if (isStringTemplate && tk == TokenKind.STRINGLITERAL) { - tk = TokenKind.STRINGFRAGMENT; - } + if (accept('\"')) { return; } @@ -580,18 +456,11 @@ public class JavaTokenizer extends UnicodeReader { } } - // String ended without close delimiter sequence or has embedded expression errors. - if (isStringTemplate) { - lexError(pos, isTextBlock ? Errors.TextBlockTemplateIsNotWellFormed - : Errors.StringTemplateIsNotWellFormed); - fragmentRanges = List.nil(); - pendingTokens = List.nil(); - } else { - lexError(pos, isTextBlock ? Errors.UnclosedTextBlock - : Errors.UnclosedStrLit); - } + // String ended without close delimiter sequence. + lexError(pos, isTextBlock ? Errors.UnclosedTextBlock + : Errors.UnclosedStrLit); - if (!hasStringTemplateErrors && firstEOLN != NOT_FOUND) { + if (firstEOLN != NOT_FOUND) { // Reset recovery position to point after text block open delimiter sequence. reset(firstEOLN); } @@ -906,20 +775,11 @@ public class JavaTokenizer extends UnicodeReader { * Read token (main entrypoint.) */ public Token readToken() { - if (pendingTokens.nonEmpty()) { - Token token = pendingTokens.head; - pendingTokens = pendingTokens.tail; - return token; - } - sb.setLength(0); name = null; radix = 0; isTextBlock = false; hasEscapeSequences = false; - isStringTemplate = false; - hasStringTemplateErrors = false; - fragmentRanges = List.nil(); int pos; List comments = null; @@ -1134,7 +994,6 @@ public class JavaTokenizer extends UnicodeReader { case '\"': // (Spec. 3.10) scanString(pos); break loop; - default: if (isSpecial(get())) { scanOperator(); @@ -1181,11 +1040,6 @@ public class JavaTokenizer extends UnicodeReader { int endPos = position(); - // Track end of final fragment. - if (isStringTemplate) { - fragmentRanges = fragmentRanges.append(endPos); - } - if (tk.tag == Token.Tag.DEFAULT) { return new Token(tk, pos, endPos, comments); } else if (tk.tag == Token.Tag.NAMED) { @@ -1217,11 +1071,6 @@ public class JavaTokenizer extends UnicodeReader { } } - if (isStringTemplate) { - // Break string into fragments and then return the first of the framents. - return getFragments(string, comments); - } - // Translate escape sequences if present. if (hasEscapeSequences) { try { @@ -1251,66 +1100,6 @@ public class JavaTokenizer extends UnicodeReader { } } - /** - * Convert the string into a list of pending tokens to precede embedded - * expressions. - * - * @param string string to fragment - * @param comments comments for first token - * - * @return first pending token. - */ - private Token getFragments(String string, List comments) { - List tokens = List.nil(); - Iterator rangeIter = fragmentRanges.iterator(); - for (String fragment : fragment(string)) { - fragment = fragment.translateEscapes(); - int fragmentPos = rangeIter.next(); - int fragmentEndPos = rangeIter.next(); - Token token = new StringToken(TokenKind.STRINGFRAGMENT, - fragmentPos, fragmentEndPos, fragment, comments); - comments = null; - tokens = tokens.append(token); - } - pendingTokens = tokens.appendList(pendingTokens); - Token first = pendingTokens.head; - pendingTokens = pendingTokens.tail; - return first; - } - - /** - * Break string template up into fragments. "\{}" indicates where - * embedded expressions occur. - * - * @param string string template - * - * @return list of fragment strings - */ - List fragment(String string) { - List fragments = List.nil(); - StringBuilder sb = new StringBuilder(); - int length = string.length(); - for (int i = 0; i < length; i++) { - char ch = string.charAt(i); - if (ch != '\\') { - sb.append(ch); - } else if (i + 2 < length && string.charAt(i + 1) == '{' - && string.charAt(i + 2) == '}') { - fragments = fragments.append(sb.toString()); - sb.setLength(0); - i += 2; - } else if (i + 1 < length){ - sb.append('\\'); - sb.append(string.charAt(i + 1)); - i++; - } else { - // Error already reported. - } - } - fragments = fragments.append(sb.toString()); - return fragments; - } - /** * Appends a comment to the list of comments preceding the current token. * diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index 4df24ef8c9d..bc53b18b3a5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -692,59 +692,6 @@ public class JavacParser implements Parser { return t; } - /** - * StringTemplate = - * [STRINGFRAGMENT] [EmbeddedExpression] - * | STRINGLITERAL - * - * EmbeddedExpression = - * LBRACE term RBRACE - */ - JCExpression stringTemplate(JCExpression processor) { - checkSourceLevel(Feature.STRING_TEMPLATES); - // Disable standalone string templates - if (processor == null) { - log.error(DiagnosticFlag.SYNTAX, token.pos, - Errors.ProcessorMissingFromStringTemplateExpression); - } - int oldmode = mode; - selectExprMode(); - Token stringToken = token; - int pos = stringToken.pos; - int endPos = stringToken.endPos; - TokenKind kind = stringToken.kind; - String string = token.stringVal(); - List fragments = List.of(string); - List expressions = List.nil(); - nextToken(); - if (kind != STRINGLITERAL) { - while (token.kind == STRINGFRAGMENT) { - stringToken = token; - endPos = stringToken.endPos; - string = stringToken.stringVal(); - fragments = fragments.append(string); - nextToken(); - } - while (token.pos < endPos && token.kind != DEFAULT && token.kind != ERROR) { - accept(LBRACE); - JCExpression expression = token.kind == RBRACE ? F.at(pos).Literal(TypeTag.BOT, null) - : term(EXPR); - expressions = expressions.append(expression); - if (token.kind != ERROR) { - accept(RBRACE); - } - } - // clean up remaining expression tokens if error - while (token.pos < endPos && token.kind != DEFAULT) { - nextToken(); - } - S.setPrevToken(stringToken); - } - JCExpression t = toP(F.at(pos).StringTemplate(processor, fragments, expressions)); - setMode(oldmode); - return t; - } - JCExpression literal(Name prefix) { return literal(prefix, token.pos); } @@ -1422,14 +1369,6 @@ public class JavacParser implements Parser { t = literal(names.empty); } else return illegal(); break; - case STRINGFRAGMENT: - if (typeArgs == null && isMode(EXPR)) { - selectExprMode(); - t = stringTemplate(null); - } else { - return illegal(); - } - break; case NEW: if (typeArgs != null) return illegal(); if (isMode(EXPR)) { @@ -1560,12 +1499,6 @@ public class JavacParser implements Parser { t = innerCreator(pos1, typeArgs, t); typeArgs = null; break loop; - case STRINGFRAGMENT: - case STRINGLITERAL: - if (typeArgs != null) return illegal(); - t = stringTemplate(t); - typeArgs = null; - break loop; } } @@ -1789,12 +1722,6 @@ public class JavacParser implements Parser { if (token.kind == LT) typeArgs = typeArguments(false); t = innerCreator(pos2, typeArgs, t); typeArgs = null; - } else if (token.kind == TokenKind.STRINGFRAGMENT || - token.kind == TokenKind.STRINGLITERAL) { - if (typeArgs != null) { - return illegal(); - } - t = stringTemplate(t); } else { List tyannos = null; if (isMode(TYPE) && token.kind == MONKEYS_AT) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index b672c1546fc..273c5bef7b4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1361,19 +1361,6 @@ compiler.err.unclosed.str.lit=\ compiler.err.unclosed.text.block=\ unclosed text block -compiler.err.string.template.is.not.well.formed=\ - string template is not well formed - -compiler.err.text.block.template.is.not.well.formed=\ - text block template is not well formed - -compiler.err.processor.missing.from.string.template.expression=\ - processor missing from string template expression - -# 0: symbol -compiler.err.not.a.processor.type=\ - not a processor type: {0} - # 0: string compiler.err.unsupported.encoding=\ unsupported encoding: {0} @@ -3219,9 +3206,6 @@ compiler.misc.feature.case.null=\ compiler.misc.feature.pattern.switch=\ patterns in switch statements -compiler.misc.feature.string.templates=\ - string templates - compiler.misc.feature.unconditional.patterns.in.instanceof=\ unconditional patterns in instanceof diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java index fcb73c59686..56daece2b2f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -269,10 +269,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { */ LITERAL, - /** String template expression. - */ - STRING_TEMPLATE, - /** Basic type identifiers, of type TypeIdent. */ TYPEIDENT, @@ -2481,59 +2477,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } - /** - * String template expression. - */ - public static class JCStringTemplate extends JCExpression implements StringTemplateTree { - public JCExpression processor; - public List fragments; - public List expressions; - public Type processMethodType; - - protected JCStringTemplate(JCExpression processor, - List fragments, - List expressions) { - this.processor = processor; - this.fragments = fragments; - this.expressions = expressions; - } - - @Override - public ExpressionTree getProcessor() { - return processor; - } - - @Override - public List getFragments() { - return fragments; - } - - @Override - public List getExpressions() { - return expressions; - } - - @Override @DefinedBy(Api.COMPILER_TREE) - public Kind getKind() { - return Kind.TEMPLATE; - } - - @Override @DefinedBy(Api.COMPILER_TREE) - public Tag getTag() { - return STRING_TEMPLATE; - } - - @Override @DefinedBy(Api.COMPILER_TREE) - public void accept(Visitor v) { - v.visitStringTemplate(this); - } - - @Override @DefinedBy(Api.COMPILER_TREE) - public R accept(TreeVisitor v, D d) { - return v.visitStringTemplate(this, d); - } - } - /** * An array selection */ @@ -3513,9 +3456,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { JCFieldAccess Select(JCExpression selected, Name selector); JCIdent Ident(Name idname); JCLiteral Literal(TypeTag tag, Object value); - JCStringTemplate StringTemplate(JCExpression processor, - List fragments, - List expressions); JCPrimitiveTypeTree TypeIdent(TypeTag typetag); JCArrayTypeTree TypeArray(JCExpression elemtype); JCTypeApply TypeApply(JCExpression clazz, List arguments); @@ -3587,7 +3527,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public void visitReference(JCMemberReference that) { visitTree(that); } public void visitIdent(JCIdent that) { visitTree(that); } public void visitLiteral(JCLiteral that) { visitTree(that); } - public void visitStringTemplate(JCStringTemplate that) { visitTree(that); } public void visitTypeIdent(JCPrimitiveTypeTree that) { visitTree(that); } public void visitTypeArray(JCArrayTypeTree that) { visitTree(that); } public void visitTypeApply(JCTypeApply that) { visitTree(that); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java index 06a8f6f143f..c63706639b3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -1476,21 +1476,6 @@ public class Pretty extends JCTree.Visitor { } } - public void visitStringTemplate(JCStringTemplate tree) { - try { - JCExpression processor = tree.processor; - print("["); - printExpr(processor); - print("]"); - print("\"" + tree.fragments.stream().collect(Collectors.joining("\\{}")) + "\""); - print("("); - printExprs(tree.expressions); - print(")"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - public void visitTypeIdent(JCPrimitiveTypeTree tree) { try { switch(tree.typetag) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java index 4d15bb8f9ae..7c2ef075ccb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, 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 @@ -283,14 +283,6 @@ public class TreeCopier

implements TreeVisitor { return M.at(t.pos).Literal(t.typetag, t.value); } - @DefinedBy(Api.COMPILER_TREE) - public JCTree visitStringTemplate(StringTemplateTree node, P p) { - JCStringTemplate t = (JCStringTemplate) node; - JCExpression processor = copy(t.processor, p); - List expressions = copy(t.expressions, p); - return M.at(t.pos).StringTemplate(processor, t.fragments, expressions); - } - @DefinedBy(Api.COMPILER_TREE) public JCTree visitMethod(MethodTree node, P p) { JCMethodDecl t = (JCMethodDecl) node; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index ee4477135c6..0a2fe85d1c3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -371,7 +371,6 @@ public class TreeInfo { case PLUS_ASG: case MINUS_ASG: case MUL_ASG: case DIV_ASG: case MOD_ASG: case APPLY: case NEWCLASS: - case STRING_TEMPLATE: case ERRONEOUS: return true; default: @@ -587,10 +586,6 @@ public class TreeInfo { JCBindingPattern node = (JCBindingPattern)tree; return getStartPos(node.var); } - case STRING_TEMPLATE: { - JCStringTemplate node = (JCStringTemplate) tree; - return node.processor == null ? node.pos : getStartPos(node.processor); - } case ERRONEOUS: { JCErroneous node = (JCErroneous)tree; if (node.errs != null && node.errs.nonEmpty()) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java index 21ced44c80e..fe6ca849f31 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -552,14 +552,6 @@ public class TreeMaker implements JCTree.Factory { return tree; } - public JCStringTemplate StringTemplate(JCExpression processor, - List fragments, - List expressions) { - JCStringTemplate tree = new JCStringTemplate(processor, fragments, expressions); - tree.pos = pos; - return tree; - } - public JCPrimitiveTypeTree TypeIdent(TypeTag typetag) { JCPrimitiveTypeTree tree = new JCPrimitiveTypeTree(typetag); tree.pos = pos; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java index f07871eff24..fc356047542 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, 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 @@ -353,11 +353,6 @@ public class TreeScanner extends Visitor { public void visitLiteral(JCLiteral tree) { } - public void visitStringTemplate(JCStringTemplate tree) { - scan(tree.processor); - scan(tree.expressions); - } - public void visitTypeIdent(JCPrimitiveTypeTree tree) { } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java index a3b7e4fc5d6..59a7457e6d0 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -409,13 +409,6 @@ public class TreeTranslator extends JCTree.Visitor { result = tree; } - public void visitStringTemplate(JCStringTemplate tree) { - tree.processor = translate(tree.processor); - tree.expressions = translate(tree.expressions); - - result = tree; - } - public void visitTypeIdent(JCPrimitiveTypeTree tree) { result = tree; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java index 229c710f7df..6c48490cf16 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -227,14 +227,6 @@ public class Names { public final Name enumSwitch; public final Name enumConstant; - // templated string - public final Name process; - public final Name STR; - public final Name RAW; - public final Name newStringTemplate; - public final Name newLargeStringTemplate; - public final Name processStringTemplate; - public final Name.Table table; @SuppressWarnings("this-escape") @@ -413,13 +405,6 @@ public class Names { permits = fromString("permits"); sealed = fromString("sealed"); - // templated string - process = fromString("process"); - STR = fromString("STR"); - RAW = fromString("RAW"); - newStringTemplate = fromString("newStringTemplate"); - newLargeStringTemplate = fromString("newLargeStringTemplate"); - processStringTemplate = fromString("processStringTemplate"); // pattern switches typeSwitch = fromString("typeSwitch"); diff --git a/test/jdk/java/lang/String/concat/MakeConcatWithTemplate.java b/test/jdk/java/lang/String/concat/MakeConcatWithTemplate.java deleted file mode 100644 index 2927afe4f9d..00000000000 --- a/test/jdk/java/lang/String/concat/MakeConcatWithTemplate.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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. - * - * 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. - */ - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.StringConcatFactory; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * @test - * @summary Test StringConcatFactory.makeConcatWithTemplate... methods. - * @enablePreview true - */ - -public class MakeConcatWithTemplate { - public static void main(String... args) { - makeConcatWithTemplate(); - makeConcatWithTemplateCluster(); - makeConcatWithTemplateGetters(); - } - - static List fragments(int n) { - String[] array = new String[n]; - Arrays.fill(array, "abc"); - return Arrays.asList(array); - } - - static List> types(int n) { - Class[] array = new Class[n]; - Arrays.fill(array, int.class); - return Arrays.asList(array); - } - - static List values(int n) { - Integer[] array = new Integer[n]; - Arrays.fill(array, 123); - return Arrays.asList(array); - } - - static List getters(int n) { - MethodHandle[] array = new MethodHandle[n]; - MethodHandle m = MethodHandles.dropArguments(MethodHandles.constant(int.class, 123), 0, Object.class); - Arrays.fill(array, m); - return Arrays.asList(array); - } - - static void makeConcatWithTemplate() { - try { - int n = StringConcatFactory.MAX_INDY_CONCAT_ARG_SLOTS - 1; - MethodHandle m = StringConcatFactory.makeConcatWithTemplate(fragments(n + 1), types(n)); - m.invokeWithArguments(values(n)); - } catch (Throwable e) { - throw new RuntimeException(e); - } - - try { - int n = StringConcatFactory.MAX_INDY_CONCAT_ARG_SLOTS; - MethodHandle m = StringConcatFactory.makeConcatWithTemplate(fragments(n + 1), types(n)); - m.invokeWithArguments(values(n)); - } catch (Throwable e) { - throw new RuntimeException(e); - } - - boolean threw = false; - try { - int n = StringConcatFactory.MAX_INDY_CONCAT_ARG_SLOTS + 1; - MethodHandle m = StringConcatFactory.makeConcatWithTemplate(fragments(n + 1), types(n)); - m.invokeWithArguments(values(n)); - } catch (Throwable e) { - threw = true; - } - - if (!threw) { - throw new RuntimeException("Exception expected - makeConcatWithTemplate"); - } - } - - static void makeConcatWithTemplateCluster() { - int n = StringConcatFactory.MAX_INDY_CONCAT_ARG_SLOTS; - int c = 3; - try { - List ms = StringConcatFactory.makeConcatWithTemplateCluster(fragments(c * n + 1), types(c * n), n); - MethodHandle m0 = ms.get(0); - MethodHandle m1 = ms.get(1); - MethodHandle m2 = ms.get(2); - MethodHandle m3 = ms.get(3); - - String s = (String)m0.invokeWithArguments(values(n)); - List args = new ArrayList<>(); - args.add(s); - args.addAll(values(n - 1)); // one less for carry over string - s = (String)m1.invokeWithArguments(args); - args.clear(); - args.add(s); - args.addAll(values(n - 1)); // one less for carry over string - s = (String)m2.invokeWithArguments(args); - args.clear(); - args.add(s); - args.addAll(values(2)); // two remaining carry overs - s = (String)m3.invokeWithArguments(args); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - static void makeConcatWithTemplateGetters() { - int n = StringConcatFactory.MAX_INDY_CONCAT_ARG_SLOTS; - int c = 3; - try { - MethodHandle m = StringConcatFactory.makeConcatWithTemplateGetters(fragments(c * n + 1), getters(c * n), n); - String s = (String)m.invoke(null); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - -} diff --git a/test/jdk/java/lang/template/Basic.java b/test/jdk/java/lang/template/Basic.java deleted file mode 100644 index e0096ce0b57..00000000000 --- a/test/jdk/java/lang/template/Basic.java +++ /dev/null @@ -1,504 +0,0 @@ -/* - * 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. - * - * 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. - */ - -/* - * @test - * @bug 0000000 - * @summary Exercise runtime handing of templated strings. - * @enablePreview true - */ - -import java.lang.StringTemplate.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.function.*; - -import static java.lang.StringTemplate.RAW; - -public class Basic { - public static void main(String... arg) { - equalsHashCode(); - concatenationTests(); - componentTests(); - limitsTests(); - processorTests(); - stringTemplateCoverage(); - simpleProcessorCoverage(); - } - - static void ASSERT(String a, String b) { - if (!Objects.equals(a, b)) { - System.out.println(a); - System.out.println(b); - throw new RuntimeException("Test failed"); - } - } - - static void ASSERT(Object a, Object b) { - if (!Objects.deepEquals(a, b)) { - System.out.println(a); - System.out.println(b); - throw new RuntimeException("Test failed"); - } - } - - /* - * equals and hashCode tests. - */ - static void equalsHashCode() { - int x = 10; - int y = 20; - int a = 10; - int b = 20; - - StringTemplate st0 = RAW."\{x} + \{y} = \{x + y}"; - StringTemplate st1 = RAW."\{a} + \{b} = \{a + b}"; - StringTemplate st2 = RAW."\{x} + \{y} = \{x + y}!"; - x++; - StringTemplate st3 = RAW."\{x} + \{y} = \{x + y}"; - - if (!st0.equals(st1)) throw new RuntimeException("st0 != st1"); - if (st0.equals(st2)) throw new RuntimeException("st0 == st2"); - if (st0.equals(st3)) throw new RuntimeException("st0 == st3"); - - if (st0.hashCode() != st1.hashCode()) throw new RuntimeException("st0.hashCode() != st1.hashCode()"); - } - - /* - * Concatenation tests. - */ - static void concatenationTests() { - int x = 10; - int y = 20; - - ASSERT(STR."\{x} \{y}", x + " " + y); - ASSERT(STR."\{x + y}", "" + (x + y)); - ASSERT(STR.process(RAW."\{x} \{y}"), x + " " + y); - ASSERT(STR.process(RAW."\{x + y}"), "" + (x + y)); - ASSERT((RAW."\{x} \{y}").process(STR), x + " " + y); - ASSERT((RAW."\{x + y}").process(STR), "" + (x + y)); - } - - /* - * Component tests. - */ - static void componentTests() { - int x = 10; - int y = 20; - - StringTemplate st = RAW."\{x} + \{y} = \{x + y}"; - ASSERT(st.values(), List.of(x, y, x + y)); - ASSERT(st.fragments(), List.of("", " + ", " = ", "")); - ASSERT(st.interpolate(), x + " + " + y + " = " + (x + y)); - } - - /* - * Limits tests. - */ - static void limitsTests() { - int x = 9; - - StringTemplate ts250 = RAW.""" - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - """; - ASSERT(ts250.values().size(), 250); - ASSERT(ts250.interpolate(), """ - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 - """); - - StringTemplate ts251 = RAW.""" - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x} - """; - ASSERT(ts251.values().size(), 251); - ASSERT(ts251.interpolate(), """ - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9 - """); - - StringTemplate ts252 = RAW.""" - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x} - """; - ASSERT(ts252.values().size(), 252); - ASSERT(ts252.interpolate(), """ - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 99 - """); - - StringTemplate ts253 = RAW.""" - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x} - """; - ASSERT(ts253.values().size(), 253); - ASSERT(ts253.interpolate(), """ - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 999 - """); - - StringTemplate ts254 = RAW.""" - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x} - """; - ASSERT(ts254.values().size(), 254); - ASSERT(ts254.interpolate(), """ - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999 - """); - - StringTemplate ts255 = RAW.""" - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x} - """; - ASSERT(ts255.values().size(), 255); - ASSERT(ts255.interpolate(), """ - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 99999 - """); - - StringTemplate ts256 = RAW.""" - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} - \{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x}\{x} \{x}\{x}\{x}\{x}\{x}\{x} - """; - ASSERT(ts256.values().size(), 256); - ASSERT(ts256.interpolate(), """ - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 9999999999 - - 9999999999 9999999999 - 9999999999 9999999999 - 9999999999 999999 - """); - - } - - /* - * Processor tests. - */ - public static final Processor STRINGIFY = st -> { - List values = st.values() - .stream() - .map(v -> (Object)String.valueOf(v)) - .toList(); - - return StringTemplate.of(st.fragments(), values); - }; - - public static final Processor UPPER = st -> { - List fragments = st.fragments() - .stream() - .map(String::toUpperCase) - .toList(); - - return StringTemplate.of(fragments, st.values()); - }; - - public static final Processor CHAIN = st -> { - st = STRINGIFY.process(st); - st = UPPER.process(st); - return STR.process(st); - }; - - static void processorTests() { - String name = "Joan"; - int age = 25; - ASSERT(CHAIN."\{name} is \{age} years old", "Joan IS 25 YEARS OLD"); - } - - /* - * StringTemplate coverage - */ - static void stringTemplateCoverage() { - StringTemplate tsNoValues = StringTemplate.of("No Values"); - - ASSERT(tsNoValues.values(), List.of()); - ASSERT(tsNoValues.fragments(), List.of("No Values")); - ASSERT(tsNoValues.interpolate(), STR."No Values"); - - int x = 10, y = 20; - StringTemplate src = RAW."\{x} + \{y} = \{x + y}"; - StringTemplate tsValues = StringTemplate.of(src.fragments(), src.values()); - ASSERT(tsValues.fragments(), List.of("", " + ", " = ", "")); - ASSERT(tsValues.values(), List.of(x, y, x + y)); - ASSERT(tsValues.interpolate(), x + " + " + y + " = " + (x + y)); - ASSERT(StringTemplate.combine(src, src).interpolate(), - RAW."\{x} + \{y} = \{x + y}\{x} + \{y} = \{x + y}".interpolate()); - ASSERT(StringTemplate.combine(src), src); - ASSERT(StringTemplate.combine().interpolate(), ""); - ASSERT(StringTemplate.combine(List.of(src, src)).interpolate(), - RAW."\{x} + \{y} = \{x + y}\{x} + \{y} = \{x + y}".interpolate()); - } - - /* - * SimpleProcessor coverage. - */ - - static class Processor0 implements Processor { - @Override - public String process(StringTemplate stringTemplate) throws IllegalArgumentException { - StringBuilder sb = new StringBuilder(); - Iterator fragmentsIter = stringTemplate.fragments().iterator(); - - for (Object value : stringTemplate.values()) { - sb.append(fragmentsIter.next()); - - if (value instanceof Boolean) { - throw new IllegalArgumentException("I don't like Booleans"); - } - - sb.append(value); - } - - sb.append(fragmentsIter.next()); - - return sb.toString(); - } - } - - static Processor0 processor0 = new Processor0(); - - static Processor processor1 = - st -> st.interpolate(); - - static Processor processor2 = st -> st.interpolate(); - - static Processor processor3 = st -> st.interpolate(); - - static Processor processor4 = st -> - StringTemplate.interpolate(st.fragments(), st.values()); - - - static void simpleProcessorCoverage() { - try { - int x = 10; - int y = 20; - ASSERT(processor0."\{x} + \{y} = \{x + y}", "10 + 20 = 30"); - ASSERT(processor1."\{x} + \{y} = \{x + y}", "10 + 20 = 30"); - ASSERT(processor2."\{x} + \{y} = \{x + y}", "10 + 20 = 30"); - ASSERT(processor3."\{x} + \{y} = \{x + y}", "10 + 20 = 30"); - ASSERT(processor4."\{x} + \{y} = \{x + y}", "10 + 20 = 30"); - } catch (IllegalArgumentException ex) { - throw new RuntimeException("processor fail"); - } - } - - static String justify(String string, int width) { - boolean leftJustify = width < 0; - int length = string.length(); - width = Math.abs(width); - int diff = width - length; - - if (diff < 0) { - string = "*".repeat(width); - } else if (0 < diff) { - if (leftJustify) { - string += " ".repeat(diff); - } else { - string = " ".repeat(diff) + string; - } - } - - return string; - } - -} diff --git a/test/jdk/java/lang/template/FormatterBuilder.java b/test/jdk/java/lang/template/FormatterBuilder.java deleted file mode 100644 index 1fc79e89846..00000000000 --- a/test/jdk/java/lang/template/FormatterBuilder.java +++ /dev/null @@ -1,961 +0,0 @@ -/* - * 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. - * - * 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. - */ - -/* - * @test - * @bug 0000000 - * @summary Exercise format builder. - * @enablePreview true - */ - -import java.util.FormatProcessor; -import java.util.Objects; -import java.util.Locale; -import java.util.MissingFormatArgumentException; -import java.util.UnknownFormatConversionException; - -import static java.util.FormatProcessor.FMT; - -public class FormatterBuilder { - public static void main(String... args) { - Locale.setDefault(Locale.US); - suite(FMT); - Locale thai = Locale.forLanguageTag("th-TH-u-nu-thai"); - FormatProcessor thaiFormat = FormatProcessor.create(thai); - Locale.setDefault(thai); - suite(thaiFormat); - } - - static void test(String a, String b) { - if (!Objects.equals(a, b)) { - throw new RuntimeException("format and FMT do not match: " + a + " : " + b); - } - } - - public interface Executable { - void execute() throws Throwable; - } - - static void assertThrows(Class expectedType, Executable executable, String message) { - Throwable actualException = null; - try { - executable.execute(); - } catch (Throwable e) { - actualException = e; - } - if (actualException == null) { - throw new RuntimeException("Expected " + expectedType + " to be thrown, but nothing was thrown."); - } - if (!expectedType.isInstance(actualException)) { - throw new RuntimeException("Expected " + expectedType + " to be thrown, but was thrown " + actualException.getClass()); - } - if (message != null && !message.equals(actualException.getMessage())) { - throw new RuntimeException("Expected " + message + " to be thrown, but was thrown " + actualException.getMessage()); - } - } - - static void suite(FormatProcessor fmt) { - Object nullObject = null; - test(String.format("%b", false), fmt."%b\{false}"); - test(String.format("%b", true), fmt."%b\{true}"); - test(String.format("%10b", false), fmt."%10b\{false}"); - test(String.format("%10b", true), fmt."%10b\{true}"); - test(String.format("%-10b", false), fmt."%-10b\{false}"); - test(String.format("%-10b", true), fmt."%-10b\{true}"); - test(String.format("%B", false), fmt."%B\{false}"); - test(String.format("%B", true), fmt."%B\{true}"); - test(String.format("%10B", false), fmt."%10B\{false}"); - test(String.format("%10B", true), fmt."%10B\{true}"); - test(String.format("%-10B", false), fmt."%-10B\{false}"); - test(String.format("%-10B", true), fmt."%-10B\{true}"); - - test(String.format("%h", 12345), fmt."%h\{12345}"); - test(String.format("%h", 0xABCDE), fmt."%h\{0xABCDE}"); - test(String.format("%10h", 12345), fmt."%10h\{12345}"); - test(String.format("%10h", 0xABCDE), fmt."%10h\{0xABCDE}"); - test(String.format("%-10h", 12345), fmt."%-10h\{12345}"); - test(String.format("%-10h", 0xABCDE), fmt."%-10h\{0xABCDE}"); - test(String.format("%H", 12345), fmt."%H\{12345}"); - test(String.format("%H", 0xABCDE), fmt."%H\{0xABCDE}"); - test(String.format("%10H", 12345), fmt."%10H\{12345}"); - test(String.format("%10H", 0xABCDE), fmt."%10H\{0xABCDE}"); - test(String.format("%-10H", 12345), fmt."%-10H\{12345}"); - test(String.format("%-10H", 0xABCDE), fmt."%-10H\{0xABCDE}"); - - test(String.format("%s", (byte)0xFF), fmt."%s\{(byte)0xFF}"); - test(String.format("%s", (short)0xFFFF), fmt."%s\{(short)0xFFFF}"); - test(String.format("%s", 12345), fmt."%s\{12345}"); - test(String.format("%s", 12345L), fmt."%s\{12345L}"); - test(String.format("%s", 1.33f), fmt."%s\{1.33f}"); - test(String.format("%s", 1.33), fmt."%s\{1.33}"); - test(String.format("%s", "abcde"), fmt."%s\{"abcde"}"); - test(String.format("%s", nullObject), fmt."%s\{nullObject}"); - test(String.format("%10s", (byte)0xFF), fmt."%10s\{(byte)0xFF}"); - test(String.format("%10s", (short)0xFFFF), fmt."%10s\{(short)0xFFFF}"); - test(String.format("%10s", 12345), fmt."%10s\{12345}"); - test(String.format("%10s", 12345L), fmt."%10s\{12345L}"); - test(String.format("%10s", 1.33f), fmt."%10s\{1.33f}"); - test(String.format("%10s", 1.33), fmt."%10s\{1.33}"); - test(String.format("%10s", "abcde"), fmt."%10s\{"abcde"}"); - test(String.format("%10s", nullObject), fmt."%10s\{nullObject}"); - test(String.format("%-10s", (byte)0xFF), fmt."%-10s\{(byte)0xFF}"); - test(String.format("%-10s", (short)0xFFFF), fmt."%-10s\{(short)0xFFFF}"); - test(String.format("%-10s", 12345), fmt."%-10s\{12345}"); - test(String.format("%-10s", 12345L), fmt."%-10s\{12345L}"); - test(String.format("%-10s", 1.33f), fmt."%-10s\{1.33f}"); - test(String.format("%-10s", 1.33), fmt."%-10s\{1.33}"); - test(String.format("%-10s", "abcde"), fmt."%-10s\{"abcde"}"); - test(String.format("%-10s", nullObject), fmt."%-10s\{nullObject}"); - test(String.format("%S", (byte)0xFF), fmt."%S\{(byte)0xFF}"); - test(String.format("%S", (short)0xFFFF), fmt."%S\{(short)0xFFFF}"); - test(String.format("%S", 12345), fmt."%S\{12345}"); - test(String.format("%S", 12345L), fmt."%S\{12345L}"); - test(String.format("%S", 1.33f), fmt."%S\{1.33f}"); - test(String.format("%S", 1.33), fmt."%S\{1.33}"); - test(String.format("%S", "abcde"), fmt."%S\{"abcde"}"); - test(String.format("%S", nullObject), fmt."%S\{nullObject}"); - test(String.format("%10S", (byte)0xFF), fmt."%10S\{(byte)0xFF}"); - test(String.format("%10S", (short)0xFFFF), fmt."%10S\{(short)0xFFFF}"); - test(String.format("%10S", 12345), fmt."%10S\{12345}"); - test(String.format("%10S", 12345L), fmt."%10S\{12345L}"); - test(String.format("%10S", 1.33f), fmt."%10S\{1.33f}"); - test(String.format("%10S", 1.33), fmt."%10S\{1.33}"); - test(String.format("%10S", "abcde"), fmt."%10S\{"abcde"}"); - test(String.format("%10S", nullObject), fmt."%10S\{nullObject}"); - test(String.format("%-10S", (byte)0xFF), fmt."%-10S\{(byte)0xFF}"); - test(String.format("%-10S", (short)0xFFFF), fmt."%-10S\{(short)0xFFFF}"); - test(String.format("%-10S", 12345), fmt."%-10S\{12345}"); - test(String.format("%-10S", 12345L), fmt."%-10S\{12345L}"); - test(String.format("%-10S", 1.33f), fmt."%-10S\{1.33f}"); - test(String.format("%-10S", 1.33), fmt."%-10S\{1.33}"); - test(String.format("%-10S", "abcde"), fmt."%-10S\{"abcde"}"); - test(String.format("%-10S", nullObject), fmt."%-10S\{nullObject}"); - - test(String.format("%c", 'a'), fmt."%c\{'a'}"); - test(String.format("%10c", 'a'), fmt."%10c\{'a'}"); - test(String.format("%-10c", 'a'), fmt."%-10c\{'a'}"); - test(String.format("%C", 'a'), fmt."%C\{'a'}"); - test(String.format("%10C", 'a'), fmt."%10C\{'a'}"); - test(String.format("%-10C", 'a'), fmt."%-10C\{'a'}"); - - test(String.format("%d", -12345), fmt."%d\{-12345}"); - test(String.format("%d", 0), fmt."%d\{0}"); - test(String.format("%d", 12345), fmt."%d\{12345}"); - test(String.format("%10d", -12345), fmt."%10d\{-12345}"); - test(String.format("%10d", 0), fmt."%10d\{0}"); - test(String.format("%10d", 12345), fmt."%10d\{12345}"); - test(String.format("%-10d", -12345), fmt."%-10d\{-12345}"); - test(String.format("%-10d", 0), fmt."%-10d\{0}"); - test(String.format("%-10d", 12345), fmt."%-10d\{12345}"); - test(String.format("%,d", -12345), fmt."%,d\{-12345}"); - test(String.format("%,d", 0), fmt."%,d\{0}"); - test(String.format("%,d", 12345), fmt."%,d\{12345}"); - test(String.format("%,10d", -12345), fmt."%,10d\{-12345}"); - test(String.format("%,10d", 0), fmt."%,10d\{0}"); - test(String.format("%,10d", 12345), fmt."%,10d\{12345}"); - test(String.format("%,-10d", -12345), fmt."%,-10d\{-12345}"); - test(String.format("%,-10d", 0), fmt."%,-10d\{0}"); - test(String.format("%,-10d", 12345), fmt."%,-10d\{12345}"); - test(String.format("%010d", -12345), fmt."%010d\{-12345}"); - test(String.format("%010d", 0), fmt."%010d\{0}"); - test(String.format("%010d", 12345), fmt."%010d\{12345}"); - test(String.format("%,010d", -12345), fmt."%,010d\{-12345}"); - test(String.format("%,010d", 0), fmt."%,010d\{0}"); - test(String.format("%,010d", 12345), fmt."%,010d\{12345}"); - - test(String.format("%d", -12345), fmt."%d\{-12345}"); - test(String.format("%d", 0), fmt."%d\{0}"); - test(String.format("%d", 12345), fmt."%d\{12345}"); - test(String.format("%10d", -12345), fmt."%10d\{-12345}"); - test(String.format("%10d", 0), fmt."%10d\{0}"); - test(String.format("%10d", 12345), fmt."%10d\{12345}"); - test(String.format("%-10d", -12345), fmt."%-10d\{-12345}"); - test(String.format("%-10d", 0), fmt."%-10d\{0}"); - test(String.format("%-10d", 12345), fmt."%-10d\{12345}"); - test(String.format("%,d", -12345), fmt."%,d\{-12345}"); - test(String.format("%,d", 0), fmt."%,d\{0}"); - test(String.format("%,d", 12345), fmt."%,d\{12345}"); - test(String.format("%,10d", -12345), fmt."%,10d\{-12345}"); - test(String.format("%,10d", 0), fmt."%,10d\{0}"); - test(String.format("%,10d", 12345), fmt."%,10d\{12345}"); - test(String.format("%,-10d", -12345), fmt."%,-10d\{-12345}"); - test(String.format("%,-10d", 0), fmt."%,-10d\{0}"); - test(String.format("%,-10d", 12345), fmt."%,-10d\{12345}"); - test(String.format("% d", -12345), fmt."% d\{-12345}"); - test(String.format("% d", 0), fmt."% d\{0}"); - test(String.format("% d", 12345), fmt."% d\{12345}"); - test(String.format("% 10d", -12345), fmt."% 10d\{-12345}"); - test(String.format("% 10d", 0), fmt."% 10d\{0}"); - test(String.format("% 10d", 12345), fmt."% 10d\{12345}"); - test(String.format("% -10d", -12345), fmt."% -10d\{-12345}"); - test(String.format("% -10d", 0), fmt."% -10d\{0}"); - test(String.format("% -10d", 12345), fmt."% -10d\{12345}"); - test(String.format("%, d", -12345), fmt."%, d\{-12345}"); - test(String.format("%, d", 0), fmt."%, d\{0}"); - test(String.format("%, d", 12345), fmt."%, d\{12345}"); - test(String.format("%, 10d", -12345), fmt."%, 10d\{-12345}"); - test(String.format("%, 10d", 0), fmt."%, 10d\{0}"); - test(String.format("%, 10d", 12345), fmt."%, 10d\{12345}"); - test(String.format("%, -10d", -12345), fmt."%, -10d\{-12345}"); - test(String.format("%, -10d", 0), fmt."%, -10d\{0}"); - test(String.format("%, -10d", 12345), fmt."%, -10d\{12345}"); - test(String.format("%010d", -12345), fmt."%010d\{-12345}"); - test(String.format("%010d", 0), fmt."%010d\{0}"); - test(String.format("%010d", 12345), fmt."%010d\{12345}"); - test(String.format("%,010d", -12345), fmt."%,010d\{-12345}"); - test(String.format("%,010d", 0), fmt."%,010d\{0}"); - test(String.format("%,010d", 12345), fmt."%,010d\{12345}"); - test(String.format("% 010d", -12345), fmt."% 010d\{-12345}"); - test(String.format("% 010d", 0), fmt."% 010d\{0}"); - test(String.format("% 010d", 12345), fmt."% 010d\{12345}"); - test(String.format("%, 010d", -12345), fmt."%, 010d\{-12345}"); - test(String.format("%, 010d", 0), fmt."%, 010d\{0}"); - test(String.format("%, 010d", 12345), fmt."%, 010d\{12345}"); - - test(String.format("%d", -12345), fmt."%d\{-12345}"); - test(String.format("%d", 0), fmt."%d\{0}"); - test(String.format("%d", 12345), fmt."%d\{12345}"); - test(String.format("%10d", -12345), fmt."%10d\{-12345}"); - test(String.format("%10d", 0), fmt."%10d\{0}"); - test(String.format("%10d", 12345), fmt."%10d\{12345}"); - test(String.format("%-10d", -12345), fmt."%-10d\{-12345}"); - test(String.format("%-10d", 0), fmt."%-10d\{0}"); - test(String.format("%-10d", 12345), fmt."%-10d\{12345}"); - test(String.format("%,d", -12345), fmt."%,d\{-12345}"); - test(String.format("%,d", 0), fmt."%,d\{0}"); - test(String.format("%,d", 12345), fmt."%,d\{12345}"); - test(String.format("%,10d", -12345), fmt."%,10d\{-12345}"); - test(String.format("%,10d", 0), fmt."%,10d\{0}"); - test(String.format("%,10d", 12345), fmt."%,10d\{12345}"); - test(String.format("%,-10d", -12345), fmt."%,-10d\{-12345}"); - test(String.format("%,-10d", 0), fmt."%,-10d\{0}"); - test(String.format("%,-10d", 12345), fmt."%,-10d\{12345}"); - test(String.format("%+d", -12345), fmt."%+d\{-12345}"); - test(String.format("%+d", 0), fmt."%+d\{0}"); - test(String.format("%+d", 12345), fmt."%+d\{12345}"); - test(String.format("%+10d", -12345), fmt."%+10d\{-12345}"); - test(String.format("%+10d", 0), fmt."%+10d\{0}"); - test(String.format("%+10d", 12345), fmt."%+10d\{12345}"); - test(String.format("%+-10d", -12345), fmt."%+-10d\{-12345}"); - test(String.format("%+-10d", 0), fmt."%+-10d\{0}"); - test(String.format("%+-10d", 12345), fmt."%+-10d\{12345}"); - test(String.format("%,+d", -12345), fmt."%,+d\{-12345}"); - test(String.format("%,+d", 0), fmt."%,+d\{0}"); - test(String.format("%,+d", 12345), fmt."%,+d\{12345}"); - test(String.format("%,+10d", -12345), fmt."%,+10d\{-12345}"); - test(String.format("%,+10d", 0), fmt."%,+10d\{0}"); - test(String.format("%,+10d", 12345), fmt."%,+10d\{12345}"); - test(String.format("%,+-10d", -12345), fmt."%,+-10d\{-12345}"); - test(String.format("%,+-10d", 0), fmt."%,+-10d\{0}"); - test(String.format("%,+-10d", 12345), fmt."%,+-10d\{12345}"); - test(String.format("%010d", -12345), fmt."%010d\{-12345}"); - test(String.format("%010d", 0), fmt."%010d\{0}"); - test(String.format("%010d", 12345), fmt."%010d\{12345}"); - test(String.format("%,010d", -12345), fmt."%,010d\{-12345}"); - test(String.format("%,010d", 0), fmt."%,010d\{0}"); - test(String.format("%,010d", 12345), fmt."%,010d\{12345}"); - test(String.format("%+010d", -12345), fmt."%+010d\{-12345}"); - test(String.format("%+010d", 0), fmt."%+010d\{0}"); - test(String.format("%+010d", 12345), fmt."%+010d\{12345}"); - test(String.format("%,+010d", -12345), fmt."%,+010d\{-12345}"); - test(String.format("%,+010d", 0), fmt."%,+010d\{0}"); - test(String.format("%,+010d", 12345), fmt."%,+010d\{12345}"); - - test(String.format("%d", -12345), fmt."%d\{-12345}"); - test(String.format("%d", 0), fmt."%d\{0}"); - test(String.format("%d", 12345), fmt."%d\{12345}"); - test(String.format("%10d", -12345), fmt."%10d\{-12345}"); - test(String.format("%10d", 0), fmt."%10d\{0}"); - test(String.format("%10d", 12345), fmt."%10d\{12345}"); - test(String.format("%-10d", -12345), fmt."%-10d\{-12345}"); - test(String.format("%-10d", 0), fmt."%-10d\{0}"); - test(String.format("%-10d", 12345), fmt."%-10d\{12345}"); - test(String.format("%,d", -12345), fmt."%,d\{-12345}"); - test(String.format("%,d", 0), fmt."%,d\{0}"); - test(String.format("%,d", 12345), fmt."%,d\{12345}"); - test(String.format("%,10d", -12345), fmt."%,10d\{-12345}"); - test(String.format("%,10d", 0), fmt."%,10d\{0}"); - test(String.format("%,10d", 12345), fmt."%,10d\{12345}"); - test(String.format("%,-10d", -12345), fmt."%,-10d\{-12345}"); - test(String.format("%,-10d", 0), fmt."%,-10d\{0}"); - test(String.format("%,-10d", 12345), fmt."%,-10d\{12345}"); - test(String.format("%(d", -12345), fmt."%(d\{-12345}"); - test(String.format("%(d", 0), fmt."%(d\{0}"); - test(String.format("%(d", 12345), fmt."%(d\{12345}"); - test(String.format("%(10d", -12345), fmt."%(10d\{-12345}"); - test(String.format("%(10d", 0), fmt."%(10d\{0}"); - test(String.format("%(10d", 12345), fmt."%(10d\{12345}"); - test(String.format("%(-10d", -12345), fmt."%(-10d\{-12345}"); - test(String.format("%(-10d", 0), fmt."%(-10d\{0}"); - test(String.format("%(-10d", 12345), fmt."%(-10d\{12345}"); - test(String.format("%,(d", -12345), fmt."%,(d\{-12345}"); - test(String.format("%,(d", 0), fmt."%,(d\{0}"); - test(String.format("%,(d", 12345), fmt."%,(d\{12345}"); - test(String.format("%,(10d", -12345), fmt."%,(10d\{-12345}"); - test(String.format("%,(10d", 0), fmt."%,(10d\{0}"); - test(String.format("%,(10d", 12345), fmt."%,(10d\{12345}"); - test(String.format("%,(-10d", -12345), fmt."%,(-10d\{-12345}"); - test(String.format("%,(-10d", 0), fmt."%,(-10d\{0}"); - test(String.format("%,(-10d", 12345), fmt."%,(-10d\{12345}"); - test(String.format("%010d", -12345), fmt."%010d\{-12345}"); - test(String.format("%010d", 0), fmt."%010d\{0}"); - test(String.format("%010d", 12345), fmt."%010d\{12345}"); - test(String.format("%,010d", -12345), fmt."%,010d\{-12345}"); - test(String.format("%,010d", 0), fmt."%,010d\{0}"); - test(String.format("%,010d", 12345), fmt."%,010d\{12345}"); - test(String.format("%(010d", -12345), fmt."%(010d\{-12345}"); - test(String.format("%(010d", 0), fmt."%(010d\{0}"); - test(String.format("%(010d", 12345), fmt."%(010d\{12345}"); - test(String.format("%,(010d", -12345), fmt."%,(010d\{-12345}"); - test(String.format("%,(010d", 0), fmt."%,(010d\{0}"); - test(String.format("%,(010d", 12345), fmt."%,(010d\{12345}"); - - test(String.format("%o", -12345), fmt."%o\{-12345}"); - test(String.format("%o", 0), fmt."%o\{0}"); - test(String.format("%o", 12345), fmt."%o\{12345}"); - test(String.format("%10o", -12345), fmt."%10o\{-12345}"); - test(String.format("%10o", 0), fmt."%10o\{0}"); - test(String.format("%10o", 12345), fmt."%10o\{12345}"); - test(String.format("%-10o", -12345), fmt."%-10o\{-12345}"); - test(String.format("%-10o", 0), fmt."%-10o\{0}"); - test(String.format("%-10o", 12345), fmt."%-10o\{12345}"); - test(String.format("%#o", -12345), fmt."%#o\{-12345}"); - test(String.format("%#o", 0), fmt."%#o\{0}"); - test(String.format("%#o", 12345), fmt."%#o\{12345}"); - test(String.format("%#10o", -12345), fmt."%#10o\{-12345}"); - test(String.format("%#10o", 0), fmt."%#10o\{0}"); - test(String.format("%#10o", 12345), fmt."%#10o\{12345}"); - test(String.format("%#-10o", -12345), fmt."%#-10o\{-12345}"); - test(String.format("%#-10o", 0), fmt."%#-10o\{0}"); - test(String.format("%#-10o", 12345), fmt."%#-10o\{12345}"); - test(String.format("%010o", -12345), fmt."%010o\{-12345}"); - test(String.format("%010o", 0), fmt."%010o\{0}"); - test(String.format("%010o", 12345), fmt."%010o\{12345}"); - test(String.format("%#010o", -12345), fmt."%#010o\{-12345}"); - test(String.format("%#010o", 0), fmt."%#010o\{0}"); - test(String.format("%#010o", 12345), fmt."%#010o\{12345}"); - - test(String.format("%x", -12345), fmt."%x\{-12345}"); - test(String.format("%x", 0), fmt."%x\{0}"); - test(String.format("%x", 12345), fmt."%x\{12345}"); - test(String.format("%10x", -12345), fmt."%10x\{-12345}"); - test(String.format("%10x", 0), fmt."%10x\{0}"); - test(String.format("%10x", 12345), fmt."%10x\{12345}"); - test(String.format("%-10x", -12345), fmt."%-10x\{-12345}"); - test(String.format("%-10x", 0), fmt."%-10x\{0}"); - test(String.format("%-10x", 12345), fmt."%-10x\{12345}"); - test(String.format("%X", -12345), fmt."%X\{-12345}"); - test(String.format("%X", 0), fmt."%X\{0}"); - test(String.format("%X", 12345), fmt."%X\{12345}"); - test(String.format("%10X", -12345), fmt."%10X\{-12345}"); - test(String.format("%10X", 0), fmt."%10X\{0}"); - test(String.format("%10X", 12345), fmt."%10X\{12345}"); - test(String.format("%-10X", -12345), fmt."%-10X\{-12345}"); - test(String.format("%-10X", 0), fmt."%-10X\{0}"); - test(String.format("%-10X", 12345), fmt."%-10X\{12345}"); - test(String.format("%#x", -12345), fmt."%#x\{-12345}"); - test(String.format("%#x", 0), fmt."%#x\{0}"); - test(String.format("%#x", 12345), fmt."%#x\{12345}"); - test(String.format("%#10x", -12345), fmt."%#10x\{-12345}"); - test(String.format("%#10x", 0), fmt."%#10x\{0}"); - test(String.format("%#10x", 12345), fmt."%#10x\{12345}"); - test(String.format("%#-10x", -12345), fmt."%#-10x\{-12345}"); - test(String.format("%#-10x", 0), fmt."%#-10x\{0}"); - test(String.format("%#-10x", 12345), fmt."%#-10x\{12345}"); - test(String.format("%#X", -12345), fmt."%#X\{-12345}"); - test(String.format("%#X", 0), fmt."%#X\{0}"); - test(String.format("%#X", 12345), fmt."%#X\{12345}"); - test(String.format("%#10X", -12345), fmt."%#10X\{-12345}"); - test(String.format("%#10X", 0), fmt."%#10X\{0}"); - test(String.format("%#10X", 12345), fmt."%#10X\{12345}"); - test(String.format("%#-10X", -12345), fmt."%#-10X\{-12345}"); - test(String.format("%#-10X", 0), fmt."%#-10X\{0}"); - test(String.format("%#-10X", 12345), fmt."%#-10X\{12345}"); - test(String.format("%010x", -12345), fmt."%010x\{-12345}"); - test(String.format("%010x", 0), fmt."%010x\{0}"); - test(String.format("%010x", 12345), fmt."%010x\{12345}"); - test(String.format("%010X", -12345), fmt."%010X\{-12345}"); - test(String.format("%010X", 0), fmt."%010X\{0}"); - test(String.format("%010X", 12345), fmt."%010X\{12345}"); - test(String.format("%#010x", -12345), fmt."%#010x\{-12345}"); - test(String.format("%#010x", 0), fmt."%#010x\{0}"); - test(String.format("%#010x", 12345), fmt."%#010x\{12345}"); - test(String.format("%#010X", -12345), fmt."%#010X\{-12345}"); - test(String.format("%#010X", 0), fmt."%#010X\{0}"); - test(String.format("%#010X", 12345), fmt."%#010X\{12345}"); - - test(String.format("%f", -12345.6), fmt."%f\{-12345.6}"); - test(String.format("%f", 0.0), fmt."%f\{0.0}"); - test(String.format("%f", 12345.6), fmt."%f\{12345.6}"); - test(String.format("%10f", -12345.6), fmt."%10f\{-12345.6}"); - test(String.format("%10f", 0.0), fmt."%10f\{0.0}"); - test(String.format("%10f", 12345.6), fmt."%10f\{12345.6}"); - test(String.format("%-10f", -12345.6), fmt."%-10f\{-12345.6}"); - test(String.format("%-10f", 0.0), fmt."%-10f\{0.0}"); - test(String.format("%-10f", 12345.6), fmt."%-10f\{12345.6}"); - test(String.format("%,f", -12345.6), fmt."%,f\{-12345.6}"); - test(String.format("%,f", 0.0), fmt."%,f\{0.0}"); - test(String.format("%,f", 12345.6), fmt."%,f\{12345.6}"); - test(String.format("%,10f", -12345.6), fmt."%,10f\{-12345.6}"); - test(String.format("%,10f", 0.0), fmt."%,10f\{0.0}"); - test(String.format("%,10f", 12345.6), fmt."%,10f\{12345.6}"); - test(String.format("%,-10f", -12345.6), fmt."%,-10f\{-12345.6}"); - test(String.format("%,-10f", 0.0), fmt."%,-10f\{0.0}"); - test(String.format("%,-10f", 12345.6), fmt."%,-10f\{12345.6}"); - - test(String.format("%f", -12345.6), fmt."%f\{-12345.6}"); - test(String.format("%f", 0.0), fmt."%f\{0.0}"); - test(String.format("%f", 12345.6), fmt."%f\{12345.6}"); - test(String.format("%10f", -12345.6), fmt."%10f\{-12345.6}"); - test(String.format("%10f", 0.0), fmt."%10f\{0.0}"); - test(String.format("%10f", 12345.6), fmt."%10f\{12345.6}"); - test(String.format("%-10f", -12345.6), fmt."%-10f\{-12345.6}"); - test(String.format("%-10f", 0.0), fmt."%-10f\{0.0}"); - test(String.format("%-10f", 12345.6), fmt."%-10f\{12345.6}"); - test(String.format("%,f", -12345.6), fmt."%,f\{-12345.6}"); - test(String.format("%,f", 0.0), fmt."%,f\{0.0}"); - test(String.format("%,f", 12345.6), fmt."%,f\{12345.6}"); - test(String.format("%,10f", -12345.6), fmt."%,10f\{-12345.6}"); - test(String.format("%,10f", 0.0), fmt."%,10f\{0.0}"); - test(String.format("%,10f", 12345.6), fmt."%,10f\{12345.6}"); - test(String.format("%,-10f", -12345.6), fmt."%,-10f\{-12345.6}"); - test(String.format("%,-10f", 0.0), fmt."%,-10f\{0.0}"); - test(String.format("%,-10f", 12345.6), fmt."%,-10f\{12345.6}"); - test(String.format("% f", -12345.6), fmt."% f\{-12345.6}"); - test(String.format("% f", 0.0), fmt."% f\{0.0}"); - test(String.format("% f", 12345.6), fmt."% f\{12345.6}"); - test(String.format("% 10f", -12345.6), fmt."% 10f\{-12345.6}"); - test(String.format("% 10f", 0.0), fmt."% 10f\{0.0}"); - test(String.format("% 10f", 12345.6), fmt."% 10f\{12345.6}"); - test(String.format("% -10f", -12345.6), fmt."% -10f\{-12345.6}"); - test(String.format("% -10f", 0.0), fmt."% -10f\{0.0}"); - test(String.format("% -10f", 12345.6), fmt."% -10f\{12345.6}"); - test(String.format("%, f", -12345.6), fmt."%, f\{-12345.6}"); - test(String.format("%, f", 0.0), fmt."%, f\{0.0}"); - test(String.format("%, f", 12345.6), fmt."%, f\{12345.6}"); - test(String.format("%, 10f", -12345.6), fmt."%, 10f\{-12345.6}"); - test(String.format("%, 10f", 0.0), fmt."%, 10f\{0.0}"); - test(String.format("%, 10f", 12345.6), fmt."%, 10f\{12345.6}"); - test(String.format("%, -10f", -12345.6), fmt."%, -10f\{-12345.6}"); - test(String.format("%, -10f", 0.0), fmt."%, -10f\{0.0}"); - test(String.format("%, -10f", 12345.6), fmt."%, -10f\{12345.6}"); - - test(String.format("%f", -12345.6), fmt."%f\{-12345.6}"); - test(String.format("%f", 0.0), fmt."%f\{0.0}"); - test(String.format("%f", 12345.6), fmt."%f\{12345.6}"); - test(String.format("%10f", -12345.6), fmt."%10f\{-12345.6}"); - test(String.format("%10f", 0.0), fmt."%10f\{0.0}"); - test(String.format("%10f", 12345.6), fmt."%10f\{12345.6}"); - test(String.format("%-10f", -12345.6), fmt."%-10f\{-12345.6}"); - test(String.format("%-10f", 0.0), fmt."%-10f\{0.0}"); - test(String.format("%-10f", 12345.6), fmt."%-10f\{12345.6}"); - test(String.format("%,f", -12345.6), fmt."%,f\{-12345.6}"); - test(String.format("%,f", 0.0), fmt."%,f\{0.0}"); - test(String.format("%,f", 12345.6), fmt."%,f\{12345.6}"); - test(String.format("%,10f", -12345.6), fmt."%,10f\{-12345.6}"); - test(String.format("%,10f", 0.0), fmt."%,10f\{0.0}"); - test(String.format("%,10f", 12345.6), fmt."%,10f\{12345.6}"); - test(String.format("%,-10f", -12345.6), fmt."%,-10f\{-12345.6}"); - test(String.format("%,-10f", 0.0), fmt."%,-10f\{0.0}"); - test(String.format("%,-10f", 12345.6), fmt."%,-10f\{12345.6}"); - test(String.format("%+f", -12345.6), fmt."%+f\{-12345.6}"); - test(String.format("%+f", 0.0), fmt."%+f\{0.0}"); - test(String.format("%+f", 12345.6), fmt."%+f\{12345.6}"); - test(String.format("%+10f", -12345.6), fmt."%+10f\{-12345.6}"); - test(String.format("%+10f", 0.0), fmt."%+10f\{0.0}"); - test(String.format("%+10f", 12345.6), fmt."%+10f\{12345.6}"); - test(String.format("%+-10f", -12345.6), fmt."%+-10f\{-12345.6}"); - test(String.format("%+-10f", 0.0), fmt."%+-10f\{0.0}"); - test(String.format("%+-10f", 12345.6), fmt."%+-10f\{12345.6}"); - test(String.format("%,+f", -12345.6), fmt."%,+f\{-12345.6}"); - test(String.format("%,+f", 0.0), fmt."%,+f\{0.0}"); - test(String.format("%,+f", 12345.6), fmt."%,+f\{12345.6}"); - test(String.format("%,+10f", -12345.6), fmt."%,+10f\{-12345.6}"); - test(String.format("%,+10f", 0.0), fmt."%,+10f\{0.0}"); - test(String.format("%,+10f", 12345.6), fmt."%,+10f\{12345.6}"); - test(String.format("%,+-10f", -12345.6), fmt."%,+-10f\{-12345.6}"); - test(String.format("%,+-10f", 0.0), fmt."%,+-10f\{0.0}"); - test(String.format("%,+-10f", 12345.6), fmt."%,+-10f\{12345.6}"); - - test(String.format("%f", -12345.6), fmt."%f\{-12345.6}"); - test(String.format("%f", 0.0), fmt."%f\{0.0}"); - test(String.format("%f", 12345.6), fmt."%f\{12345.6}"); - test(String.format("%10f", -12345.6), fmt."%10f\{-12345.6}"); - test(String.format("%10f", 0.0), fmt."%10f\{0.0}"); - test(String.format("%10f", 12345.6), fmt."%10f\{12345.6}"); - test(String.format("%-10f", -12345.6), fmt."%-10f\{-12345.6}"); - test(String.format("%-10f", 0.0), fmt."%-10f\{0.0}"); - test(String.format("%-10f", 12345.6), fmt."%-10f\{12345.6}"); - test(String.format("%,f", -12345.6), fmt."%,f\{-12345.6}"); - test(String.format("%,f", 0.0), fmt."%,f\{0.0}"); - test(String.format("%,f", 12345.6), fmt."%,f\{12345.6}"); - test(String.format("%,10f", -12345.6), fmt."%,10f\{-12345.6}"); - test(String.format("%,10f", 0.0), fmt."%,10f\{0.0}"); - test(String.format("%,10f", 12345.6), fmt."%,10f\{12345.6}"); - test(String.format("%,-10f", -12345.6), fmt."%,-10f\{-12345.6}"); - test(String.format("%,-10f", 0.0), fmt."%,-10f\{0.0}"); - test(String.format("%,-10f", 12345.6), fmt."%,-10f\{12345.6}"); - test(String.format("%(f", -12345.6), fmt."%(f\{-12345.6}"); - test(String.format("%(f", 0.0), fmt."%(f\{0.0}"); - test(String.format("%(f", 12345.6), fmt."%(f\{12345.6}"); - test(String.format("%(10f", -12345.6), fmt."%(10f\{-12345.6}"); - test(String.format("%(10f", 0.0), fmt."%(10f\{0.0}"); - test(String.format("%(10f", 12345.6), fmt."%(10f\{12345.6}"); - test(String.format("%(-10f", -12345.6), fmt."%(-10f\{-12345.6}"); - test(String.format("%(-10f", 0.0), fmt."%(-10f\{0.0}"); - test(String.format("%(-10f", 12345.6), fmt."%(-10f\{12345.6}"); - test(String.format("%,(f", -12345.6), fmt."%,(f\{-12345.6}"); - test(String.format("%,(f", 0.0), fmt."%,(f\{0.0}"); - test(String.format("%,(f", 12345.6), fmt."%,(f\{12345.6}"); - test(String.format("%,(10f", -12345.6), fmt."%,(10f\{-12345.6}"); - test(String.format("%,(10f", 0.0), fmt."%,(10f\{0.0}"); - test(String.format("%,(10f", 12345.6), fmt."%,(10f\{12345.6}"); - test(String.format("%,(-10f", -12345.6), fmt."%,(-10f\{-12345.6}"); - test(String.format("%,(-10f", 0.0), fmt."%,(-10f\{0.0}"); - test(String.format("%,(-10f", 12345.6), fmt."%,(-10f\{12345.6}"); - test(String.format("%+f", -12345.6), fmt."%+f\{-12345.6}"); - test(String.format("%+f", 0.0), fmt."%+f\{0.0}"); - test(String.format("%+f", 12345.6), fmt."%+f\{12345.6}"); - test(String.format("%+10f", -12345.6), fmt."%+10f\{-12345.6}"); - test(String.format("%+10f", 0.0), fmt."%+10f\{0.0}"); - test(String.format("%+10f", 12345.6), fmt."%+10f\{12345.6}"); - test(String.format("%+-10f", -12345.6), fmt."%+-10f\{-12345.6}"); - test(String.format("%+-10f", 0.0), fmt."%+-10f\{0.0}"); - test(String.format("%+-10f", 12345.6), fmt."%+-10f\{12345.6}"); - test(String.format("%,+f", -12345.6), fmt."%,+f\{-12345.6}"); - test(String.format("%,+f", 0.0), fmt."%,+f\{0.0}"); - test(String.format("%,+f", 12345.6), fmt."%,+f\{12345.6}"); - test(String.format("%,+10f", -12345.6), fmt."%,+10f\{-12345.6}"); - test(String.format("%,+10f", 0.0), fmt."%,+10f\{0.0}"); - test(String.format("%,+10f", 12345.6), fmt."%,+10f\{12345.6}"); - test(String.format("%,+-10f", -12345.6), fmt."%,+-10f\{-12345.6}"); - test(String.format("%,+-10f", 0.0), fmt."%,+-10f\{0.0}"); - test(String.format("%,+-10f", 12345.6), fmt."%,+-10f\{12345.6}"); - test(String.format("%(+f", -12345.6), fmt."%(+f\{-12345.6}"); - test(String.format("%(+f", 0.0), fmt."%(+f\{0.0}"); - test(String.format("%(+f", 12345.6), fmt."%(+f\{12345.6}"); - test(String.format("%(+10f", -12345.6), fmt."%(+10f\{-12345.6}"); - test(String.format("%(+10f", 0.0), fmt."%(+10f\{0.0}"); - test(String.format("%(+10f", 12345.6), fmt."%(+10f\{12345.6}"); - test(String.format("%(+-10f", -12345.6), fmt."%(+-10f\{-12345.6}"); - test(String.format("%(+-10f", 0.0), fmt."%(+-10f\{0.0}"); - test(String.format("%(+-10f", 12345.6), fmt."%(+-10f\{12345.6}"); - test(String.format("%,(+f", -12345.6), fmt."%,(+f\{-12345.6}"); - test(String.format("%,(+f", 0.0), fmt."%,(+f\{0.0}"); - test(String.format("%,(+f", 12345.6), fmt."%,(+f\{12345.6}"); - test(String.format("%,(+10f", -12345.6), fmt."%,(+10f\{-12345.6}"); - test(String.format("%,(+10f", 0.0), fmt."%,(+10f\{0.0}"); - test(String.format("%,(+10f", 12345.6), fmt."%,(+10f\{12345.6}"); - test(String.format("%,(+-10f", -12345.6), fmt."%,(+-10f\{-12345.6}"); - test(String.format("%,(+-10f", 0.0), fmt."%,(+-10f\{0.0}"); - test(String.format("%,(+-10f", 12345.6), fmt."%,(+-10f\{12345.6}"); - - test(String.format("%e", -12345.6), fmt."%e\{-12345.6}"); - test(String.format("%e", 0.0), fmt."%e\{0.0}"); - test(String.format("%e", 12345.6), fmt."%e\{12345.6}"); - test(String.format("%10e", -12345.6), fmt."%10e\{-12345.6}"); - test(String.format("%10e", 0.0), fmt."%10e\{0.0}"); - test(String.format("%10e", 12345.6), fmt."%10e\{12345.6}"); - test(String.format("%-10e", -12345.6), fmt."%-10e\{-12345.6}"); - test(String.format("%-10e", 0.0), fmt."%-10e\{0.0}"); - test(String.format("%-10e", 12345.6), fmt."%-10e\{12345.6}"); - test(String.format("%E", -12345.6), fmt."%E\{-12345.6}"); - test(String.format("%E", 0.0), fmt."%E\{0.0}"); - test(String.format("%E", 12345.6), fmt."%E\{12345.6}"); - test(String.format("%10E", -12345.6), fmt."%10E\{-12345.6}"); - test(String.format("%10E", 0.0), fmt."%10E\{0.0}"); - test(String.format("%10E", 12345.6), fmt."%10E\{12345.6}"); - test(String.format("%-10E", -12345.6), fmt."%-10E\{-12345.6}"); - test(String.format("%-10E", 0.0), fmt."%-10E\{0.0}"); - test(String.format("%-10E", 12345.6), fmt."%-10E\{12345.6}"); - - test(String.format("%g", -12345.6), fmt."%g\{-12345.6}"); - test(String.format("%g", 0.0), fmt."%g\{0.0}"); - test(String.format("%g", 12345.6), fmt."%g\{12345.6}"); - test(String.format("%10g", -12345.6), fmt."%10g\{-12345.6}"); - test(String.format("%10g", 0.0), fmt."%10g\{0.0}"); - test(String.format("%10g", 12345.6), fmt."%10g\{12345.6}"); - test(String.format("%-10g", -12345.6), fmt."%-10g\{-12345.6}"); - test(String.format("%-10g", 0.0), fmt."%-10g\{0.0}"); - test(String.format("%-10g", 12345.6), fmt."%-10g\{12345.6}"); - test(String.format("%G", -12345.6), fmt."%G\{-12345.6}"); - test(String.format("%G", 0.0), fmt."%G\{0.0}"); - test(String.format("%G", 12345.6), fmt."%G\{12345.6}"); - test(String.format("%10G", -12345.6), fmt."%10G\{-12345.6}"); - test(String.format("%10G", 0.0), fmt."%10G\{0.0}"); - test(String.format("%10G", 12345.6), fmt."%10G\{12345.6}"); - test(String.format("%-10G", -12345.6), fmt."%-10G\{-12345.6}"); - test(String.format("%-10G", 0.0), fmt."%-10G\{0.0}"); - test(String.format("%-10G", 12345.6), fmt."%-10G\{12345.6}"); - test(String.format("%,g", -12345.6), fmt."%,g\{-12345.6}"); - test(String.format("%,g", 0.0), fmt."%,g\{0.0}"); - test(String.format("%,g", 12345.6), fmt."%,g\{12345.6}"); - test(String.format("%,10g", -12345.6), fmt."%,10g\{-12345.6}"); - test(String.format("%,10g", 0.0), fmt."%,10g\{0.0}"); - test(String.format("%,10g", 12345.6), fmt."%,10g\{12345.6}"); - test(String.format("%,-10g", -12345.6), fmt."%,-10g\{-12345.6}"); - test(String.format("%,-10g", 0.0), fmt."%,-10g\{0.0}"); - test(String.format("%,-10g", 12345.6), fmt."%,-10g\{12345.6}"); - test(String.format("%,G", -12345.6), fmt."%,G\{-12345.6}"); - test(String.format("%,G", 0.0), fmt."%,G\{0.0}"); - test(String.format("%,G", 12345.6), fmt."%,G\{12345.6}"); - test(String.format("%,10G", -12345.6), fmt."%,10G\{-12345.6}"); - test(String.format("%,10G", 0.0), fmt."%,10G\{0.0}"); - test(String.format("%,10G", 12345.6), fmt."%,10G\{12345.6}"); - test(String.format("%,-10G", -12345.6), fmt."%,-10G\{-12345.6}"); - test(String.format("%,-10G", 0.0), fmt."%,-10G\{0.0}"); - test(String.format("%,-10G", 12345.6), fmt."%,-10G\{12345.6}"); - - test(String.format("%g", -12345.6), fmt."%g\{-12345.6}"); - test(String.format("%g", 0.0), fmt."%g\{0.0}"); - test(String.format("%g", 12345.6), fmt."%g\{12345.6}"); - test(String.format("%10g", -12345.6), fmt."%10g\{-12345.6}"); - test(String.format("%10g", 0.0), fmt."%10g\{0.0}"); - test(String.format("%10g", 12345.6), fmt."%10g\{12345.6}"); - test(String.format("%-10g", -12345.6), fmt."%-10g\{-12345.6}"); - test(String.format("%-10g", 0.0), fmt."%-10g\{0.0}"); - test(String.format("%-10g", 12345.6), fmt."%-10g\{12345.6}"); - test(String.format("%G", -12345.6), fmt."%G\{-12345.6}"); - test(String.format("%G", 0.0), fmt."%G\{0.0}"); - test(String.format("%G", 12345.6), fmt."%G\{12345.6}"); - test(String.format("%10G", -12345.6), fmt."%10G\{-12345.6}"); - test(String.format("%10G", 0.0), fmt."%10G\{0.0}"); - test(String.format("%10G", 12345.6), fmt."%10G\{12345.6}"); - test(String.format("%-10G", -12345.6), fmt."%-10G\{-12345.6}"); - test(String.format("%-10G", 0.0), fmt."%-10G\{0.0}"); - test(String.format("%-10G", 12345.6), fmt."%-10G\{12345.6}"); - test(String.format("%,g", -12345.6), fmt."%,g\{-12345.6}"); - test(String.format("%,g", 0.0), fmt."%,g\{0.0}"); - test(String.format("%,g", 12345.6), fmt."%,g\{12345.6}"); - test(String.format("%,10g", -12345.6), fmt."%,10g\{-12345.6}"); - test(String.format("%,10g", 0.0), fmt."%,10g\{0.0}"); - test(String.format("%,10g", 12345.6), fmt."%,10g\{12345.6}"); - test(String.format("%,-10g", -12345.6), fmt."%,-10g\{-12345.6}"); - test(String.format("%,-10g", 0.0), fmt."%,-10g\{0.0}"); - test(String.format("%,-10g", 12345.6), fmt."%,-10g\{12345.6}"); - test(String.format("%,G", -12345.6), fmt."%,G\{-12345.6}"); - test(String.format("%,G", 0.0), fmt."%,G\{0.0}"); - test(String.format("%,G", 12345.6), fmt."%,G\{12345.6}"); - test(String.format("%,10G", -12345.6), fmt."%,10G\{-12345.6}"); - test(String.format("%,10G", 0.0), fmt."%,10G\{0.0}"); - test(String.format("%,10G", 12345.6), fmt."%,10G\{12345.6}"); - test(String.format("%,-10G", -12345.6), fmt."%,-10G\{-12345.6}"); - test(String.format("%,-10G", 0.0), fmt."%,-10G\{0.0}"); - test(String.format("%,-10G", 12345.6), fmt."%,-10G\{12345.6}"); - test(String.format("% g", -12345.6), fmt."% g\{-12345.6}"); - test(String.format("% g", 0.0), fmt."% g\{0.0}"); - test(String.format("% g", 12345.6), fmt."% g\{12345.6}"); - test(String.format("% 10g", -12345.6), fmt."% 10g\{-12345.6}"); - test(String.format("% 10g", 0.0), fmt."% 10g\{0.0}"); - test(String.format("% 10g", 12345.6), fmt."% 10g\{12345.6}"); - test(String.format("% -10g", -12345.6), fmt."% -10g\{-12345.6}"); - test(String.format("% -10g", 0.0), fmt."% -10g\{0.0}"); - test(String.format("% -10g", 12345.6), fmt."% -10g\{12345.6}"); - test(String.format("% G", -12345.6), fmt."% G\{-12345.6}"); - test(String.format("% G", 0.0), fmt."% G\{0.0}"); - test(String.format("% G", 12345.6), fmt."% G\{12345.6}"); - test(String.format("% 10G", -12345.6), fmt."% 10G\{-12345.6}"); - test(String.format("% 10G", 0.0), fmt."% 10G\{0.0}"); - test(String.format("% 10G", 12345.6), fmt."% 10G\{12345.6}"); - test(String.format("% -10G", -12345.6), fmt."% -10G\{-12345.6}"); - test(String.format("% -10G", 0.0), fmt."% -10G\{0.0}"); - test(String.format("% -10G", 12345.6), fmt."% -10G\{12345.6}"); - test(String.format("%, g", -12345.6), fmt."%, g\{-12345.6}"); - test(String.format("%, g", 0.0), fmt."%, g\{0.0}"); - test(String.format("%, g", 12345.6), fmt."%, g\{12345.6}"); - test(String.format("%, 10g", -12345.6), fmt."%, 10g\{-12345.6}"); - test(String.format("%, 10g", 0.0), fmt."%, 10g\{0.0}"); - test(String.format("%, 10g", 12345.6), fmt."%, 10g\{12345.6}"); - test(String.format("%, -10g", -12345.6), fmt."%, -10g\{-12345.6}"); - test(String.format("%, -10g", 0.0), fmt."%, -10g\{0.0}"); - test(String.format("%, -10g", 12345.6), fmt."%, -10g\{12345.6}"); - test(String.format("%, G", -12345.6), fmt."%, G\{-12345.6}"); - test(String.format("%, G", 0.0), fmt."%, G\{0.0}"); - test(String.format("%, G", 12345.6), fmt."%, G\{12345.6}"); - test(String.format("%, 10G", -12345.6), fmt."%, 10G\{-12345.6}"); - test(String.format("%, 10G", 0.0), fmt."%, 10G\{0.0}"); - test(String.format("%, 10G", 12345.6), fmt."%, 10G\{12345.6}"); - test(String.format("%, -10G", -12345.6), fmt."%, -10G\{-12345.6}"); - test(String.format("%, -10G", 0.0), fmt."%, -10G\{0.0}"); - test(String.format("%, -10G", 12345.6), fmt."%, -10G\{12345.6}"); - - test(String.format("%g", -12345.6), fmt."%g\{-12345.6}"); - test(String.format("%g", 0.0), fmt."%g\{0.0}"); - test(String.format("%g", 12345.6), fmt."%g\{12345.6}"); - test(String.format("%10g", -12345.6), fmt."%10g\{-12345.6}"); - test(String.format("%10g", 0.0), fmt."%10g\{0.0}"); - test(String.format("%10g", 12345.6), fmt."%10g\{12345.6}"); - test(String.format("%-10g", -12345.6), fmt."%-10g\{-12345.6}"); - test(String.format("%-10g", 0.0), fmt."%-10g\{0.0}"); - test(String.format("%-10g", 12345.6), fmt."%-10g\{12345.6}"); - test(String.format("%G", -12345.6), fmt."%G\{-12345.6}"); - test(String.format("%G", 0.0), fmt."%G\{0.0}"); - test(String.format("%G", 12345.6), fmt."%G\{12345.6}"); - test(String.format("%10G", -12345.6), fmt."%10G\{-12345.6}"); - test(String.format("%10G", 0.0), fmt."%10G\{0.0}"); - test(String.format("%10G", 12345.6), fmt."%10G\{12345.6}"); - test(String.format("%-10G", -12345.6), fmt."%-10G\{-12345.6}"); - test(String.format("%-10G", 0.0), fmt."%-10G\{0.0}"); - test(String.format("%-10G", 12345.6), fmt."%-10G\{12345.6}"); - test(String.format("%,g", -12345.6), fmt."%,g\{-12345.6}"); - test(String.format("%,g", 0.0), fmt."%,g\{0.0}"); - test(String.format("%,g", 12345.6), fmt."%,g\{12345.6}"); - test(String.format("%,10g", -12345.6), fmt."%,10g\{-12345.6}"); - test(String.format("%,10g", 0.0), fmt."%,10g\{0.0}"); - test(String.format("%,10g", 12345.6), fmt."%,10g\{12345.6}"); - test(String.format("%,-10g", -12345.6), fmt."%,-10g\{-12345.6}"); - test(String.format("%,-10g", 0.0), fmt."%,-10g\{0.0}"); - test(String.format("%,-10g", 12345.6), fmt."%,-10g\{12345.6}"); - test(String.format("%,G", -12345.6), fmt."%,G\{-12345.6}"); - test(String.format("%,G", 0.0), fmt."%,G\{0.0}"); - test(String.format("%,G", 12345.6), fmt."%,G\{12345.6}"); - test(String.format("%,10G", -12345.6), fmt."%,10G\{-12345.6}"); - test(String.format("%,10G", 0.0), fmt."%,10G\{0.0}"); - test(String.format("%,10G", 12345.6), fmt."%,10G\{12345.6}"); - test(String.format("%,-10G", -12345.6), fmt."%,-10G\{-12345.6}"); - test(String.format("%,-10G", 0.0), fmt."%,-10G\{0.0}"); - test(String.format("%,-10G", 12345.6), fmt."%,-10G\{12345.6}"); - test(String.format("%+g", -12345.6), fmt."%+g\{-12345.6}"); - test(String.format("%+g", 0.0), fmt."%+g\{0.0}"); - test(String.format("%+g", 12345.6), fmt."%+g\{12345.6}"); - test(String.format("%+10g", -12345.6), fmt."%+10g\{-12345.6}"); - test(String.format("%+10g", 0.0), fmt."%+10g\{0.0}"); - test(String.format("%+10g", 12345.6), fmt."%+10g\{12345.6}"); - test(String.format("%+-10g", -12345.6), fmt."%+-10g\{-12345.6}"); - test(String.format("%+-10g", 0.0), fmt."%+-10g\{0.0}"); - test(String.format("%+-10g", 12345.6), fmt."%+-10g\{12345.6}"); - test(String.format("%+G", -12345.6), fmt."%+G\{-12345.6}"); - test(String.format("%+G", 0.0), fmt."%+G\{0.0}"); - test(String.format("%+G", 12345.6), fmt."%+G\{12345.6}"); - test(String.format("%+10G", -12345.6), fmt."%+10G\{-12345.6}"); - test(String.format("%+10G", 0.0), fmt."%+10G\{0.0}"); - test(String.format("%+10G", 12345.6), fmt."%+10G\{12345.6}"); - test(String.format("%+-10G", -12345.6), fmt."%+-10G\{-12345.6}"); - test(String.format("%+-10G", 0.0), fmt."%+-10G\{0.0}"); - test(String.format("%+-10G", 12345.6), fmt."%+-10G\{12345.6}"); - test(String.format("%,+g", -12345.6), fmt."%,+g\{-12345.6}"); - test(String.format("%,+g", 0.0), fmt."%,+g\{0.0}"); - test(String.format("%,+g", 12345.6), fmt."%,+g\{12345.6}"); - test(String.format("%,+10g", -12345.6), fmt."%,+10g\{-12345.6}"); - test(String.format("%,+10g", 0.0), fmt."%,+10g\{0.0}"); - test(String.format("%,+10g", 12345.6), fmt."%,+10g\{12345.6}"); - test(String.format("%,+-10g", -12345.6), fmt."%,+-10g\{-12345.6}"); - test(String.format("%,+-10g", 0.0), fmt."%,+-10g\{0.0}"); - test(String.format("%,+-10g", 12345.6), fmt."%,+-10g\{12345.6}"); - test(String.format("%,+G", -12345.6), fmt."%,+G\{-12345.6}"); - test(String.format("%,+G", 0.0), fmt."%,+G\{0.0}"); - test(String.format("%,+G", 12345.6), fmt."%,+G\{12345.6}"); - test(String.format("%,+10G", -12345.6), fmt."%,+10G\{-12345.6}"); - test(String.format("%,+10G", 0.0), fmt."%,+10G\{0.0}"); - test(String.format("%,+10G", 12345.6), fmt."%,+10G\{12345.6}"); - test(String.format("%,+-10G", -12345.6), fmt."%,+-10G\{-12345.6}"); - test(String.format("%,+-10G", 0.0), fmt."%,+-10G\{0.0}"); - test(String.format("%,+-10G", 12345.6), fmt."%,+-10G\{12345.6}"); - - test(String.format("%g", -12345.6), fmt."%g\{-12345.6}"); - test(String.format("%g", 0.0), fmt."%g\{0.0}"); - test(String.format("%g", 12345.6), fmt."%g\{12345.6}"); - test(String.format("%10g", -12345.6), fmt."%10g\{-12345.6}"); - test(String.format("%10g", 0.0), fmt."%10g\{0.0}"); - test(String.format("%10g", 12345.6), fmt."%10g\{12345.6}"); - test(String.format("%-10g", -12345.6), fmt."%-10g\{-12345.6}"); - test(String.format("%-10g", 0.0), fmt."%-10g\{0.0}"); - test(String.format("%-10g", 12345.6), fmt."%-10g\{12345.6}"); - test(String.format("%G", -12345.6), fmt."%G\{-12345.6}"); - test(String.format("%G", 0.0), fmt."%G\{0.0}"); - test(String.format("%G", 12345.6), fmt."%G\{12345.6}"); - test(String.format("%10G", -12345.6), fmt."%10G\{-12345.6}"); - test(String.format("%10G", 0.0), fmt."%10G\{0.0}"); - test(String.format("%10G", 12345.6), fmt."%10G\{12345.6}"); - test(String.format("%-10G", -12345.6), fmt."%-10G\{-12345.6}"); - test(String.format("%-10G", 0.0), fmt."%-10G\{0.0}"); - test(String.format("%-10G", 12345.6), fmt."%-10G\{12345.6}"); - test(String.format("%,g", -12345.6), fmt."%,g\{-12345.6}"); - test(String.format("%,g", 0.0), fmt."%,g\{0.0}"); - test(String.format("%,g", 12345.6), fmt."%,g\{12345.6}"); - test(String.format("%,10g", -12345.6), fmt."%,10g\{-12345.6}"); - test(String.format("%,10g", 0.0), fmt."%,10g\{0.0}"); - test(String.format("%,10g", 12345.6), fmt."%,10g\{12345.6}"); - test(String.format("%,-10g", -12345.6), fmt."%,-10g\{-12345.6}"); - test(String.format("%,-10g", 0.0), fmt."%,-10g\{0.0}"); - test(String.format("%,-10g", 12345.6), fmt."%,-10g\{12345.6}"); - test(String.format("%,G", -12345.6), fmt."%,G\{-12345.6}"); - test(String.format("%,G", 0.0), fmt."%,G\{0.0}"); - test(String.format("%,G", 12345.6), fmt."%,G\{12345.6}"); - test(String.format("%,10G", -12345.6), fmt."%,10G\{-12345.6}"); - test(String.format("%,10G", 0.0), fmt."%,10G\{0.0}"); - test(String.format("%,10G", 12345.6), fmt."%,10G\{12345.6}"); - test(String.format("%,-10G", -12345.6), fmt."%,-10G\{-12345.6}"); - test(String.format("%,-10G", 0.0), fmt."%,-10G\{0.0}"); - test(String.format("%,-10G", 12345.6), fmt."%,-10G\{12345.6}"); - test(String.format("%(g", -12345.6), fmt."%(g\{-12345.6}"); - test(String.format("%(g", 0.0), fmt."%(g\{0.0}"); - test(String.format("%(g", 12345.6), fmt."%(g\{12345.6}"); - test(String.format("%(10g", -12345.6), fmt."%(10g\{-12345.6}"); - test(String.format("%(10g", 0.0), fmt."%(10g\{0.0}"); - test(String.format("%(10g", 12345.6), fmt."%(10g\{12345.6}"); - test(String.format("%(-10g", -12345.6), fmt."%(-10g\{-12345.6}"); - test(String.format("%(-10g", 0.0), fmt."%(-10g\{0.0}"); - test(String.format("%(-10g", 12345.6), fmt."%(-10g\{12345.6}"); - test(String.format("%(G", -12345.6), fmt."%(G\{-12345.6}"); - test(String.format("%(G", 0.0), fmt."%(G\{0.0}"); - test(String.format("%(G", 12345.6), fmt."%(G\{12345.6}"); - test(String.format("%(10G", -12345.6), fmt."%(10G\{-12345.6}"); - test(String.format("%(10G", 0.0), fmt."%(10G\{0.0}"); - test(String.format("%(10G", 12345.6), fmt."%(10G\{12345.6}"); - test(String.format("%(-10G", -12345.6), fmt."%(-10G\{-12345.6}"); - test(String.format("%(-10G", 0.0), fmt."%(-10G\{0.0}"); - test(String.format("%(-10G", 12345.6), fmt."%(-10G\{12345.6}"); - test(String.format("%,(g", -12345.6), fmt."%,(g\{-12345.6}"); - test(String.format("%,(g", 0.0), fmt."%,(g\{0.0}"); - test(String.format("%,(g", 12345.6), fmt."%,(g\{12345.6}"); - test(String.format("%,(10g", -12345.6), fmt."%,(10g\{-12345.6}"); - test(String.format("%,(10g", 0.0), fmt."%,(10g\{0.0}"); - test(String.format("%,(10g", 12345.6), fmt."%,(10g\{12345.6}"); - test(String.format("%,(-10g", -12345.6), fmt."%,(-10g\{-12345.6}"); - test(String.format("%,(-10g", 0.0), fmt."%,(-10g\{0.0}"); - test(String.format("%,(-10g", 12345.6), fmt."%,(-10g\{12345.6}"); - test(String.format("%,(G", -12345.6), fmt."%,(G\{-12345.6}"); - test(String.format("%,(G", 0.0), fmt."%,(G\{0.0}"); - test(String.format("%,(G", 12345.6), fmt."%,(G\{12345.6}"); - test(String.format("%,(10G", -12345.6), fmt."%,(10G\{-12345.6}"); - test(String.format("%,(10G", 0.0), fmt."%,(10G\{0.0}"); - test(String.format("%,(10G", 12345.6), fmt."%,(10G\{12345.6}"); - test(String.format("%,(-10G", -12345.6), fmt."%,(-10G\{-12345.6}"); - test(String.format("%,(-10G", 0.0), fmt."%,(-10G\{0.0}"); - test(String.format("%,(-10G", 12345.6), fmt."%,(-10G\{12345.6}"); - test(String.format("%+g", -12345.6), fmt."%+g\{-12345.6}"); - test(String.format("%+g", 0.0), fmt."%+g\{0.0}"); - test(String.format("%+g", 12345.6), fmt."%+g\{12345.6}"); - test(String.format("%+10g", -12345.6), fmt."%+10g\{-12345.6}"); - test(String.format("%+10g", 0.0), fmt."%+10g\{0.0}"); - test(String.format("%+10g", 12345.6), fmt."%+10g\{12345.6}"); - test(String.format("%+-10g", -12345.6), fmt."%+-10g\{-12345.6}"); - test(String.format("%+-10g", 0.0), fmt."%+-10g\{0.0}"); - test(String.format("%+-10g", 12345.6), fmt."%+-10g\{12345.6}"); - test(String.format("%+G", -12345.6), fmt."%+G\{-12345.6}"); - test(String.format("%+G", 0.0), fmt."%+G\{0.0}"); - test(String.format("%+G", 12345.6), fmt."%+G\{12345.6}"); - test(String.format("%+10G", -12345.6), fmt."%+10G\{-12345.6}"); - test(String.format("%+10G", 0.0), fmt."%+10G\{0.0}"); - test(String.format("%+10G", 12345.6), fmt."%+10G\{12345.6}"); - test(String.format("%+-10G", -12345.6), fmt."%+-10G\{-12345.6}"); - test(String.format("%+-10G", 0.0), fmt."%+-10G\{0.0}"); - test(String.format("%+-10G", 12345.6), fmt."%+-10G\{12345.6}"); - test(String.format("%,+g", -12345.6), fmt."%,+g\{-12345.6}"); - test(String.format("%,+g", 0.0), fmt."%,+g\{0.0}"); - test(String.format("%,+g", 12345.6), fmt."%,+g\{12345.6}"); - test(String.format("%,+10g", -12345.6), fmt."%,+10g\{-12345.6}"); - test(String.format("%,+10g", 0.0), fmt."%,+10g\{0.0}"); - test(String.format("%,+10g", 12345.6), fmt."%,+10g\{12345.6}"); - test(String.format("%,+-10g", -12345.6), fmt."%,+-10g\{-12345.6}"); - test(String.format("%,+-10g", 0.0), fmt."%,+-10g\{0.0}"); - test(String.format("%,+-10g", 12345.6), fmt."%,+-10g\{12345.6}"); - test(String.format("%,+G", -12345.6), fmt."%,+G\{-12345.6}"); - test(String.format("%,+G", 0.0), fmt."%,+G\{0.0}"); - test(String.format("%,+G", 12345.6), fmt."%,+G\{12345.6}"); - test(String.format("%,+10G", -12345.6), fmt."%,+10G\{-12345.6}"); - test(String.format("%,+10G", 0.0), fmt."%,+10G\{0.0}"); - test(String.format("%,+10G", 12345.6), fmt."%,+10G\{12345.6}"); - test(String.format("%,+-10G", -12345.6), fmt."%,+-10G\{-12345.6}"); - test(String.format("%,+-10G", 0.0), fmt."%,+-10G\{0.0}"); - test(String.format("%,+-10G", 12345.6), fmt."%,+-10G\{12345.6}"); - test(String.format("%(+g", -12345.6), fmt."%(+g\{-12345.6}"); - test(String.format("%(+g", 0.0), fmt."%(+g\{0.0}"); - test(String.format("%(+g", 12345.6), fmt."%(+g\{12345.6}"); - test(String.format("%(+10g", -12345.6), fmt."%(+10g\{-12345.6}"); - test(String.format("%(+10g", 0.0), fmt."%(+10g\{0.0}"); - test(String.format("%(+10g", 12345.6), fmt."%(+10g\{12345.6}"); - test(String.format("%(+-10g", -12345.6), fmt."%(+-10g\{-12345.6}"); - test(String.format("%(+-10g", 0.0), fmt."%(+-10g\{0.0}"); - test(String.format("%(+-10g", 12345.6), fmt."%(+-10g\{12345.6}"); - test(String.format("%(+G", -12345.6), fmt."%(+G\{-12345.6}"); - test(String.format("%(+G", 0.0), fmt."%(+G\{0.0}"); - test(String.format("%(+G", 12345.6), fmt."%(+G\{12345.6}"); - test(String.format("%(+10G", -12345.6), fmt."%(+10G\{-12345.6}"); - test(String.format("%(+10G", 0.0), fmt."%(+10G\{0.0}"); - test(String.format("%(+10G", 12345.6), fmt."%(+10G\{12345.6}"); - test(String.format("%(+-10G", -12345.6), fmt."%(+-10G\{-12345.6}"); - test(String.format("%(+-10G", 0.0), fmt."%(+-10G\{0.0}"); - test(String.format("%(+-10G", 12345.6), fmt."%(+-10G\{12345.6}"); - test(String.format("%,(+g", -12345.6), fmt."%,(+g\{-12345.6}"); - test(String.format("%,(+g", 0.0), fmt."%,(+g\{0.0}"); - test(String.format("%,(+g", 12345.6), fmt."%,(+g\{12345.6}"); - test(String.format("%,(+10g", -12345.6), fmt."%,(+10g\{-12345.6}"); - test(String.format("%,(+10g", 0.0), fmt."%,(+10g\{0.0}"); - test(String.format("%,(+10g", 12345.6), fmt."%,(+10g\{12345.6}"); - test(String.format("%,(+-10g", -12345.6), fmt."%,(+-10g\{-12345.6}"); - test(String.format("%,(+-10g", 0.0), fmt."%,(+-10g\{0.0}"); - test(String.format("%,(+-10g", 12345.6), fmt."%,(+-10g\{12345.6}"); - test(String.format("%,(+G", -12345.6), fmt."%,(+G\{-12345.6}"); - test(String.format("%,(+G", 0.0), fmt."%,(+G\{0.0}"); - test(String.format("%,(+G", 12345.6), fmt."%,(+G\{12345.6}"); - test(String.format("%,(+10G", -12345.6), fmt."%,(+10G\{-12345.6}"); - test(String.format("%,(+10G", 0.0), fmt."%,(+10G\{0.0}"); - test(String.format("%,(+10G", 12345.6), fmt."%,(+10G\{12345.6}"); - test(String.format("%,(+-10G", -12345.6), fmt."%,(+-10G\{-12345.6}"); - test(String.format("%,(+-10G", 0.0), fmt."%,(+-10G\{0.0}"); - test(String.format("%,(+-10G", 12345.6), fmt."%,(+-10G\{12345.6}"); - - test(String.format("%a", -12345.6), fmt."%a\{-12345.6}"); - test(String.format("%a", 0.0), fmt."%a\{0.0}"); - test(String.format("%a", 12345.6), fmt."%a\{12345.6}"); - test(String.format("%10a", -12345.6), fmt."%10a\{-12345.6}"); - test(String.format("%10a", 0.0), fmt."%10a\{0.0}"); - test(String.format("%10a", 12345.6), fmt."%10a\{12345.6}"); - test(String.format("%-10a", -12345.6), fmt."%-10a\{-12345.6}"); - test(String.format("%-10a", 0.0), fmt."%-10a\{0.0}"); - test(String.format("%-10a", 12345.6), fmt."%-10a\{12345.6}"); - test(String.format("%A", -12345.6), fmt."%A\{-12345.6}"); - test(String.format("%A", 0.0), fmt."%A\{0.0}"); - test(String.format("%A", 12345.6), fmt."%A\{12345.6}"); - test(String.format("%10A", -12345.6), fmt."%10A\{-12345.6}"); - test(String.format("%10A", 0.0), fmt."%10A\{0.0}"); - test(String.format("%10A", 12345.6), fmt."%10A\{12345.6}"); - test(String.format("%-10A", -12345.6), fmt."%-10A\{-12345.6}"); - test(String.format("%-10A", 0.0), fmt."%-10A\{0.0}"); - test(String.format("%-10A", 12345.6), fmt."%-10A\{12345.6}"); - - test("aaa%false", fmt."aaa%%%b\{false}"); - test("aaa" + System.lineSeparator() + "false", fmt."aaa%n%b\{false}"); - - assertThrows( - MissingFormatArgumentException.class, - () -> fmt. "%10ba\{ false }", - "Format specifier '%10b is not immediately followed by an embedded expression'"); - - assertThrows( - MissingFormatArgumentException.class, - () ->fmt. "%ba\{ false }", - "Format specifier '%b is not immediately followed by an embedded expression'"); - - assertThrows( - MissingFormatArgumentException.class, - () ->fmt. "%b", - "Format specifier '%b is not immediately followed by an embedded expression'"); - assertThrows( - UnknownFormatConversionException.class, - () ->fmt. "%0", - "Conversion = '0'"); - } -} diff --git a/test/jdk/java/lang/template/StringTemplateTest.java b/test/jdk/java/lang/template/StringTemplateTest.java deleted file mode 100644 index 53aca6d83ff..00000000000 --- a/test/jdk/java/lang/template/StringTemplateTest.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (c) 2023, 2024, 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. - * - * 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. - */ - -/* - * @test - * @bug 0000000 - * @summary Exercise runtime handing of templated strings. - * @enablePreview true - */ - -import java.io.ByteArrayOutputStream; -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.URI; -import java.util.*; -import java.util.function.Supplier; -import javax.tools.FileObject; -import javax.tools.ForwardingJavaFileManager; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import static javax.tools.StandardLocation.CLASS_OUTPUT; -import javax.tools.ToolProvider; - -public class StringTemplateTest { - enum Category{GENERAL, CHARACTER, INTEGRAL, BIG_INT, FLOATING, BIG_FLOAT, DATE}; - - static final String[] GENERAL = {"true", "false", "(Object)null", "STR", "BO", "BOOL", "(Boolean)null"}; - static final String[] CHARS = {"C", "CHAR", "(Character)null"}; - static final String[] INTS = {"L", "LONG", "I", "INT", "S", "SHORT", "BY", "BYTE", "Long.MAX_VALUE", "Long.MIN_VALUE", "(Long)null", "(Integer)null", "(Short)null", "(Byte)null"}; - static final String[] BIGINTS = {}; - static final String[] FLOATS = {"F", "FLOAT", "D", "DOUBLE", "Double.NEGATIVE_INFINITY", "Double.NaN", "Double.MAX_VALUE", "(Double)null", "(Float)null"}; - static final String[] BIGFLOATS = {}; - static final String[] DATES = {}; - - final Random r = new Random(1); - - String randomValue(Category category) { - return switch (category) { - case GENERAL -> randomChoice( - GENERAL, - () -> randomValue(Category.CHARACTER), - () -> randomValue(Category.INTEGRAL), - () -> randomValue(Category.BIG_INT), - () -> randomValue(Category.FLOATING), - () -> randomValue(Category.BIG_FLOAT), - () -> randomValue(Category.DATE), - () -> "\"" + randomString(r.nextInt(10)) + "\""); - case CHARACTER -> randomChoice( - CHARS, - () -> "\'" + randomString(1) + "\'"); - case INTEGRAL -> randomChoice( - INTS, - () -> "(byte)" + String.valueOf(r.nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE)), - () -> "(short)" + String.valueOf(r.nextInt(Short.MIN_VALUE, Short.MAX_VALUE)), - () -> String.valueOf(r.nextInt()), - () -> r.nextLong() + "l"); - case BIG_INT -> randomChoice( - BIGINTS, - () -> "new java.math.BigInteger(\"" + r.nextLong() + "\")"); - case FLOATING -> randomChoice( - FLOATS, - () -> String.valueOf(r.nextDouble()), - () -> r.nextFloat() + "f"); - case BIG_FLOAT -> randomChoice( - BIGFLOATS, - () -> "new java.math.BigDecimal(" + r.nextDouble() + ")"); - case DATE -> randomChoice( - DATES, - () -> "new java.util.Date(" + r.nextLong() + "l)", - () -> r.nextLong() + "l"); - }; - } - - String randomChoice(Supplier... suppl) { - return suppl[r.nextInt(suppl.length)].get(); - } - - String randomChoice(String... values) { - return values[r.nextInt(values.length)]; - } - - String randomChoice(String[] values, Supplier... suppl) { - int i = r.nextInt(values.length + suppl.length); - return i < values.length ? values[i] : suppl[i - values.length].get(); - } - - String randomString(int length) { - var sb = new StringBuilder(length << 2); - while (length-- > 0) { - char ch = (char)r.nextInt(9, 128); - var s = switch (ch) { - case '\t' -> "\\t"; - case '\'' -> "\\\'"; - case '"' -> "\\\""; - case '\r' -> "\\r"; - case '\\' -> "\\\\"; - case '\n' -> "\\n"; - case '\f' -> "\\f"; - case '\b' -> "\\b"; - default -> ch + ""; - }; - sb.append(s); - } - return sb.toString(); - } - - String randomFormat(Category category) { - char c; - return "%" + switch (category) { - case GENERAL -> randomWidth("-") + randomPrecision() + randomChar("bBhHsS"); - case CHARACTER -> randomWidth("-") + randomChar("cC"); - case INTEGRAL -> switch (c = randomChar("doxX")) { - case 'd' -> randomFlags("+ ,("); - default -> randomFlags(""); - } + randomWidth("-0") + c; - case BIG_INT -> switch (c = randomChar("doxX")) { - case 'd' -> randomFlags("+ ,("); - default -> randomFlags("+ ("); - } + randomWidth("-0") + c; - case FLOATING -> switch (c = randomChar("eEfaAgG")) { - case 'a', 'A' -> randomFlags("+ ") + randomWidth("-0"); - case 'e', 'E' -> randomFlags("+ (") + randomWidth("-0") + randomPrecision(); - default -> randomFlags("+ ,(") + randomWidth("-0") + randomPrecision(); - } + c; - case BIG_FLOAT -> switch (c = randomChar("eEfgG")) { - case 'e', 'E' -> randomFlags("+ (") + randomWidth("-0") + randomPrecision(); - default -> randomFlags("+ ,(") + randomWidth("-0") + randomPrecision(); - } + c; - case DATE -> randomWidth("-") + randomChar("tT") + randomChar("BbhAaCYyjmdeRTrDFc"); - }; - } - - String randomFlags(String flags) { - var sb = new StringBuilder(flags.length()); - for (var f : flags.toCharArray()) { - if (r.nextBoolean() && (f != ' ' || sb.length() == 0 || sb.charAt(sb.length() - 1) != '+')) sb.append(f); - } - return sb.toString(); - } - - char randomChar(String chars) { - return chars.charAt(r.nextInt(chars.length())); - } - - String randomWidth(String flags) { - var f = r.nextInt(flags.length() + 1); - return r.nextBoolean() ? (r.nextBoolean() ? flags.charAt(r.nextInt(flags.length())) : "") + String.valueOf(r.nextInt(10) + 1) : ""; - } - - String randomPrecision() { - return r.nextBoolean() ? '.' + String.valueOf(r.nextInt(10) + 1) : ""; - } - - public Class compile() throws Exception { - var classes = new HashMap(); - var fileManager = new ForwardingJavaFileManager(ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null)) { - @Override - public ClassLoader getClassLoader(JavaFileManager.Location location) { - return new ClassLoader() { - @Override - public Class loadClass(String name) throws ClassNotFoundException { - try { - return super.loadClass(name); - } catch (ClassNotFoundException e) { - byte[] classData = classes.get(name); - return defineClass(name, classData, 0, classData.length); - } - } - }; - } - @Override - public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String name, JavaFileObject.Kind kind, FileObject originatingSource) throws UnsupportedOperationException { - return new SimpleJavaFileObject(URI.create(name + ".class"), JavaFileObject.Kind.CLASS) { - @Override - public OutputStream openOutputStream() { - return new FilterOutputStream(new ByteArrayOutputStream()) { - @Override - public void close() throws IOException { - classes.put(name, ((ByteArrayOutputStream)out).toByteArray()); - } - }; - } - }; - } - }; - var source = genSource(); -// System.out.println(source); - if (ToolProvider.getSystemJavaCompiler().getTask(null, fileManager, null, - List.of("--enable-preview", "-source", String.valueOf(Runtime.version().feature())), null, - List.of(SimpleJavaFileObject.forSource(URI.create("StringTemplateTest$.java"), source)) - ).call()) { - return fileManager.getClassLoader(CLASS_OUTPUT).loadClass("StringTemplateTest$"); - } else { - throw new AssertionError("compilation failed"); - } - } - - String genFragments(Category c) { - var fragments = new LinkedList(); - for (int i = 0; i < 1500; i++) { - var format = randomFormat(c); - var value = randomValue(c); - var qValue = value.replace("\\", "\\\\").replace("\"", "\\\""); - fragments.add(STR."test(FMT.\"\{format}\\{\{value}}\", \"\{format}\", \"\{qValue}\", \{value}, log);"); - } - return String.join("\n ", fragments); - } - - String genSource() { - return STR.""" - import java.util.FormatProcessor; - import java.util.Locale; - - public class StringTemplateTest$ { - static final FormatProcessor FMT = FormatProcessor.create(Locale.US); - static String STR = "this is static String"; - static char C = 'c'; - static Character CHAR = 'C'; - static long L = -12345678910l; - static Long LONG = 9876543210l; - static int I = 42; - static Integer INT = -49; - static boolean BO = true; - static Boolean BOOL = false; - static short S = 13; - static Short SHORT = -17; - static byte BY = -3; - static Byte BYTE = 12; - static float F = 4.789f; - static Float FLOAT = -0.000006f; - static double D = 6545745.6734654563; - static Double DOUBLE = -4323.7645676574; - - public static void run(java.util.List log) { - runGeneral(log); - runCharacter(log); - runIntegral(log); - runBigInt(log); - runFloating(log); - runBigFloat(log); - runDate(log); - } - public static void runGeneral(java.util.List log) { - \{genFragments(Category.GENERAL)} - } - public static void runCharacter(java.util.List log) { - \{genFragments(Category.CHARACTER)} - } - public static void runIntegral(java.util.List log) { - \{genFragments(Category.INTEGRAL)} - } - public static void runBigInt(java.util.List log) { - \{genFragments(Category.BIG_INT)} - } - public static void runFloating(java.util.List log) { - \{genFragments(Category.FLOATING)} - } - public static void runBigFloat(java.util.List log) { - \{genFragments(Category.BIG_FLOAT)} - } - public static void runDate(java.util.List log) { - \{genFragments(Category.DATE)} - } - static void test(String fmt, String format, String expression, Object value, java.util.List log) { - var formatted = String.format(java.util.Locale.US, format, value); - if (!fmt.equals(formatted)) { - log.add(" format: '%s' expression: '%s' value: '%s' expected: '%s' found: '%s'".formatted(format, expression, value, formatted, fmt)); - } - } - } - """; - } - - public static void main(String... args) throws Exception { - var log = new LinkedList(); - new StringTemplateTest().compile().getMethod("run", List.class).invoke(null, log); - if (!log.isEmpty()) { - log.forEach(System.out::println); - throw new AssertionError(STR."failed \{log.size()} tests"); - } - } -} diff --git a/test/jdk/java/lang/template/T8313809.java b/test/jdk/java/lang/template/T8313809.java deleted file mode 100644 index b673b2b9c44..00000000000 --- a/test/jdk/java/lang/template/T8313809.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - * - * 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. - */ - -/* - * @test - * @bug 8313809 - * @summary String template fails with java.lang.StringIndexOutOfBoundsException if last fragment is UTF16 -. - * @enablePreview true - */ - -import static java.util.FormatProcessor.FMT; - -public class T8313809 { - public static void main(final String[] args) throws Exception { - double sum = 12.34; - final String message = FMT."The sum is : %f\{sum} €"; // this fails - if (!message.equals("The sum is : 12.340000 €")) { - throw new RuntimeException("Incorrect result"); - } - } -} - diff --git a/test/langtools/jdk/jshell/CompletenessTest.java b/test/langtools/jdk/jshell/CompletenessTest.java index 09fcbfbdd39..06cbc6bd41f 100644 --- a/test/langtools/jdk/jshell/CompletenessTest.java +++ b/test/langtools/jdk/jshell/CompletenessTest.java @@ -89,8 +89,7 @@ public class CompletenessTest extends KullaTesting { "record.any", "record()", "record(1)", - "record.length()", - "\"\\{0}\"" + "record.length()" }; static final String[] complete_with_semi = new String[] { @@ -235,10 +234,7 @@ public class CompletenessTest extends KullaTesting { static final String[] unknown = new String[] { "new ;", "\"", - "\"\\", - "\"\\{", - "\"\\{0", - "\"\\{0}", + "\"\\" }; static final Map statusToCases = new HashMap<>(); @@ -384,9 +380,6 @@ public class CompletenessTest extends KullaTesting { assertStatus("\"\"\"\ntext\\\"\"\"\\\"\"\"", DEFINITELY_INCOMPLETE, null); assertStatus("\"\"\"\ntext\\\"\"\"\\\"\"\"\"\"\"", COMPLETE, "\"\"\"\ntext\\\"\"\"\\\"\"\"\"\"\""); assertStatus("\"\"\"\n\\", DEFINITELY_INCOMPLETE, null); - assertStatus("\"\"\"\n\\{", DEFINITELY_INCOMPLETE, null); - assertStatus("\"\"\"\n\\{0", DEFINITELY_INCOMPLETE, null); - assertStatus("\"\"\"\n\\{0}", DEFINITELY_INCOMPLETE, null); } public void testMiscSource() { diff --git a/test/langtools/tools/javac/diags/examples/StringTemplate.java b/test/langtools/tools/javac/diags/examples/StringTemplate.java deleted file mode 100644 index e35cbab11e4..00000000000 --- a/test/langtools/tools/javac/diags/examples/StringTemplate.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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. - * - * 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. - */ - - // key: compiler.misc.feature.string.templates - // key: compiler.warn.preview.feature.use.plural - // options: --enable-preview -source ${jdk.version} -Xlint:preview - -class StringTemplate { - String m() { - int x = 10, y = 20; - return STR."\{x} + \{y} = \{x + y}"; - } -} diff --git a/test/langtools/tools/javac/diags/examples/StringTemplateNoProcessor.java b/test/langtools/tools/javac/diags/examples/StringTemplateNoProcessor.java deleted file mode 100644 index f909ec726d2..00000000000 --- a/test/langtools/tools/javac/diags/examples/StringTemplateNoProcessor.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - * - * 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. - */ - - // key: compiler.err.processor.missing.from.string.template.expression - // key: compiler.misc.feature.string.templates - // key: compiler.warn.preview.feature.use.plural - // options: --enable-preview -source ${jdk.version} -Xlint:preview - -class StringTemplateNoProcessor { - String m() { - int x = 10, y = 20; - return "\{x} + \{y} = \{x + y}"; - } -} diff --git a/test/langtools/tools/javac/diags/examples/StringTemplateNotProcessor.java b/test/langtools/tools/javac/diags/examples/StringTemplateNotProcessor.java deleted file mode 100644 index cd71f7df7e1..00000000000 --- a/test/langtools/tools/javac/diags/examples/StringTemplateNotProcessor.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * - * 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. - */ - - // key: compiler.note.preview.filename - // key: compiler.err.cant.resolve.location.args - // key: compiler.misc.location - // key: compiler.note.preview.recompile - // key: compiler.err.not.a.processor.type - // options: --enable-preview -source ${jdk.version} - -import java.lang.*; - -class StringTemplateNotProcessor { - String m() { - String processor = ""; - int x = 10, y = 20; - return processor."\{x} + \{y} = \{x + y}"; - } -} diff --git a/test/langtools/tools/javac/diags/examples/StringTemplateRawProcessor.java b/test/langtools/tools/javac/diags/examples/StringTemplateRawProcessor.java deleted file mode 100644 index 9ab344fb021..00000000000 --- a/test/langtools/tools/javac/diags/examples/StringTemplateRawProcessor.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - * - * 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. - */ - - // key: compiler.note.preview.filename - // key: compiler.note.preview.recompile - // key: compiler.misc.unexpected.ret.val - // key: compiler.err.prob.found.req - // options: --enable-preview -source ${jdk.version} - -import java.lang.*; -import java.lang.StringTemplate.Processor; - -class StringTemplateRawProcessor { - void m() { - Processor processor = ts -> ts.interpolate(); - try { - int x = 10, y = 20; - return processor."\{x} + \{y} = \{x + y}"; - } catch (Throwable x) { - throw new RuntimeException(x); - } - } -} - diff --git a/test/langtools/tools/javac/diags/examples/StringTemplateUnclosedString.java b/test/langtools/tools/javac/diags/examples/StringTemplateUnclosedString.java deleted file mode 100644 index c96ccf96ee3..00000000000 --- a/test/langtools/tools/javac/diags/examples/StringTemplateUnclosedString.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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. - * - * 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. - */ - - // key: compiler.note.preview.filename - // key: compiler.note.preview.recompile - // key: compiler.err.unclosed.str.lit - // key: compiler.err.string.template.is.not.well.formed - // options: --enable-preview -source ${jdk.version} - -import java.lang.*; - -class StringTemplateUnclosedString { - String m() { - int x = 10; - return STR."\{x"; - } -} diff --git a/test/langtools/tools/javac/diags/examples/StringTemplateUnclosedTextBlock.java b/test/langtools/tools/javac/diags/examples/StringTemplateUnclosedTextBlock.java deleted file mode 100644 index 87460aba029..00000000000 --- a/test/langtools/tools/javac/diags/examples/StringTemplateUnclosedTextBlock.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - * - * 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. - */ - - // key: compiler.note.preview.filename - // key: compiler.note.preview.recompile - // key: compiler.err.unclosed.text.block - // key: compiler.err.text.block.template.is.not.well.formed - // key: compiler.err.premature.eof - // options: --enable-preview -source ${jdk.version} - -import java.lang.*; - -class StringTemplateUnclosedTextBlock { - String m() { - int x = 10; - return STR.""" - aaa - \{x - """ - ; - } -} diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index f9ccb39c05e..93b2b51a8fa 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -1917,52 +1917,6 @@ public class JavacParserTest extends TestCase { }.scan(cut, null); } - @Test - void testStringTemplate1() throws IOException { - String code = """ - package test; - public class Test { - Test(int a) { - String s = "prefix \\{a} suffix"; - } - } - """; - - JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, - null, null, Arrays.asList(new MyFileObject(code))); - CompilationUnitTree cut = ct.parse().iterator().next(); - ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); - MethodTree constr = (MethodTree) clazz.getMembers().get(0); - VariableTree decl = (VariableTree) constr.getBody().getStatements().get(0); - SourcePositions sp = Trees.instance(ct).getSourcePositions(); - int initStart = (int) sp.getStartPosition(cut, decl.getInitializer()); - int initEnd = (int) sp.getEndPosition(cut, decl.getInitializer()); - assertEquals("correct templated String span expected", code.substring(initStart, initEnd), "\"prefix \\{a} suffix\""); - } - - @Test - void testStringTemplate2() throws IOException { - String code = """ - package test; - public class Test { - Test(int a) { - String s = STR."prefix \\{a} suffix"; - } - } - """; - - JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, - null, null, Arrays.asList(new MyFileObject(code))); - CompilationUnitTree cut = ct.parse().iterator().next(); - ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); - MethodTree constr = (MethodTree) clazz.getMembers().get(0); - VariableTree decl = (VariableTree) constr.getBody().getStatements().get(0); - SourcePositions sp = Trees.instance(ct).getSourcePositions(); - int initStart = (int) sp.getStartPosition(cut, decl.getInitializer()); - int initEnd = (int) sp.getEndPosition(cut, decl.getInitializer()); - assertEquals("correct templated String span expected", code.substring(initStart, initEnd), "STR.\"prefix \\{a} suffix\""); - } - @Test //JDK-8293897 void testImplicitFinalInTryWithResources() throws IOException { String code = """ @@ -2044,63 +1998,6 @@ public class JavacParserTest extends TestCase { }.scan(cut, null); } - @Test - void testIncompleteStringTemplate() throws IOException { - String template = "\"\\{o.toString()}\""; - String prefix = """ - package t; - class Test { - void test(Object o) { - String s = STR."""; - - Worker verifyParseable = task -> { - try { - task.parse().iterator().next(); - return null; - } catch (IOException ex) { - throw new AssertionError(ex); - } - }; - JavacTaskPool pool = new JavacTaskPool(1); - DiagnosticListener dl = d -> {}; - List options = List.of("--enable-preview", - "-source", System.getProperty("java.specification.version")); - for (int i = 0; i < template.length(); i++) { - pool.getTask(null, fm, dl, options, - null, Arrays.asList(new MyFileObject(prefix + template.substring(0, i))), - verifyParseable - ); - } - for (int i = 0; i < template.length() - 1; i++) { - pool.getTask(null, fm, dl, options, - null, Arrays.asList(new MyFileObject(prefix + template.substring(0, i) + "\"")), - verifyParseable); - } - String incomplete = prefix + "\"\\{o."; - pool.getTask(null, fm, dl, options, - null, Arrays.asList(new MyFileObject(incomplete)), task -> { - try { - CompilationUnitTree cut = task.parse().iterator().next(); - String result = cut.toString().replaceAll("\\R", "\n"); - System.out.println("RESULT\n" + result); - assertEquals("incorrect AST", - result, - """ - package t; - \n\ - class Test { - \n\ - void test(Object o) { - String s = STR.; - } - }"""); - return null; - } catch (IOException ex) { - throw new AssertionError(ex); - } - }); - } - @Test //JDK-8295401 void testModuleInfoProvidesRecovery() throws IOException { String code = """ diff --git a/test/langtools/tools/javac/template/Basic.java b/test/langtools/tools/javac/template/Basic.java deleted file mode 100644 index d6d36de18ca..00000000000 --- a/test/langtools/tools/javac/template/Basic.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * 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. - * - * 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. - */ - -/* - * @test - * @bug 0000000 - * @summary Exercise javac handing of templated strings. - * @library /tools/lib - * @modules jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.main - * @build toolbox.ToolBox toolbox.JavacTask - * @run main Basic - */ - - -import toolbox.JavacTask; -import toolbox.JavaTask; -import toolbox.Task; -import toolbox.ToolBox; - -public class Basic { - private static ToolBox TOOLBOX = new ToolBox(); - private static final String JAVA_VERSION = System.getProperty("java.specification.version"); - - public static void main(String... arg) { - primitivesTest(); - missingPartsTest(); - expressionsTest(); - invalidExpressionsTest(); - processorTest(); - } - - /* - * Primitive types test. - */ - static void primitivesTest() { - for (String type : new String[] { - "byte", - "short", - "int", - "long", - "float", - "double" - }) { - compPass(type + " x = 10; " + type + " y = 20; StringTemplate result = RAW.\"\\{x} + \\{y} = \\{x + y}\";"); - } - } - - /* - * Missing parts test. - */ - static void missingPartsTest() { - compFail(""" - int x = 10; - StringTemplate result = RAW."\\{x"; - """); - compFail(""" - int x = 10; - StringTemplate result = RAW."\\{{x}"; - """); - compFail(""" - int x = 10; - StringTemplate result = RAW."\\{x + }"; - """); - compFail(""" - int x = 10; - StringTemplate result = RAW."\\{ * x }"; - """); - compFail(""" - int x = 10; - StringTemplate result = RAW."\\{ (x + x }"; - """); - } - - /* - * Expressions test. - */ - static void expressionsTest() { - compPass(""" - int x = 10; - int[] y = new int[] { 10, 20, 30 }; - StringTemplate result1 = RAW."\\{x + 1}"; - StringTemplate result2 = RAW."\\{x + x}"; - StringTemplate result3 = RAW."\\{x - x}"; - StringTemplate result4 = RAW."\\{x * x}"; - StringTemplate result5 = RAW."\\{x / x}"; - StringTemplate result6 = RAW."\\{x % x}"; - StringTemplate result7 = RAW."\\{x + (x + x)}"; - StringTemplate result8 = RAW."\\{y[x - 9]}"; - StringTemplate result9 = RAW."\\{System.out}"; - StringTemplate result10 = RAW.\""" - \\{ "a string" } - \"""; - """); - compPass(""" - StringTemplate result = RAW.\""" - \\{ - new Collection() { - @Override public int size() { return 0; } - @Override public boolean isEmpty() { return false; } - @Override public boolean contains(Object o) { return false; } - @Override public Iterator iterator() { return null; } - @Override public Object[] toArray() { return new Object[0]; } - @Override public T[] toArray(T[] a) { return null; } - @Override public boolean add(String s) { return false; } - @Override public boolean remove(Object o) { return false; } - @Override public boolean containsAll(Collection c) { return false; } - @Override public boolean addAll(Collection c) { return false; } - @Override public boolean removeAll(Collection c) { return false; } - @Override public boolean retainAll(Collection c) { return false; } - @Override public void clear() { } - } - } - \"""; - """); - } - - /* - * Invalid expressions test. - */ - static void invalidExpressionsTest() { - compFail(""" - int x = 10; - StringTemplate result = RAW."\\{ (x == x }"; - """); - compFail(""" - int x = 10; - StringTemplate result = RAW."\\{ true ? : x - 1 }"; - """); - compFail(""" - String result = RAW."\\{ 'a }"; - """); - compFail(""" - int x = 10; - StringTemplate result = RAW."\\{ Math.min(, x - 1) }"; - """); - compFail(""" - int x = 10; - StringTemplate result = RAW."\\{ \\tx }"; - """); - } - - /* - * Processor test. - */ - static void processorTest() { - compPass(""" - int x = 10, y = 20; - String string = STR."\\{x} + \\{y} = \\{x + y}"; - """); - compFail(""" - int x = 10, y = 20; - String processor = "abc"; - String string = processor."\\{x} + \\{y} = \\{x + y}"; - """); - compFail(""" - int x = 10, y = 20; - long processor = 100; - String string = processor."\\{x} + \\{y} = \\{x + y}"; - """); - } - - /* - * Test source for successful compile. - */ - static void compPass(String code) { - String source = """ - import java.lang.*; - import java.util.*; - import static java.lang.StringTemplate.RAW; - public class TEST { - public static void main(String... arg) { - """ + - code.indent(8) + - """ - } - } - """; - String output = new JavacTask(TOOLBOX) - .sources(source) - .classpath(".") - .options("-encoding", "utf8", "--enable-preview", "-source", JAVA_VERSION) - .run() - .writeAll() - .getOutput(Task.OutputKind.DIRECT); - - if (output.contains("compiler.err")) { - throw new RuntimeException("Error detected"); - } - } - - /* - * Test source for unsuccessful compile and specific error. - */ - static void compFail(String code) { - String source = """ - import java.lang.*; - import java.util.*; - import static java.lang.StringTemplate.RAW; - public class TEST { - public static void main(String... arg) { - """ + - code.indent(8) + - """ - } - } - """; - String errors = new JavacTask(TOOLBOX) - .sources(source) - .classpath(".") - .options("-XDrawDiagnostics", "-encoding", "utf8", "--enable-preview", "-source", JAVA_VERSION) - .run(Task.Expect.FAIL) - .writeAll() - .getOutput(Task.OutputKind.DIRECT); - - if (!errors.contains("compiler.err")) { - throw new RuntimeException("No error detected"); - } - } -} diff --git a/test/langtools/tools/javac/template/T8312814.java b/test/langtools/tools/javac/template/T8312814.java deleted file mode 100644 index 15207828a7d..00000000000 --- a/test/langtools/tools/javac/template/T8312814.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - * - * 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. - */ - -/* - * @test T8312814 - * @summary Verify proper behavior of TransType w.r.t. templated Strings - * @enablePreview - * @compile T8312814.java - */ - - -import java.util.List; - -public class T8312814 { - void x(List> list) { - list.get(0).""; - } -} - diff --git a/test/langtools/tools/javac/template/TreeScannerTest.java b/test/langtools/tools/javac/template/TreeScannerTest.java deleted file mode 100644 index ffd7112ab47..00000000000 --- a/test/langtools/tools/javac/template/TreeScannerTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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. - * - * 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. - */ - -/* - * @test - * @summary Verify proper behavior of TreeScanner w.r.t. templated Strings - * @modules jdk.compiler - */ - -import java.io.*; -import java.util.*; -import javax.tools.*; -import com.sun.source.tree.*; -import com.sun.source.util.*; -import java.net.URI; -import java.net.URISyntaxException; - -public class TreeScannerTest { - private static final String JAVA_VERSION = System.getProperty("java.specification.version"); - - public static void main(String... args) throws Exception { - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - String code = """ - public class Test { - private void test(int a) { - String s1 = TEST."p\\{a}s"; - String s2 = "p\\{a}s"; - } - } - """; - JavacTask task = (JavacTask) compiler.getTask(null, null, null, - List.of("--enable-preview", "-source", JAVA_VERSION), null, List.of(new TestJFO(code))); - StringBuilder output = new StringBuilder(); - TreeScanner checker = new TreeScanner() { - private boolean log; - - @Override - public Void visitStringTemplate(StringTemplateTree node, Void p) { - boolean prevLog = log; - try { - log = true; - return super.visitStringTemplate(node, p); - } finally { - log = prevLog; - } - } - - @Override - public Void scan(Tree tree, Void p) { - if (log) { - output.append("("); - output.append(tree != null ? tree.getKind() : "null"); - try { - return super.scan(tree, p); - } finally { - output.append(")"); - } - } else { - return super.scan(tree, p); - } - } - - }; - - checker.scan(task.parse(), null); - - String expected = "(IDENTIFIER)(IDENTIFIER)(null)(IDENTIFIER)"; - if (!expected.equals(output.toString())) { - throw new AssertionError("expected output not found, found: " + output); - } - } - - private static final class TestJFO extends SimpleJavaFileObject { - private final String code; - - public TestJFO(String code) throws URISyntaxException, IOException { - super(new URI("mem://Test.java"), Kind.SOURCE); - this.code = code; - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - return code; - } - - } -} diff --git a/test/langtools/tools/javac/tree/TreeKindTest.java b/test/langtools/tools/javac/tree/TreeKindTest.java index 626288af168..15b4ae37bbe 100644 --- a/test/langtools/tools/javac/tree/TreeKindTest.java +++ b/test/langtools/tools/javac/tree/TreeKindTest.java @@ -123,10 +123,6 @@ public class TreeKindTest { ok = ok & verify(k, i, i == OpensTree.class); break; - case TEMPLATE: - ok = ok & verify(k, i, i == StringTemplateTree.class); - break; - case OTHER: ok = ok & verify(k, i, i == null); break; diff --git a/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java b/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java index 63814220c03..aa30682e1bc 100644 --- a/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java +++ b/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java @@ -92,7 +92,6 @@ public class ListModuleDeps { public Object[][] jdkModules() { return new Object[][]{ {"jdk.compiler", new String[]{ - "java.base/jdk.internal.javac", "java.base/jdk.internal.jmod", "java.base/jdk.internal.misc", "java.base/jdk.internal.module", diff --git a/test/micro/org/openjdk/bench/java/lang/StringTemplateFMT.java b/test/micro/org/openjdk/bench/java/lang/StringTemplateFMT.java deleted file mode 100644 index 60a3024c7f8..00000000000 --- a/test/micro/org/openjdk/bench/java/lang/StringTemplateFMT.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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. - * - * 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 org.openjdk.bench.java.lang; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; - -import java.util.concurrent.TimeUnit; - -import static java.util.FormatProcessor.FMT; - -/* - * This benchmark measures StringTemplate.FMT FormatProcessor performance; - * exactly mirroring {@link org.openjdk.bench.java.lang.StringFormat} benchmark - */ -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@State(Scope.Thread) -@Warmup(iterations = 5, time = 1) -@Measurement(iterations = 5, time = 1) -@Fork(value = 3, jvmArgsAppend = "--enable-preview") -public class StringTemplateFMT { - - public String s = "str"; - public int i = 17; - - @Benchmark - public String stringFormat() { - return FMT."%s\{s}"; - } - - @Benchmark - public String stringIntFormat() { - return FMT."%s\{s} %d\{i}"; - } - - @Benchmark - public String widthStringFormat() { - return FMT."%3s\{s}"; - } - - @Benchmark - public String widthStringIntFormat() { - return FMT."%3s\{s} %d\{i}"; - } - - @Benchmark - public String complexFormat() { - return FMT."%3s\{s} %10d\{i} %4S\{s} %04X\{i} %4S\{s} %04X\{i} %4S\{s} %04X\{i}"; - } -}