Skip to content

Commit

Permalink
ICU-22893 Remove support for Unsupported, Private & Reserved constructs
Browse files Browse the repository at this point in the history
- Matching PR #883 in the message-format-wg repo.
- Also removes some unused imports
  • Loading branch information
mihnita committed Sep 18, 2024
1 parent 1b33f5e commit 09c5aa1
Show file tree
Hide file tree
Showing 15 changed files with 30 additions and 264 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public SelectMessage(
*/
@Deprecated
public interface Declaration {
// Provides a common type for InputDeclaration, LocalDeclaration, and UnsupportedStatement.
// Provides a common type for InputDeclaration, and LocalDeclaration
}

/**
Expand Down Expand Up @@ -130,28 +130,6 @@ public LocalDeclaration(String name, Expression value) {
}
}

/**
* @internal ICU 72 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
public static class UnsupportedStatement implements Declaration {
public final String keyword;
public final String body;
public final List<Expression> expressions;

/**
* @internal ICU 72 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
public UnsupportedStatement(String keyword, String body, List<Expression> expressions) {
this.keyword = keyword;
this.body = body;
this.expressions = expressions;
}
}

/**
* @internal ICU 72 technology preview
* @deprecated This API is for technology preview only.
Expand Down Expand Up @@ -312,26 +290,6 @@ public FunctionExpression(FunctionAnnotation annotation, List<Attribute> attribu
}
}

/**
* @internal ICU 72 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
public static class UnsupportedExpression implements Expression {
public final UnsupportedAnnotation annotation;
public final List<Attribute> attributes;

/**
* @internal ICU 72 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
public UnsupportedExpression(UnsupportedAnnotation annotation, List<Attribute> attributes) {
this.annotation = annotation;
this.attributes = attributes;
}
}

/**
* @internal ICU 72 technology preview
* @deprecated This API is for technology preview only.
Expand Down Expand Up @@ -441,24 +399,6 @@ public Option(String name, LiteralOrVariableRef value) {
}
}

/**
* @internal ICU 72 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
public static class UnsupportedAnnotation implements Annotation {
public final String source;

/**
* @internal ICU 72 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
public UnsupportedAnnotation(String source) {
this.source = source;
}
}

// Markup

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
import com.ibm.icu.message2.MFDataModel.Pattern;
import com.ibm.icu.message2.MFDataModel.SelectMessage;
import com.ibm.icu.message2.MFDataModel.StringPart;
import com.ibm.icu.message2.MFDataModel.UnsupportedAnnotation;
import com.ibm.icu.message2.MFDataModel.UnsupportedExpression;
import com.ibm.icu.message2.MFDataModel.VariableRef;
import com.ibm.icu.message2.MFDataModel.Variant;
import com.ibm.icu.util.Calendar;
Expand Down Expand Up @@ -104,7 +102,8 @@ String format(Map<String, Object> arguments) {
variables = resolveDeclarations(sm.declarations, arguments);
patternToRender = findBestMatchingPattern(sm, variables, arguments);
} else {
formattingError("");
fatalFormattingError("Unknown message type.");
// formattingError throws, so the return does not actually happen
return "ERROR!";
}

Expand All @@ -123,10 +122,8 @@ String format(Map<String, Object> arguments) {
result.append(formattedExpression.getFormattedValue().toString());
} else if (part instanceof MFDataModel.Markup) {
// Ignore
} else if (part instanceof MFDataModel.UnsupportedExpression) {
// Ignore
} else {
formattingError("Unknown part type: " + part);
fatalFormattingError("Unknown part type: " + part);
}
}
return result.toString();
Expand Down Expand Up @@ -217,7 +214,7 @@ private Pattern findBestMatchingPattern(
// spec: Append `ks` as the last element of the list `keys`.
keys.add(ks);
} else {
formattingError("Literal expected, but got " + key);
fatalFormattingError("Literal expected, but got " + key);
}
}
// spec: Let `rv` be the resolved value at index `i` of `res`.
Expand Down Expand Up @@ -249,7 +246,7 @@ private Pattern findBestMatchingPattern(
}
// spec: Assert that `key` is a _literal_.
if (!(key instanceof Literal)) {
formattingError("Literal expected");
fatalFormattingError("Literal expected");
}
// spec: Let `ks` be the resolved value of `key`.
String ks = ((Literal) key).value;
Expand Down Expand Up @@ -304,7 +301,7 @@ private Pattern findBestMatchingPattern(
if (!(key instanceof CatchallKey)) {
// spec: Assert that `key` is a _literal_.
if (!(key instanceof Literal)) {
formattingError("Literal expected");
fatalFormattingError("Literal expected");
}
// spec: Let `ks` be the resolved value of `key`.
String ks = ((Literal) key).value;
Expand Down Expand Up @@ -356,7 +353,7 @@ private static int sortVariants(IntVarTuple o1, IntVarTuple o2) {
List<LiteralOrCatchallKey> v1 = o1.variant.keys;
List<LiteralOrCatchallKey> v2 = o1.variant.keys;
if (v1.size() != v2.size()) {
formattingError("The number of keys is not equal.");
fatalFormattingError("The number of keys is not equal.");
}
for (int i = 0; i < v1.size(); i++) {
LiteralOrCatchallKey k1 = v1.get(i);
Expand Down Expand Up @@ -399,7 +396,7 @@ public ResolvedSelector(
}
}

private static void formattingError(String message) {
private static void fatalFormattingError(String message) {
throw new IllegalArgumentException(message);
}

Expand Down Expand Up @@ -512,24 +509,23 @@ private FormattedPlaceholder formatExpression(
// No output on markup, for now (we only format to string)
return new FormattedPlaceholder(expression, new PlainStringFormattedValue(""));
} else {
UnsupportedExpression ue = (UnsupportedExpression) expression;
char sigil = ue.annotation.source.charAt(0);
return new FormattedPlaceholder(
expression, new PlainStringFormattedValue("{" + sigil + "}"));
if (expression == null) {
fatalFormattingError("unexpected null expression");
} else {
fatalFormattingError("unknown expression type "
+ expression.getClass().getName());
}
}

if (annotation instanceof FunctionAnnotation) {
FunctionAnnotation fa = (FunctionAnnotation) annotation;
if (functionName != null && !functionName.equals(fa.name)) {
formattingError(
fatalFormattingError(
"invalid function overrides, '" + functionName + "' <> '" + fa.name + "'");
}
functionName = fa.name;
Map<String, Object> newOptions = convertOptions(fa.options, variables, arguments);
options.putAll(newOptions);
} else if (annotation instanceof UnsupportedAnnotation) {
// We don't know how to format unsupported annotations
return new FormattedPlaceholder(expression, new PlainStringFormattedValue(fallbackString));
}

FormatterFactory funcFactory = getFormattingFunctionFactoryByName(toFormat, functionName);
Expand Down
94 changes: 11 additions & 83 deletions icu4j/main/core/src/main/java/com/ibm/icu/message2/MFParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,13 @@ private String getText() {

// abnf: placeholder = expression / markup
// abnf: expression = literal-expression
// abnf: / variable-expression
// abnf: / annotation-expression
// abnf: / variable-expression
// abnf: / annotation-expression
// abnf: literal-expression = "{" [s] literal [s annotation] *(s attribute) [s] "}"
// abnf: variable-expression = "{" [s] variable [s annotation] *(s attribute) [s] "}"
// abnf: annotation-expression = "{" [s] annotation *(s attribute) [s] "}"
// abnf: markup = "{" [s] "#" identifier *(s option) *(s attribute) [s] ["/"] "}" ; open and standalone
// abnf: / "{" [s] "/" identifier *(s option) *(s attribute) [s] "}" ; close
// abnf: / "{" [s] "/" identifier *(s option) *(s attribute) [s] "}" ; close
private MFDataModel.Expression getPlaceholder() throws MFParseException {
int cp = input.peekChar();
if (cp != '{') {
Expand All @@ -168,9 +168,7 @@ private MFDataModel.Expression getPlaceholder() throws MFParseException {
result = getMarkup();
} else if (cp == '$') {
result = getVariableExpression();
} else if (StringUtils.isFunctionSigil(cp)
|| StringUtils.isPrivateAnnotationSigil(cp)
|| StringUtils.isReservedAnnotationSigil(cp)) {
} else if (StringUtils.isFunctionSigil(cp)) {
result = getAnnotationExpression();
} else {
result = getLiteralExpression();
Expand Down Expand Up @@ -214,16 +212,8 @@ private MFDataModel.Annotation getAnnotation(boolean whitespaceRequired) throws
checkCondition(identifier != null, "Annotation / function name missing");
Map<String, MFDataModel.Option> options = getOptions();
return new MFDataModel.FunctionAnnotation(identifier, options);
default: // reserved && private
if (StringUtils.isReservedAnnotationSigil(cp)
|| StringUtils.isPrivateAnnotationSigil(cp)) {
cp = input.readCodePoint();
// The sigil is part of the body.
// Safe to cast to char, the code point is in BMP
identifier = (char) cp + getIdentifier();
String body = getReservedBody();
return new MFDataModel.UnsupportedAnnotation(identifier + body);
}
default:
// OK to continue and return null, it is an error.
}
input.gotoPosition(position);
return null;
Expand All @@ -246,7 +236,7 @@ private MFDataModel.Annotation getMarkupAnnotation() throws MFParseException {
Map<String, MFDataModel.Option> options = getOptions();
return new MFDataModel.FunctionAnnotation(identifier, options);
default:
// reserved, private, function, something else,
// function or something else,
return null;
}
}
Expand Down Expand Up @@ -290,17 +280,14 @@ private MFDataModel.Expression getAnnotationExpression() throws MFParseException
if (annotation instanceof MFDataModel.FunctionAnnotation) {
return new MFDataModel.FunctionExpression(
(MFDataModel.FunctionAnnotation) annotation, attributes);
} else if (annotation instanceof MFDataModel.UnsupportedAnnotation) {
return new MFDataModel.UnsupportedExpression(
(MFDataModel.UnsupportedAnnotation) annotation, attributes);
} else {
error("Unexpected annotation : " + annotation);
}
return null;
}

// abnf: markup = "{" [s] "#" identifier *(s option) *(s attribute) [s] ["/"] "}" ; open and standalone
// abnf: / "{" [s] "/" identifier *(s option) *(s attribute) [s] "}" ; close
// abnf: / "{" [s] "/" identifier *(s option) *(s attribute) [s] "}" ; close
private MFDataModel.Markup getMarkup() throws MFParseException {
int cp = input.peekChar(); // consume the '{'
checkCondition(cp == '#' || cp == '/', "Should not happen. Expecting a markup.");
Expand Down Expand Up @@ -370,39 +357,6 @@ private MFDataModel.Attribute getAttribute() throws MFParseException {
return null;
}

// abnf: reserved-body = *([s] 1*(reserved-char / reserved-escape / quoted))
// abnf: reserved-escape = backslash ( backslash / "{" / "|" / "}" )
private String getReservedBody() throws MFParseException {
int spaceCount = skipWhitespaces();
StringBuilder result = new StringBuilder();
while (true) {
int cp = input.readCodePoint();
if (StringUtils.isReservedChar(cp)) {
result.appendCodePoint(cp);
} else if (cp == '\\') {
cp = input.readCodePoint();
checkCondition(
cp == '{' || cp == '|' || cp == '}',
"Invalid escape sequence. Only \\{, \\| and \\} are valid here.");
result.append(cp);
} else if (cp == '|') {
input.backup(1);
MFDataModel.Literal quoted = getQuotedLiteral();
result.append(quoted.value);
} else if (cp == EOF) {
return result.toString();
} else {
if (result.length() == 0) {
input.backup(spaceCount + 1);
return "";
} else {
input.backup(1);
return result.toString();
}
}
}
}

// abnf: identifier = [namespace ":"] name
// abnf: namespace = name
// abnf: name = name-start *name-char
Expand Down Expand Up @@ -650,7 +604,7 @@ private MFDataModel.SelectMessage getMatch(List<MFDataModel.Declaration> declara
// abnf: key = literal / "*"
private MFDataModel.Variant getVariant() throws MFParseException {
List<MFDataModel.LiteralOrCatchallKey> keys = new ArrayList<>();
// abnf variant = key *(s key) [s] quoted-pattern
// abnf: variant = key *(s key) [s] quoted-pattern
while (true) {
// Space is required between keys
MFDataModel.LiteralOrCatchallKey key = getKey(!keys.isEmpty());
Expand Down Expand Up @@ -705,8 +659,6 @@ private static class MatchDeclaration implements MFDataModel.Declaration {

// abnf: input-declaration = input [s] variable-expression
// abnf: local-declaration = local s variable [s] "=" [s] expression
// abnf: reserved-statement = reserved-keyword [s reserved-body] 1*([s] expression)
// abnf: reserved-keyword = "." name
private MFDataModel.Declaration getDeclaration() throws MFParseException {
int position = input.getPosition();
skipOptionalWhitespaces();
Expand Down Expand Up @@ -745,32 +697,8 @@ private MFDataModel.Declaration getDeclaration() throws MFParseException {
break;
case "match":
return new MatchDeclaration();
default: // abnf: reserved-statement = reserved-keyword [s reserved-body] 1*([s] expression)
skipOptionalWhitespaces();
String body = getReservedBody();
List<MFDataModel.Expression> expressions = new ArrayList<>();
while (true) {
skipOptionalWhitespaces();
// Look ahead to detect the end of the unsupported statement
// (next token either begins a placeholder or begins a complex body)
cp = input.readCodePoint();
int cp1 = input.readCodePoint();
if (cp == '{' && cp1 == '{') {
// End of unsupported statement
input.backup(2);
break;
} else {
input.backup(2);
}
expression = getPlaceholder();
// This also covers != null
if (expression instanceof MFDataModel.VariableExpression) {
expressions.add(expression);
} else {
break;
}
}
return new MFDataModel.UnsupportedStatement(declName, body, expressions);
default:
// OK to continue and return null, it is an error.
}
return null;
}
Expand Down
Loading

0 comments on commit 09c5aa1

Please sign in to comment.