mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-06 05:55:35 +00:00
ICU-22902 Remove support for Unsupported, Private & Reserved constructs
Matching PR #883 in the message-format-wg repo. Also move spec tests for unsupported statements and expressions into new files to serve as syntax error tests.
This commit is contained in:
parent
5f9f8b2053
commit
2f348f4c7a
20 changed files with 109 additions and 1577 deletions
icu4c/source
common
i18n
messageformat2.cppmessageformat2_checker.cppmessageformat2_data_model.cppmessageformat2_errors.cppmessageformat2_errors.hmessageformat2_parser.cppmessageformat2_parser.hmessageformat2_serializer.cppmessageformat2_serializer.h
unicode
test/intltest
icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2
testdata/message2
|
@ -597,15 +597,13 @@ typedef enum UErrorCode {
|
|||
U_MF_MISSING_SELECTOR_ANNOTATION_ERROR, /**< A selector expression evaluates to an unannotated operand. @internal ICU 75 technology preview @deprecated This API is for technology preview only. */
|
||||
U_MF_DUPLICATE_DECLARATION_ERROR, /**< The same variable is declared in more than one .local or .input declaration. @internal ICU 75 technology preview @deprecated This API is for technology preview only. */
|
||||
U_MF_OPERAND_MISMATCH_ERROR, /**< An operand provided to a function does not have the required form for that function @internal ICU 75 technology preview @deprecated This API is for technology preview only. */
|
||||
U_MF_UNSUPPORTED_STATEMENT_ERROR, /**< A message includes a reserved statement. @internal ICU 75 technology preview @deprecated This API is for technology preview only. */
|
||||
U_MF_UNSUPPORTED_EXPRESSION_ERROR, /**< A message includes syntax reserved for future standardization or private implementation use. @internal ICU 75 technology preview @deprecated This API is for technology preview only. */
|
||||
U_MF_DUPLICATE_VARIANT_ERROR, /**< A message includes a variant with the same key list as another variant. @internal ICU 76 technology preview @deprecated This API is for technology preview only. */
|
||||
#ifndef U_HIDE_DEPRECATED_API
|
||||
/**
|
||||
* One more than the highest normal formatting API error code.
|
||||
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
|
||||
*/
|
||||
U_FMT_PARSE_ERROR_LIMIT = 0x10122,
|
||||
U_FMT_PARSE_ERROR_LIMIT = 0x10120,
|
||||
#endif // U_HIDE_DEPRECATED_API
|
||||
|
||||
/*
|
||||
|
|
|
@ -140,8 +140,6 @@ _uFmtErrorName[U_FMT_PARSE_ERROR_LIMIT - U_FMT_PARSE_ERROR_START] = {
|
|||
"U_MF_MISSING_SELECTOR_ANNOTATION_ERROR",
|
||||
"U_MF_DUPLICATE_DECLARATION_ERROR",
|
||||
"U_MF_OPERAND_MISMATCH_ERROR",
|
||||
"U_MF_UNSUPPORTED_STATEMENT_ERROR",
|
||||
"U_MF_UNSUPPORTED_EXPRESSION_ERROR",
|
||||
"U_MF_DUPLICATE_VARIANT_ERROR"
|
||||
};
|
||||
|
||||
|
|
|
@ -241,24 +241,6 @@ FunctionOptions MessageFormatter::resolveOptions(const Environment& env, const O
|
|||
return FormattedPlaceholder(fallback);
|
||||
}
|
||||
|
||||
// Per https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#fallback-resolution
|
||||
static UnicodeString reservedFallback (const Expression& e) {
|
||||
UErrorCode localErrorCode = U_ZERO_ERROR;
|
||||
const Operator* rator = e.getOperator(localErrorCode);
|
||||
U_ASSERT(U_SUCCESS(localErrorCode));
|
||||
const Reserved& r = rator->asReserved();
|
||||
|
||||
// An empty Reserved isn't representable in the syntax
|
||||
U_ASSERT(r.numParts() > 0);
|
||||
|
||||
const UnicodeString& contents = r.getPart(0).unquoted();
|
||||
// Parts should never be empty
|
||||
U_ASSERT(contents.length() > 0);
|
||||
|
||||
// Return first character of string
|
||||
return UnicodeString(contents, 0, 1);
|
||||
}
|
||||
|
||||
// Formats an expression using `globalEnv` for the values of variables
|
||||
[[nodiscard]] FormattedPlaceholder MessageFormatter::formatExpression(const Environment& globalEnv,
|
||||
const Expression& expr,
|
||||
|
@ -268,12 +250,6 @@ static UnicodeString reservedFallback (const Expression& e) {
|
|||
return {};
|
||||
}
|
||||
|
||||
// Formatting error
|
||||
if (expr.isReserved()) {
|
||||
context.getErrors().setReservedError(status);
|
||||
return FormattedPlaceholder(reservedFallback(expr));
|
||||
}
|
||||
|
||||
const Operand& rand = expr.getOperand();
|
||||
// Format the operand (formatOperand handles the case of a null operand)
|
||||
FormattedPlaceholder randVal = formatOperand(globalEnv, rand, context, status);
|
||||
|
@ -675,12 +651,6 @@ ResolvedSelector MessageFormatter::resolveVariables(const Environment& env,
|
|||
return {};
|
||||
}
|
||||
|
||||
// A `reserved` is an error
|
||||
if (expr.isReserved()) {
|
||||
context.getErrors().setReservedError(status);
|
||||
return ResolvedSelector(FormattedPlaceholder(reservedFallback(expr)));
|
||||
}
|
||||
|
||||
// Function call -- resolve the operand and options
|
||||
if (expr.isFunctionCall()) {
|
||||
const Operator* rator = expr.getOperator(status);
|
||||
|
|
|
@ -136,9 +136,7 @@ void Checker::addFreeVars(TypeEnvironment& t, const OptionMap& opts, UErrorCode&
|
|||
void Checker::addFreeVars(TypeEnvironment& t, const Operator& rator, UErrorCode& status) {
|
||||
CHECK_ERROR(status);
|
||||
|
||||
if (!rator.isReserved()) {
|
||||
addFreeVars(t, rator.getOptionsInternal(), status);
|
||||
}
|
||||
addFreeVars(t, rator.getOptionsInternal(), status);
|
||||
}
|
||||
|
||||
void Checker::addFreeVars(TypeEnvironment& t, const Expression& rhs, UErrorCode& status) {
|
||||
|
@ -213,12 +211,10 @@ void Checker::requireAnnotated(const TypeEnvironment& t, const Expression& selec
|
|||
if (selectorExpr.isFunctionCall()) {
|
||||
return; // No error
|
||||
}
|
||||
if (!selectorExpr.isReserved()) {
|
||||
const Operand& rand = selectorExpr.getOperand();
|
||||
if (rand.isVariable()) {
|
||||
if (t.get(rand.asVariable()) == TypeEnvironment::Type::Annotated) {
|
||||
return; // No error
|
||||
}
|
||||
const Operand& rand = selectorExpr.getOperand();
|
||||
if (rand.isVariable()) {
|
||||
if (t.get(rand.asVariable()) == TypeEnvironment::Type::Annotated) {
|
||||
return; // No error
|
||||
}
|
||||
}
|
||||
// If this code is reached, an error was detected
|
||||
|
@ -240,9 +236,6 @@ TypeEnvironment::Type typeOf(TypeEnvironment& t, const Expression& expr) {
|
|||
if (expr.isFunctionCall()) {
|
||||
return TypeEnvironment::Type::Annotated;
|
||||
}
|
||||
if (expr.isReserved()) {
|
||||
return TypeEnvironment::Type::Unannotated;
|
||||
}
|
||||
const Operand& rand = expr.getOperand();
|
||||
U_ASSERT(!rand.isNull());
|
||||
if (rand.isLiteral()) {
|
||||
|
@ -296,11 +289,6 @@ void Checker::checkDeclarations(TypeEnvironment& t, UErrorCode& status) {
|
|||
// Next, extend the type environment with a binding from lhs to its type
|
||||
t.extend(lhs, typeOf(t, rhs), status);
|
||||
}
|
||||
|
||||
// Check for unsupported statements
|
||||
if (dataModel.unsupportedStatementsLen > 0) {
|
||||
errors.addError(StaticErrorType::UnsupportedStatementError, status);
|
||||
}
|
||||
}
|
||||
|
||||
void Checker::check(UErrorCode& status) {
|
||||
|
|
|
@ -199,77 +199,6 @@ const Literal& Key::asLiteral() const {
|
|||
|
||||
Key::~Key() {}
|
||||
|
||||
// ------------ Reserved
|
||||
|
||||
// Copy constructor
|
||||
Reserved::Reserved(const Reserved& other) : len(other.len) {
|
||||
U_ASSERT(!other.bogus);
|
||||
|
||||
UErrorCode localErrorCode = U_ZERO_ERROR;
|
||||
if (len == 0) {
|
||||
parts.adoptInstead(nullptr);
|
||||
} else {
|
||||
parts.adoptInstead(copyArray(other.parts.getAlias(), len, localErrorCode));
|
||||
}
|
||||
if (U_FAILURE(localErrorCode)) {
|
||||
bogus = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reserved& Reserved::operator=(Reserved other) noexcept {
|
||||
swap(*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Reserved::Reserved(const UVector& ps, UErrorCode& status) noexcept : len(ps.size()) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
parts = LocalArray<Literal>(copyVectorToArray<Literal>(ps, status));
|
||||
}
|
||||
|
||||
int32_t Reserved::numParts() const {
|
||||
U_ASSERT(!bogus);
|
||||
return len;
|
||||
}
|
||||
|
||||
const Literal& Reserved::getPart(int32_t i) const {
|
||||
U_ASSERT(!bogus);
|
||||
U_ASSERT(i < numParts());
|
||||
return parts[i];
|
||||
}
|
||||
|
||||
Reserved::Builder::Builder(UErrorCode& status) {
|
||||
parts = createUVector(status);
|
||||
}
|
||||
|
||||
Reserved Reserved::Builder::build(UErrorCode& status) const noexcept {
|
||||
if (U_FAILURE(status)) {
|
||||
return {};
|
||||
}
|
||||
U_ASSERT(parts != nullptr);
|
||||
return Reserved(*parts, status);
|
||||
}
|
||||
|
||||
Reserved::Builder& Reserved::Builder::add(Literal&& part, UErrorCode& status) noexcept {
|
||||
U_ASSERT(parts != nullptr);
|
||||
if (U_SUCCESS(status)) {
|
||||
Literal* l = create<Literal>(std::move(part), status);
|
||||
parts->adoptElement(l, status);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Reserved::Builder::~Builder() {
|
||||
if (parts != nullptr) {
|
||||
delete parts;
|
||||
}
|
||||
}
|
||||
|
||||
Reserved::~Reserved() {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
//------------------------ Operator
|
||||
|
||||
OptionMap::OptionMap(const UVector& opts, UErrorCode& status) : len(opts.size()) {
|
||||
|
@ -379,14 +308,8 @@ OptionMap::Builder::~Builder() {
|
|||
}
|
||||
}
|
||||
|
||||
const Reserved& Operator::asReserved() const {
|
||||
U_ASSERT(isReserved());
|
||||
return *(std::get_if<Reserved>(&contents));
|
||||
}
|
||||
|
||||
const OptionMap& Operator::getOptionsInternal() const {
|
||||
U_ASSERT(!isReserved());
|
||||
return std::get_if<Callable>(&contents)->getOptions();
|
||||
return options;
|
||||
}
|
||||
|
||||
Option::Option(const Option& other): name(other.name), rand(other.rand) {}
|
||||
|
@ -400,62 +323,28 @@ Option::~Option() {}
|
|||
|
||||
Operator::Builder::Builder(UErrorCode& status) : options(OptionMap::Builder(status)) {}
|
||||
|
||||
Operator::Builder& Operator::Builder::setReserved(Reserved&& reserved) {
|
||||
isReservedSequence = true;
|
||||
hasFunctionName = false;
|
||||
hasOptions = false;
|
||||
asReserved = std::move(reserved);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Operator::Builder& Operator::Builder::setFunctionName(FunctionName&& func) {
|
||||
isReservedSequence = false;
|
||||
hasFunctionName = true;
|
||||
functionName = std::move(func);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const FunctionName& Operator::getFunctionName() const {
|
||||
U_ASSERT(!isReserved());
|
||||
return std::get_if<Callable>(&contents)->getName();
|
||||
return name;
|
||||
}
|
||||
|
||||
Operator::Builder& Operator::Builder::addOption(const UnicodeString &key, Operand&& value, UErrorCode& errorCode) noexcept {
|
||||
THIS_ON_ERROR(errorCode);
|
||||
|
||||
isReservedSequence = false;
|
||||
hasOptions = true;
|
||||
options.add(Option(key, std::move(value)), errorCode);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Operator Operator::Builder::build(UErrorCode& errorCode) {
|
||||
Operator result;
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return result;
|
||||
}
|
||||
// Must be either reserved or function, not both; enforced by methods
|
||||
if (isReservedSequence) {
|
||||
// Methods enforce that the function name and options are unset
|
||||
// if `setReserved()` is called, so if they were valid, that
|
||||
// would indicate a bug.
|
||||
U_ASSERT(!hasOptions && !hasFunctionName);
|
||||
result = Operator(asReserved);
|
||||
} else {
|
||||
if (!hasFunctionName) {
|
||||
// Neither function name nor reserved was set
|
||||
// There is no default, so this case could occur if the
|
||||
// caller creates a builder and doesn't make any calls
|
||||
// before calling build().
|
||||
errorCode = U_INVALID_STATE_ERROR;
|
||||
return result;
|
||||
}
|
||||
result = Operator(functionName, options.build(errorCode));
|
||||
}
|
||||
return result;
|
||||
return Operator(functionName, options.build(errorCode));
|
||||
}
|
||||
|
||||
Operator::Operator(const Operator& other) noexcept : contents(other.contents) {}
|
||||
Operator::Operator(const Operator& other) noexcept
|
||||
: name(other.name), options(other.options) {}
|
||||
|
||||
Operator& Operator::operator=(Operator other) noexcept {
|
||||
swap(*this, other);
|
||||
|
@ -463,23 +352,13 @@ Operator& Operator::operator=(Operator other) noexcept {
|
|||
}
|
||||
|
||||
// Function call
|
||||
Operator::Operator(const FunctionName& f, const UVector& optsVector, UErrorCode& status) : contents(Callable(f, OptionMap(optsVector, status))) {}
|
||||
|
||||
Operator::Operator(const FunctionName& f, const OptionMap& opts) : contents(Callable(f, opts)) {}
|
||||
Operator::Operator(const FunctionName& f, const OptionMap& opts) : name(f), options(opts) {}
|
||||
|
||||
Operator::Builder::~Builder() {}
|
||||
|
||||
Operator::~Operator() {}
|
||||
|
||||
Callable& Callable::operator=(Callable other) noexcept {
|
||||
swap(*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Callable::Callable(const Callable& other) : name(other.name), options(other.options) {}
|
||||
|
||||
Callable::~Callable() {}
|
||||
|
||||
// ------------ Markup
|
||||
|
||||
Markup::Builder::Builder(UErrorCode& status)
|
||||
|
@ -538,19 +417,14 @@ UBool Expression::isStandaloneAnnotation() const {
|
|||
|
||||
// Returns true for function calls with operands as well as
|
||||
// standalone annotations.
|
||||
// Reserved sequences are not function calls
|
||||
UBool Expression::isFunctionCall() const {
|
||||
return (rator.has_value() && !rator->isReserved());
|
||||
}
|
||||
|
||||
UBool Expression::isReserved() const {
|
||||
return (rator.has_value() && rator->isReserved());
|
||||
return rator.has_value();
|
||||
}
|
||||
|
||||
const Operator* Expression::getOperator(UErrorCode& status) const {
|
||||
NULL_ON_ERROR(status);
|
||||
|
||||
if (!(isReserved() || isFunctionCall())) {
|
||||
if (!isFunctionCall()) {
|
||||
status = U_INVALID_STATE_ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -617,92 +491,6 @@ Expression::Builder::~Builder() {}
|
|||
|
||||
Expression::~Expression() {}
|
||||
|
||||
// ----------- UnsupportedStatement
|
||||
|
||||
UnsupportedStatement::Builder::Builder(UErrorCode& status) {
|
||||
expressions = createUVector(status);
|
||||
}
|
||||
|
||||
UnsupportedStatement::Builder& UnsupportedStatement::Builder::setKeyword(const UnicodeString& k) {
|
||||
keyword = k;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UnsupportedStatement::Builder& UnsupportedStatement::Builder::setBody(Reserved&& r) {
|
||||
body.emplace(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
UnsupportedStatement::Builder& UnsupportedStatement::Builder::addExpression(Expression&& e, UErrorCode& status) {
|
||||
U_ASSERT(expressions != nullptr);
|
||||
if (U_SUCCESS(status)) {
|
||||
Expression* expr = create<Expression>(std::move(e), status);
|
||||
expressions->adoptElement(expr, status);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
UnsupportedStatement UnsupportedStatement::Builder::build(UErrorCode& status) const {
|
||||
if (U_SUCCESS(status)) {
|
||||
U_ASSERT(expressions != nullptr);
|
||||
if (keyword.length() <= 0) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
} else if (expressions->size() < 1) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
} else {
|
||||
return UnsupportedStatement(keyword, body, *expressions, status);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
const Reserved* UnsupportedStatement::getBody(UErrorCode& errorCode) const {
|
||||
if (U_SUCCESS(errorCode)) {
|
||||
if (body.has_value()) {
|
||||
return &(*body);
|
||||
}
|
||||
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UnsupportedStatement::UnsupportedStatement(const UnicodeString& k,
|
||||
const std::optional<Reserved>& r,
|
||||
const UVector& es,
|
||||
UErrorCode& status)
|
||||
: keyword(k), body(r), expressionsLen(es.size()) {
|
||||
CHECK_ERROR(status);
|
||||
|
||||
U_ASSERT(expressionsLen >= 1);
|
||||
Expression* result = copyVectorToArray<Expression>(es, status);
|
||||
CHECK_ERROR(status);
|
||||
expressions.adoptInstead(result);
|
||||
}
|
||||
|
||||
UnsupportedStatement::UnsupportedStatement(const UnsupportedStatement& other) {
|
||||
keyword = other.keyword;
|
||||
body = other.body;
|
||||
expressionsLen = other.expressionsLen;
|
||||
U_ASSERT(expressionsLen > 0);
|
||||
UErrorCode localErrorCode = U_ZERO_ERROR;
|
||||
expressions.adoptInstead(copyArray(other.expressions.getAlias(), expressionsLen, localErrorCode));
|
||||
if (U_FAILURE(localErrorCode)) {
|
||||
expressionsLen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UnsupportedStatement& UnsupportedStatement::operator=(UnsupportedStatement other) noexcept {
|
||||
swap(*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
UnsupportedStatement::Builder::~Builder() {
|
||||
if (expressions != nullptr) {
|
||||
delete expressions;
|
||||
}
|
||||
}
|
||||
|
||||
UnsupportedStatement::~UnsupportedStatement() {}
|
||||
// ----------- PatternPart
|
||||
|
||||
// PatternPart needs a copy constructor in order to make Pattern deeply copyable
|
||||
|
@ -844,7 +632,7 @@ const Expression& Binding::getValue() const {
|
|||
if (hasOperator) {
|
||||
rator = b.getValue().getOperator(errorCode);
|
||||
U_ASSERT(U_SUCCESS(errorCode));
|
||||
b.annotation = &rator->contents;
|
||||
b.annotation = rator;
|
||||
} else {
|
||||
b.annotation = nullptr;
|
||||
}
|
||||
|
@ -856,18 +644,17 @@ const Expression& Binding::getValue() const {
|
|||
|
||||
const OptionMap& Binding::getOptionsInternal() const {
|
||||
U_ASSERT(annotation != nullptr);
|
||||
U_ASSERT(std::holds_alternative<Callable>(*annotation));
|
||||
return std::get_if<Callable>(annotation)->getOptions();
|
||||
return annotation->getOptionsInternal();
|
||||
}
|
||||
|
||||
void Binding::updateAnnotation() {
|
||||
UErrorCode localErrorCode = U_ZERO_ERROR;
|
||||
const Operator* rator = expr.getOperator(localErrorCode);
|
||||
if (U_FAILURE(localErrorCode) || rator->isReserved()) {
|
||||
if (U_FAILURE(localErrorCode)) {
|
||||
return;
|
||||
}
|
||||
U_ASSERT(U_SUCCESS(localErrorCode) && !rator->isReserved());
|
||||
annotation = &rator->contents;
|
||||
U_ASSERT(U_SUCCESS(localErrorCode));
|
||||
annotation = rator;
|
||||
}
|
||||
|
||||
Binding::Binding(const Binding& other) : var(other.var), expr(other.expr), local(other.local) {
|
||||
|
@ -949,17 +736,8 @@ const Variant* MFDataModel::getVariantsInternal() const {
|
|||
return std::get_if<Matcher>(&body)->variants.getAlias();
|
||||
}
|
||||
|
||||
// Returns nullptr if no unsupported statements
|
||||
const UnsupportedStatement* MFDataModel::getUnsupportedStatementsInternal() const {
|
||||
U_ASSERT(!bogus);
|
||||
U_ASSERT(unsupportedStatementsLen == 0 || unsupportedStatements != nullptr);
|
||||
return unsupportedStatements.getAlias();
|
||||
}
|
||||
|
||||
|
||||
MFDataModel::Builder::Builder(UErrorCode& status) {
|
||||
bindings = createUVector(status);
|
||||
unsupportedStatements = createUVector(status);
|
||||
}
|
||||
|
||||
// Invalidate pattern and create selectors/variants if necessary
|
||||
|
@ -1008,14 +786,6 @@ MFDataModel::Builder& MFDataModel::Builder::addBinding(Binding&& b, UErrorCode&
|
|||
return *this;
|
||||
}
|
||||
|
||||
MFDataModel::Builder& MFDataModel::Builder::addUnsupportedStatement(UnsupportedStatement&& s, UErrorCode& status) {
|
||||
if (U_SUCCESS(status)) {
|
||||
U_ASSERT(unsupportedStatements != nullptr);
|
||||
unsupportedStatements->adoptElement(create<UnsupportedStatement>(std::move(s), status), status);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
selector must be non-null
|
||||
*/
|
||||
|
@ -1077,10 +847,6 @@ MFDataModel::MFDataModel(const MFDataModel& other) : body(Pattern()) {
|
|||
if (bindingsLen > 0) {
|
||||
bindings.adoptInstead(copyArray(other.bindings.getAlias(), bindingsLen, localErrorCode));
|
||||
}
|
||||
unsupportedStatementsLen = other.unsupportedStatementsLen;
|
||||
if (unsupportedStatementsLen > 0) {
|
||||
unsupportedStatements.adoptInstead(copyArray(other.unsupportedStatements.getAlias(), unsupportedStatementsLen, localErrorCode));
|
||||
}
|
||||
if (U_FAILURE(localErrorCode)) {
|
||||
bogus = true;
|
||||
}
|
||||
|
@ -1110,11 +876,6 @@ MFDataModel::MFDataModel(const MFDataModel::Builder& builder, UErrorCode& errorC
|
|||
if (bindingsLen > 0) {
|
||||
bindings.adoptInstead(copyVectorToArray<Binding>(*builder.bindings, errorCode));
|
||||
}
|
||||
unsupportedStatementsLen = builder.unsupportedStatements->size();
|
||||
if (unsupportedStatementsLen > 0) {
|
||||
unsupportedStatements.adoptInstead(copyVectorToArray<UnsupportedStatement>(*builder.unsupportedStatements,
|
||||
errorCode));
|
||||
}
|
||||
if (U_FAILURE(errorCode)) {
|
||||
bogus = true;
|
||||
}
|
||||
|
@ -1149,9 +910,6 @@ MFDataModel::Builder::~Builder() {
|
|||
if (bindings != nullptr) {
|
||||
delete bindings;
|
||||
}
|
||||
if (unsupportedStatements != nullptr) {
|
||||
delete unsupportedStatements;
|
||||
}
|
||||
}
|
||||
} // namespace message2
|
||||
|
||||
|
|
|
@ -19,10 +19,6 @@ namespace message2 {
|
|||
// Errors
|
||||
// -----------
|
||||
|
||||
void DynamicErrors::setReservedError(UErrorCode& status) {
|
||||
addError(DynamicError(DynamicErrorType::ReservedError), status);
|
||||
}
|
||||
|
||||
void DynamicErrors::setFormattingError(const FunctionName& formatterName, UErrorCode& status) {
|
||||
addError(DynamicError(DynamicErrorType::FormattingError, formatterName), status);
|
||||
}
|
||||
|
@ -143,10 +139,6 @@ namespace message2 {
|
|||
status = U_MF_OPERAND_MISMATCH_ERROR;
|
||||
break;
|
||||
}
|
||||
case DynamicErrorType::ReservedError: {
|
||||
status = U_MF_UNSUPPORTED_EXPRESSION_ERROR;
|
||||
break;
|
||||
}
|
||||
case DynamicErrorType::SelectorError: {
|
||||
status = U_MF_SELECTOR_ERROR;
|
||||
break;
|
||||
|
@ -196,10 +188,6 @@ namespace message2 {
|
|||
dataModelError = true;
|
||||
break;
|
||||
}
|
||||
case StaticErrorType::UnsupportedStatementError: {
|
||||
dataModelError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
syntaxAndDataModelErrors->adoptElement(errorP, status);
|
||||
}
|
||||
|
@ -228,10 +216,6 @@ namespace message2 {
|
|||
resolutionAndFormattingErrors->adoptElement(errorP, status);
|
||||
break;
|
||||
}
|
||||
case DynamicErrorType::ReservedError: {
|
||||
resolutionAndFormattingErrors->adoptElement(errorP, status);
|
||||
break;
|
||||
}
|
||||
case DynamicErrorType::SelectorError: {
|
||||
selectorError = true;
|
||||
resolutionAndFormattingErrors->adoptElement(errorP, status);
|
||||
|
@ -279,9 +263,6 @@ namespace message2 {
|
|||
status = U_MF_SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
case StaticErrorType::UnsupportedStatementError: {
|
||||
status = U_MF_UNSUPPORTED_STATEMENT_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ namespace message2 {
|
|||
MissingSelectorAnnotation,
|
||||
NonexhaustivePattern,
|
||||
SyntaxError,
|
||||
UnsupportedStatementError,
|
||||
VariantKeyMismatchError
|
||||
};
|
||||
|
||||
|
@ -66,7 +65,6 @@ namespace message2 {
|
|||
UnresolvedVariable,
|
||||
FormattingError,
|
||||
OperandMismatchError,
|
||||
ReservedError,
|
||||
SelectorError,
|
||||
UnknownFunction,
|
||||
};
|
||||
|
@ -123,7 +121,6 @@ namespace message2 {
|
|||
|
||||
int32_t count() const;
|
||||
void setSelectorError(const FunctionName&, UErrorCode&);
|
||||
void setReservedError(UErrorCode&);
|
||||
void setUnresolvedVariable(const VariableName&, UErrorCode&);
|
||||
void setUnknownFunction(const FunctionName&, UErrorCode&);
|
||||
void setFormattingError(const FunctionName&, UErrorCode&);
|
||||
|
|
|
@ -104,8 +104,6 @@ static bool inRange(UChar32 c, UChar32 first, UChar32 last) {
|
|||
|
||||
`isContentChar()` : `content-char`
|
||||
`isTextChar()` : `text-char`
|
||||
`isReservedStart()` : `reserved-start`
|
||||
`isReservedChar()` : `reserved-char`
|
||||
`isAlpha()` : `ALPHA`
|
||||
`isDigit()` : `DIGIT`
|
||||
`isNameStart()` : `name-start`
|
||||
|
@ -149,35 +147,6 @@ static bool isTextChar(UChar32 c) {
|
|||
|| c == PIPE;
|
||||
}
|
||||
|
||||
// Note: this doesn't distinguish between private-use
|
||||
// and reserved, since the data model doesn't
|
||||
static bool isReservedStart(UChar32 c) {
|
||||
switch (c) {
|
||||
case BANG:
|
||||
case PERCENT:
|
||||
case ASTERISK:
|
||||
case PLUS:
|
||||
case LESS_THAN:
|
||||
case GREATER_THAN:
|
||||
case QUESTION:
|
||||
case TILDE:
|
||||
// Private-use
|
||||
case CARET:
|
||||
case AMPERSAND:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isReservedChar(UChar32 c) {
|
||||
return isContentChar(c) || c == PERIOD;
|
||||
}
|
||||
|
||||
static bool isReservedBodyStart(UChar32 c) {
|
||||
return isReservedChar(c) || c == BACKSLASH || c == PIPE;
|
||||
}
|
||||
|
||||
static bool isAlpha(UChar32 c) { return inRange(c, 0x0041, 0x005A) || inRange(c, 0x0061, 0x007A); }
|
||||
|
||||
static bool isDigit(UChar32 c) { return inRange(c, 0x0030, 0x0039); }
|
||||
|
@ -230,24 +199,7 @@ static bool isFunctionStart(UChar32 c) {
|
|||
|
||||
// Returns true iff `c` can begin an `annotation` nonterminal
|
||||
static bool isAnnotationStart(UChar32 c) {
|
||||
return isFunctionStart(c) || isReservedStart(c);
|
||||
}
|
||||
|
||||
// Returns true iff `c` can begin either a `reserved-char` or `reserved-escape`
|
||||
// literal
|
||||
static bool reservedChunkFollows(UChar32 c) {
|
||||
switch(c) {
|
||||
// reserved-escape
|
||||
case BACKSLASH:
|
||||
// literal
|
||||
case PIPE: {
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
// reserved-char
|
||||
return (isReservedChar(c));
|
||||
}
|
||||
}
|
||||
return isFunctionStart(c);
|
||||
}
|
||||
|
||||
// Returns true iff `c` can begin a `literal` nonterminal
|
||||
|
@ -1121,189 +1073,7 @@ Arbitrary lookahead is required to parse attribute lists, similarly to option li
|
|||
}
|
||||
|
||||
/*
|
||||
Consumes a non-empty sequence of reserved-chars, reserved-escapes, and
|
||||
literals (as in 1*(reserved-char / reserved-escape / literal) in the `reserved-body` rule)
|
||||
|
||||
Appends it to `str`
|
||||
*/
|
||||
void Parser::parseReservedChunk(Reserved::Builder& result, UErrorCode& status) {
|
||||
CHECK_ERROR(status);
|
||||
|
||||
bool empty = true;
|
||||
UnicodeString chunk;
|
||||
while(reservedChunkFollows(peek())) {
|
||||
empty = false;
|
||||
// reserved-char
|
||||
if (isReservedChar(peek())) {
|
||||
chunk += peek();
|
||||
normalizedInput += peek();
|
||||
// consume the char
|
||||
next();
|
||||
// Restore precondition
|
||||
CHECK_BOUNDS(status);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chunk.length() > 0) {
|
||||
result.add(Literal(false, chunk), status);
|
||||
chunk.setTo(u"", 0);
|
||||
}
|
||||
|
||||
if (peek() == BACKSLASH) {
|
||||
// reserved-escape
|
||||
result.add(Literal(false, parseEscapeSequence(status)), status);
|
||||
chunk.setTo(u"", 0);
|
||||
} else if (peek() == PIPE || isUnquotedStart(peek())) {
|
||||
result.add(parseLiteral(status), status);
|
||||
} else {
|
||||
// The reserved chunk ends here
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK_ERROR(status); // Avoid looping infinitely
|
||||
}
|
||||
|
||||
// Add the last chunk if necessary
|
||||
if (chunk.length() > 0) {
|
||||
result.add(Literal(false, chunk), status);
|
||||
}
|
||||
|
||||
if (empty) {
|
||||
ERROR(status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Consume a `reserved-start` character followed by a possibly-empty sequence
|
||||
of non-empty sequences of reserved characters, separated by whitespace.
|
||||
Matches the `reserved` nonterminal in the grammar
|
||||
|
||||
*/
|
||||
Reserved Parser::parseReserved(UErrorCode& status) {
|
||||
Reserved::Builder builder(status);
|
||||
|
||||
if (U_FAILURE(status)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
U_ASSERT(inBounds());
|
||||
|
||||
// Require a `reservedStart` character
|
||||
if (!isReservedStart(peek())) {
|
||||
ERROR(status);
|
||||
return Reserved();
|
||||
}
|
||||
|
||||
// Add the start char as a separate text chunk
|
||||
UnicodeString firstCharString(peek());
|
||||
builder.add(Literal(false, firstCharString), status);
|
||||
if (U_FAILURE(status)) {
|
||||
return {};
|
||||
}
|
||||
// Consume reservedStart
|
||||
normalizedInput += peek();
|
||||
next();
|
||||
return parseReservedBody(builder, status);
|
||||
}
|
||||
|
||||
Reserved Parser::parseReservedBody(Reserved::Builder& builder, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/*
|
||||
Arbitrary lookahead is required to parse a `reserved`, for similar reasons
|
||||
to why it's required for parsing function annotations.
|
||||
|
||||
In the grammar:
|
||||
|
||||
annotation = (function *(s option)) / reserved
|
||||
expression = "{" [s] (((literal / variable) [s annotation]) / annotation) [s] "}"
|
||||
reserved = reserved-start reserved-body
|
||||
reserved-body = *( [s] 1*(reserved-char / reserved-escape / literal))
|
||||
|
||||
When reading a whitespace character, it's ambiguous whether it's the optional
|
||||
whitespace in this rule, or the optional whitespace that precedes a '}' in an
|
||||
expression.
|
||||
|
||||
The ambiguity is resolved using the same grammar refactoring as shown in
|
||||
the comment in `parseOptions()`.
|
||||
*/
|
||||
// Consume reserved characters / literals / reserved escapes
|
||||
// until a character that can't be in a `reserved-body` is seen
|
||||
while (true) {
|
||||
/*
|
||||
First, if there is whitespace, it means either a chunk follows it,
|
||||
or this is the trailing whitespace before the '}' that terminates an
|
||||
expression.
|
||||
|
||||
Next, if the next character can start a reserved-char, reserved-escape,
|
||||
or literal, then parse a "chunk" of reserved things.
|
||||
In any other case, we exit successfully, since per the refactored
|
||||
grammar rule:
|
||||
annotation = (function *(s option) [s]) / (reserved [s])
|
||||
it's valid to consume whitespace after a `reserved`.
|
||||
(`parseExpression()` is responsible for checking that the next
|
||||
character is in fact a '}'.)
|
||||
*/
|
||||
if (!inBounds()) {
|
||||
break;
|
||||
}
|
||||
int32_t numWhitespaceChars = 0;
|
||||
int32_t savedIndex = index;
|
||||
if (isWhitespace(peek())) {
|
||||
parseOptionalWhitespace(status);
|
||||
numWhitespaceChars = index - savedIndex;
|
||||
// Restore precondition
|
||||
if (!inBounds()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (reservedChunkFollows(peek())) {
|
||||
parseReservedChunk(builder, status);
|
||||
|
||||
// Avoid looping infinitely
|
||||
if (U_FAILURE(status) || !inBounds()) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (numWhitespaceChars > 0) {
|
||||
if (peek() == LEFT_CURLY_BRACE) {
|
||||
// Resolve even more ambiguity (space preceding another piece of
|
||||
// a `reserved-body`, vs. space preceding an expression in `reserved-statement`
|
||||
// "Backtrack"
|
||||
index -= numWhitespaceChars;
|
||||
break;
|
||||
}
|
||||
if (peek() == RIGHT_CURLY_BRACE) {
|
||||
// Not an error: just means there's no trailing whitespace
|
||||
// after this `reserved`
|
||||
break;
|
||||
}
|
||||
if (peek() == AT) {
|
||||
// Not an error, but we have to "backtrack" due to the ambiguity
|
||||
// between an `s` preceding another reserved chunk
|
||||
// and an `s` preceding an attribute list
|
||||
index -= numWhitespaceChars;
|
||||
break;
|
||||
}
|
||||
// Error: if there's whitespace, it must either be followed
|
||||
// by a non-empty sequence or by '}'
|
||||
ERROR(status);
|
||||
break;
|
||||
}
|
||||
// If there was no whitespace, it's not an error,
|
||||
// just the end of the reserved string
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build(status);
|
||||
}
|
||||
|
||||
/*
|
||||
Consume a function call or reserved string, matching the `annotation`
|
||||
Consume a function call, matching the `annotation`
|
||||
nonterminal in the grammar
|
||||
|
||||
Returns an `Operator` representing this (a reserved is a parse error)
|
||||
|
@ -1323,17 +1093,9 @@ Operator Parser::parseAnnotation(UErrorCode& status) {
|
|||
// Consume the options (which may be empty)
|
||||
parseOptions(addOptions, status);
|
||||
} else {
|
||||
// Must be reserved
|
||||
// A reserved sequence is not a parse error, but might be a formatting error
|
||||
Reserved rator = parseReserved(status);
|
||||
ratorBuilder.setReserved(std::move(rator));
|
||||
ERROR(status);
|
||||
}
|
||||
UErrorCode localStatus = U_ZERO_ERROR;
|
||||
Operator result = ratorBuilder.build(localStatus);
|
||||
// Either `setReserved` or `setFunctionName` was called,
|
||||
// so there shouldn't be an error.
|
||||
U_ASSERT(U_SUCCESS(localStatus));
|
||||
return result;
|
||||
return ratorBuilder.build(status);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1613,95 +1375,6 @@ void Parser::parseInputDeclaration(UErrorCode& status) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Parses a `reserved-statement` per the grammar
|
||||
*/
|
||||
void Parser::parseUnsupportedStatement(UErrorCode& status) {
|
||||
U_ASSERT(inBounds() && peek() == PERIOD);
|
||||
|
||||
UnsupportedStatement::Builder builder(status);
|
||||
CHECK_ERROR(status);
|
||||
|
||||
// Parse the keyword
|
||||
UnicodeString keyword(PERIOD);
|
||||
normalizedInput += UnicodeString(PERIOD);
|
||||
next();
|
||||
keyword += parseName(status);
|
||||
builder.setKeyword(keyword);
|
||||
|
||||
// Parse the body, which is optional
|
||||
// Lookahead is required to distinguish the `s` in reserved-body
|
||||
// from the `s` in `[s] expression`
|
||||
// Next character may be:
|
||||
// * whitespace (followed by either a reserved-body start or
|
||||
// a '{')
|
||||
// * a '{'
|
||||
|
||||
CHECK_BOUNDS(status);
|
||||
|
||||
if (peek() != LEFT_CURLY_BRACE) {
|
||||
if (!isWhitespace(peek())) {
|
||||
ERROR(status);
|
||||
return;
|
||||
}
|
||||
// Expect a reserved-body start
|
||||
int32_t savedIndex = index;
|
||||
parseRequiredWhitespace(status);
|
||||
CHECK_BOUNDS(status);
|
||||
if (isReservedBodyStart(peek())) {
|
||||
// There is a reserved body
|
||||
Reserved::Builder r(status);
|
||||
builder.setBody(parseReservedBody(r, status));
|
||||
} else {
|
||||
// No body -- backtrack so we can parse 1*([s] expression)
|
||||
index = savedIndex;
|
||||
normalizedInput.truncate(normalizedInput.length() - 1);
|
||||
}
|
||||
// Otherwise, the next character must be a '{'
|
||||
// to open the required expression (or optional whitespace)
|
||||
if (peek() != LEFT_CURLY_BRACE && !isWhitespace(peek())) {
|
||||
ERROR(status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, parse the expressions
|
||||
|
||||
// Need to look ahead to disambiguate a '{' beginning
|
||||
// an expression from one beginning with a quoted pattern
|
||||
int32_t expressionCount = 0;
|
||||
while (peek() == LEFT_CURLY_BRACE || isWhitespace(peek())) {
|
||||
parseOptionalWhitespace(status);
|
||||
|
||||
bool nextIsLbrace = peek() == LEFT_CURLY_BRACE;
|
||||
bool nextIsQuotedPattern = nextIsLbrace && inBounds(1)
|
||||
&& peek(1) == LEFT_CURLY_BRACE;
|
||||
if (nextIsQuotedPattern) {
|
||||
break;
|
||||
}
|
||||
|
||||
builder.addExpression(parseExpression(status), status);
|
||||
expressionCount++;
|
||||
}
|
||||
if (expressionCount <= 0) {
|
||||
// At least one expression is required
|
||||
ERROR(status);
|
||||
return;
|
||||
}
|
||||
dataModel.addUnsupportedStatement(builder.build(status), status);
|
||||
}
|
||||
|
||||
// Terrible hack to get around the ambiguity between unsupported keywords
|
||||
// and supported keywords
|
||||
bool Parser::nextIs(const std::u16string_view &keyword) const {
|
||||
for (int32_t i = 0; i < static_cast<int32_t>(keyword.length()); i++) {
|
||||
if (!inBounds(i) || peek(i) != keyword[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Consume a possibly-empty sequence of declarations separated by whitespace;
|
||||
each declaration matches the `declaration` nonterminal in the grammar
|
||||
|
@ -1715,11 +1388,7 @@ void Parser::parseDeclarations(UErrorCode& status) {
|
|||
|
||||
while (peek() == PERIOD) {
|
||||
CHECK_BOUNDS_1(status);
|
||||
// Check for unsupported statements first
|
||||
// Lookahead is needed to disambiguate keyword from known keywords
|
||||
if (!nextIs(ID_MATCH) && !nextIs(ID_LOCAL) && !nextIs(ID_INPUT)) {
|
||||
parseUnsupportedStatement(status);
|
||||
} else if (peek(1) == ID_LOCAL[1]) {
|
||||
if (peek(1) == ID_LOCAL[1]) {
|
||||
parseLocalDeclaration(status);
|
||||
} else if (peek(1) == ID_INPUT[1]) {
|
||||
parseInputDeclaration(status);
|
||||
|
|
|
@ -127,9 +127,6 @@ namespace message2 {
|
|||
void parseOption(OptionAdder<T>&, UErrorCode&);
|
||||
template<class T>
|
||||
void parseOptions(OptionAdder<T>&, UErrorCode&);
|
||||
void parseReservedChunk(Reserved::Builder&, UErrorCode&);
|
||||
Reserved parseReserved(UErrorCode&);
|
||||
Reserved parseReservedBody(Reserved::Builder&, UErrorCode&);
|
||||
Operator parseAnnotation(UErrorCode&);
|
||||
void parseLiteralOrVariableWithAnnotation(bool, Expression::Builder&, UErrorCode&);
|
||||
Markup parseMarkup(UErrorCode&);
|
||||
|
|
|
@ -134,36 +134,10 @@ void Serializer::emitAttributes(const OptionMap& attributes) {
|
|||
}
|
||||
}
|
||||
|
||||
void Serializer::emit(const Reserved& reserved) {
|
||||
// Re-escape '\' / '{' / '|' / '}'
|
||||
for (int32_t i = 0; i < reserved.numParts(); i++) {
|
||||
const Literal& l = reserved.getPart(i);
|
||||
if (l.isQuoted()) {
|
||||
emit(l);
|
||||
} else {
|
||||
const UnicodeString& s = l.unquoted();
|
||||
for (int32_t j = 0; j < s.length(); j++) {
|
||||
switch(s[j]) {
|
||||
case LEFT_CURLY_BRACE:
|
||||
case PIPE:
|
||||
case RIGHT_CURLY_BRACE:
|
||||
case BACKSLASH: {
|
||||
emit(BACKSLASH);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
emit(s[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::emit(const Expression& expr) {
|
||||
emit(LEFT_CURLY_BRACE);
|
||||
|
||||
if (!expr.isReserved() && !expr.isFunctionCall()) {
|
||||
if (!expr.isFunctionCall()) {
|
||||
// Literal or variable, no annotation
|
||||
emit(expr.getOperand());
|
||||
} else {
|
||||
|
@ -176,17 +150,12 @@ void Serializer::emit(const Reserved& reserved) {
|
|||
UErrorCode localStatus = U_ZERO_ERROR;
|
||||
const Operator* rator = expr.getOperator(localStatus);
|
||||
U_ASSERT(U_SUCCESS(localStatus));
|
||||
if (rator->isReserved()) {
|
||||
const Reserved& reserved = rator->asReserved();
|
||||
emit(reserved);
|
||||
} else {
|
||||
emit(COLON);
|
||||
emit(rator->getFunctionName());
|
||||
// No whitespace after function name, in case it has
|
||||
// no options. (when there are options, emit(OptionMap) will
|
||||
// emit the leading whitespace)
|
||||
emit(rator->getOptionsInternal());
|
||||
}
|
||||
emit(COLON);
|
||||
emit(rator->getFunctionName());
|
||||
// No whitespace after function name, in case it has
|
||||
// no options. (when there are options, emit(OptionMap) will
|
||||
// emit the leading whitespace)
|
||||
emit(rator->getOptionsInternal());
|
||||
}
|
||||
emitAttributes(expr.getAttributesInternal());
|
||||
emit(RIGHT_CURLY_BRACE);
|
||||
|
@ -273,26 +242,6 @@ void Serializer::serializeDeclarations() {
|
|||
}
|
||||
}
|
||||
|
||||
void Serializer::serializeUnsupported() {
|
||||
const UnsupportedStatement* statements = dataModel.getUnsupportedStatementsInternal();
|
||||
U_ASSERT(dataModel.unsupportedStatementsLen == 0 || statements != nullptr);
|
||||
|
||||
for (int32_t i = 0; i < dataModel.unsupportedStatementsLen; i++) {
|
||||
const UnsupportedStatement& s = statements[i];
|
||||
emit(s.getKeyword());
|
||||
UErrorCode localErrorCode = U_ZERO_ERROR;
|
||||
const Reserved* r = s.getBody(localErrorCode);
|
||||
if (U_SUCCESS(localErrorCode)) {
|
||||
whitespace();
|
||||
emit(*r);
|
||||
}
|
||||
const Expression* e = s.getExpressionsInternal();
|
||||
for (int32_t j = 0; j < s.expressionsLen; j++) {
|
||||
emit(e[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::serializeSelectors() {
|
||||
U_ASSERT(!dataModel.hasPattern());
|
||||
const Expression* selectors = dataModel.getSelectorsInternal();
|
||||
|
@ -319,7 +268,6 @@ void Serializer::serializeVariants() {
|
|||
// Main (public) serializer method
|
||||
void Serializer::serialize() {
|
||||
serializeDeclarations();
|
||||
serializeUnsupported();
|
||||
// Pattern message
|
||||
if (dataModel.hasPattern()) {
|
||||
emit(dataModel.getPattern());
|
||||
|
|
|
@ -44,14 +44,12 @@ namespace message2 {
|
|||
void emit(const Key&);
|
||||
void emit(const SelectorKeys&);
|
||||
void emit(const Operand&);
|
||||
void emit(const Reserved&);
|
||||
void emit(const Expression&);
|
||||
void emit(const PatternPart&);
|
||||
void emit(const Pattern&);
|
||||
void emit(const Variant*);
|
||||
void emitAttributes(const OptionMap&);
|
||||
void emit(const OptionMap&);
|
||||
void serializeUnsupported();
|
||||
void serializeDeclarations();
|
||||
void serializeSelectors();
|
||||
void serializeVariants();
|
||||
|
|
|
@ -62,163 +62,6 @@ namespace message2 {
|
|||
class Literal;
|
||||
class Operator;
|
||||
|
||||
/**
|
||||
* The `Reserved` class represents a `reserved` annotation, as in the `reserved` nonterminal
|
||||
* in the MessageFormat 2 grammar or the `Reserved` interface
|
||||
* defined in
|
||||
* https://github.com/unicode-org/message-format-wg/blob/main/spec/data-model.md#expressions
|
||||
*
|
||||
* `Reserved` is immutable, copyable and movable.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
class U_I18N_API Reserved : public UMemory {
|
||||
public:
|
||||
/**
|
||||
* A `Reserved` is a sequence of literals.
|
||||
*
|
||||
* @return The number of literals.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
int32_t numParts() const;
|
||||
/**
|
||||
* Indexes into the sequence.
|
||||
* Precondition: i < numParts()
|
||||
*
|
||||
* @param i Index of the part being accessed.
|
||||
* @return A reference to he i'th literal in the sequence
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
const Literal& getPart(int32_t i) const;
|
||||
|
||||
/**
|
||||
* The mutable `Reserved::Builder` class allows the reserved sequence to be
|
||||
* constructed one part at a time.
|
||||
*
|
||||
* Builder is not copyable or movable.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
class U_I18N_API Builder : public UMemory {
|
||||
private:
|
||||
UVector* parts; // Not a LocalPointer for the same reason as in `SelectorKeys::Builder`
|
||||
|
||||
public:
|
||||
/**
|
||||
* Adds a single literal to the reserved sequence.
|
||||
*
|
||||
* @param part The literal to be added. Passed by move.
|
||||
* @param status Input/output error code
|
||||
* @return A reference to the builder.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Builder& add(Literal&& part, UErrorCode& status) noexcept;
|
||||
/**
|
||||
* Constructs a new immutable `Reserved` using the list of parts
|
||||
* set with previous `add()` calls.
|
||||
*
|
||||
* The builder object (`this`) can still be used after calling `build()`.
|
||||
*
|
||||
* param status Input/output error code
|
||||
* @return The new Reserved object
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Reserved build(UErrorCode& status) const noexcept;
|
||||
/**
|
||||
* Default constructor.
|
||||
* Returns a builder with an empty Reserved sequence.
|
||||
*
|
||||
* param status Input/output error code
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Builder(UErrorCode& status);
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
virtual ~Builder();
|
||||
Builder(const Builder&) = delete;
|
||||
Builder& operator=(const Builder&) = delete;
|
||||
Builder(Builder&&) = delete;
|
||||
Builder& operator=(Builder&&) = delete;
|
||||
}; // class Reserved::Builder
|
||||
/**
|
||||
* Non-member swap function.
|
||||
* @param r1 will get r2's contents
|
||||
* @param r2 will get r1's contents
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
friend inline void swap(Reserved& r1, Reserved& r2) noexcept {
|
||||
using std::swap;
|
||||
|
||||
swap(r1.bogus, r2.bogus);
|
||||
swap(r1.parts, r2.parts);
|
||||
swap(r1.len, r2.len);
|
||||
}
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Reserved(const Reserved& other);
|
||||
/**
|
||||
* Assignment operator
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Reserved& operator=(Reserved) noexcept;
|
||||
/**
|
||||
* Default constructor.
|
||||
* Puts the Reserved into a valid but undefined state.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Reserved() { parts = LocalArray<Literal>(); }
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
virtual ~Reserved();
|
||||
private:
|
||||
friend class Builder;
|
||||
friend class Operator;
|
||||
|
||||
// True if a copy failed; this has to be distinguished
|
||||
// from a valid `Reserved` with empty parts
|
||||
bool bogus = false;
|
||||
|
||||
// Possibly-empty list of parts
|
||||
// `literal` reserved as a quoted literal; `reserved-char` / `reserved-escape`
|
||||
// strings represented as unquoted literals
|
||||
/* const */ LocalArray<Literal> parts;
|
||||
int32_t len = 0;
|
||||
|
||||
Reserved(const UVector& parts, UErrorCode& status) noexcept;
|
||||
// Helper
|
||||
static void initLiterals(Reserved&, const Reserved&);
|
||||
};
|
||||
|
||||
/**
|
||||
* The `Literal` class corresponds to the `literal` nonterminal in the MessageFormat 2 grammar,
|
||||
* https://github.com/unicode-org/message-format-wg/blob/main/spec/message.abnf and the
|
||||
|
@ -349,8 +192,6 @@ namespace message2 {
|
|||
virtual ~Literal();
|
||||
|
||||
private:
|
||||
friend class Reserved::Builder;
|
||||
|
||||
/* const */ bool thisIsQuoted = false;
|
||||
/* const */ UnicodeString contents;
|
||||
};
|
||||
|
@ -986,60 +827,22 @@ namespace message2 {
|
|||
}; // class OptionMap
|
||||
#endif
|
||||
|
||||
// Internal use only
|
||||
#ifndef U_IN_DOXYGEN
|
||||
class U_I18N_API Callable : public UObject {
|
||||
public:
|
||||
friend inline void swap(Callable& c1, Callable& c2) noexcept {
|
||||
using std::swap;
|
||||
|
||||
swap(c1.name, c2.name);
|
||||
swap(c1.options, c2.options);
|
||||
}
|
||||
const FunctionName& getName() const { return name; }
|
||||
const OptionMap& getOptions() const { return options; }
|
||||
Callable(const FunctionName& f, const OptionMap& opts) : name(f), options(opts) {}
|
||||
Callable& operator=(Callable) noexcept;
|
||||
Callable(const Callable&);
|
||||
Callable() = default;
|
||||
virtual ~Callable();
|
||||
private:
|
||||
/* const */ FunctionName name;
|
||||
/* const */ OptionMap options;
|
||||
};
|
||||
#endif
|
||||
} // namespace data_model
|
||||
} // namespace message2
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
/// @cond DOXYGEN_IGNORE
|
||||
// Export an explicit template instantiation of the std::variant that is used as a
|
||||
// data member of various MFDataModel classes.
|
||||
// (When building DLLs for Windows this is required.)
|
||||
// (See measunit_impl.h, datefmt.h, collationiterator.h, erarules.h and others
|
||||
// for similar examples.)
|
||||
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
|
||||
#if defined(U_REAL_MSVC) && defined(_MSVC_STL_VERSION)
|
||||
template class U_I18N_API std::_Variant_storage_<false, icu::message2::data_model::Reserved,icu::message2::data_model::Callable>;
|
||||
#endif
|
||||
template class U_I18N_API std::variant<icu::message2::data_model::Reserved,icu::message2::data_model::Callable>;
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
namespace message2 {
|
||||
namespace data_model {
|
||||
/**
|
||||
* The `Operator` class corresponds to the `FunctionRef | Reserved` type in the
|
||||
* The `Operator` class corresponds to the `FunctionRef` type in the
|
||||
* `Expression` interface defined in
|
||||
* https://github.com/unicode-org/message-format-wg/blob/main/spec/data-model.md#patterns
|
||||
*
|
||||
* It represents the annotation that an expression can have: either a function name paired
|
||||
* with a map from option names to operands (possibly empty),
|
||||
* or a reserved sequence, which has no meaning and results in an error if the formatter
|
||||
* is invoked.
|
||||
* It represents the annotation that an expression can have: a function name paired
|
||||
* with a map from option names to operands (possibly empty).
|
||||
*
|
||||
* `Operator` is immutable, copyable and movable.
|
||||
*
|
||||
|
@ -1048,18 +851,8 @@ namespace message2 {
|
|||
*/
|
||||
class U_I18N_API Operator : public UObject {
|
||||
public:
|
||||
/**
|
||||
* Determines if this operator is a reserved annotation.
|
||||
*
|
||||
* @return true if and only if this operator represents a reserved sequence.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
UBool isReserved() const { return std::holds_alternative<Reserved>(contents); }
|
||||
/**
|
||||
* Accesses the function name.
|
||||
* Precondition: !isReserved()
|
||||
*
|
||||
* @return The function name of this operator.
|
||||
*
|
||||
|
@ -1067,19 +860,8 @@ namespace message2 {
|
|||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
const FunctionName& getFunctionName() const;
|
||||
/**
|
||||
* Accesses the underlying reserved sequence.
|
||||
* Precondition: isReserved()
|
||||
*
|
||||
* @return The reserved sequence represented by this operator.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
const Reserved& asReserved() const;
|
||||
/**
|
||||
* Accesses function options.
|
||||
* Precondition: !isReserved()
|
||||
*
|
||||
* @return A vector of function options for this operator.
|
||||
*
|
||||
|
@ -1087,11 +869,7 @@ namespace message2 {
|
|||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
std::vector<Option> getOptions() const {
|
||||
const Callable* f = std::get_if<Callable>(&contents);
|
||||
// This case should never happen, as the precondition is !isReserved()
|
||||
if (f == nullptr) { return {}; }
|
||||
const OptionMap& opts = f->getOptions();
|
||||
return opts.getOptions();
|
||||
return options.getOptions();
|
||||
}
|
||||
/**
|
||||
* The mutable `Operator::Builder` class allows the operator to be constructed
|
||||
|
@ -1105,30 +883,12 @@ namespace message2 {
|
|||
class U_I18N_API Builder : public UMemory {
|
||||
private:
|
||||
friend class Operator;
|
||||
bool isReservedSequence = false;
|
||||
bool hasFunctionName = false;
|
||||
bool hasOptions = false;
|
||||
Reserved asReserved;
|
||||
FunctionName functionName;
|
||||
OptionMap::Builder options;
|
||||
public:
|
||||
/**
|
||||
* Sets this operator to be a reserved sequence.
|
||||
* If a function name and/or options were previously set,
|
||||
* clears them.
|
||||
*
|
||||
* @param reserved The reserved sequence to set as the contents of this Operator.
|
||||
* (Passed by move.)
|
||||
* @return A reference to the builder.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Builder& setReserved(Reserved&& reserved);
|
||||
/**
|
||||
* Sets this operator to be a function annotation and sets its name
|
||||
* to `func`.
|
||||
* If a reserved sequence was previously set, clears it.
|
||||
*
|
||||
* @param func The function name.
|
||||
* @return A reference to the builder.
|
||||
|
@ -1140,7 +900,6 @@ namespace message2 {
|
|||
/**
|
||||
* Sets this operator to be a function annotation and adds a
|
||||
* single option.
|
||||
* If a reserved sequence was previously set, clears it.
|
||||
*
|
||||
* @param key The name of the option.
|
||||
* @param value The value (right-hand side) of the option.
|
||||
|
@ -1152,10 +911,8 @@ namespace message2 {
|
|||
*/
|
||||
Builder& addOption(const UnicodeString &key, Operand&& value, UErrorCode& status) noexcept;
|
||||
/**
|
||||
* Constructs a new immutable `Operator` using the `reserved` annotation
|
||||
* or the function name and options that were previously set.
|
||||
* If neither `setReserved()` nor `setFunctionName()` was previously
|
||||
* called, then `status` is set to U_INVALID_STATE_ERROR.
|
||||
* Constructs a new immutable `Operator` using the
|
||||
* function name and options that were previously set.
|
||||
*
|
||||
* The builder object (`this`) can still be used after calling `build()`.
|
||||
*
|
||||
|
@ -1171,7 +928,7 @@ namespace message2 {
|
|||
Operator build(UErrorCode& status);
|
||||
/**
|
||||
* Default constructor.
|
||||
* Returns a Builder with no function name or reserved sequence set.
|
||||
* Returns a Builder with no function name or options set.
|
||||
*
|
||||
* @param status Input/output error code.
|
||||
*
|
||||
|
@ -1209,7 +966,8 @@ namespace message2 {
|
|||
friend inline void swap(Operator& o1, Operator& o2) noexcept {
|
||||
using std::swap;
|
||||
|
||||
swap(o1.contents, o2.contents);
|
||||
swap(o1.name, o2.name);
|
||||
swap(o1.options, o2.options);
|
||||
}
|
||||
/**
|
||||
* Assignment operator.
|
||||
|
@ -1225,7 +983,7 @@ namespace message2 {
|
|||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Operator() : contents(Reserved()) {}
|
||||
Operator() {}
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
|
@ -1242,12 +1000,12 @@ namespace message2 {
|
|||
|
||||
// Function call constructor
|
||||
Operator(const FunctionName& f, const UVector& options, UErrorCode&);
|
||||
// Reserved sequence constructor
|
||||
Operator(const Reserved& r) : contents(r) {}
|
||||
|
||||
const OptionMap& getOptionsInternal() const;
|
||||
Operator(const FunctionName&, const OptionMap&);
|
||||
/* const */ std::variant<Reserved, Callable> contents;
|
||||
|
||||
/* const */ FunctionName name;
|
||||
/* const */ OptionMap options;
|
||||
}; // class Operator
|
||||
} // namespace data_model
|
||||
} // namespace message2
|
||||
|
@ -1262,7 +1020,6 @@ U_NAMESPACE_END
|
|||
// for similar examples.)
|
||||
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
|
||||
template class U_I18N_API std::optional<icu::message2::data_model::Operator>;
|
||||
template class U_I18N_API std::optional<icu::message2::data_model::Reserved>;
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
|
@ -1520,8 +1277,7 @@ namespace message2 {
|
|||
UBool isStandaloneAnnotation() const;
|
||||
/**
|
||||
* Checks if this expression has a function
|
||||
* annotation (with or without an operand). A reserved
|
||||
* sequence is not a function annotation.
|
||||
* annotation (with or without an operand).
|
||||
*
|
||||
* @return True if and only if the expression has an annotation
|
||||
* that is a function.
|
||||
|
@ -1531,20 +1287,9 @@ namespace message2 {
|
|||
*/
|
||||
UBool isFunctionCall() const;
|
||||
/**
|
||||
* Returns true if and only if this expression is
|
||||
* annotated with a reserved sequence.
|
||||
*
|
||||
* @return True if and only if the expression has an
|
||||
* annotation that is a reserved sequence,
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
UBool isReserved() const;
|
||||
/**
|
||||
* Accesses the function or reserved sequence
|
||||
* Accesses the function
|
||||
* annotating this expression.
|
||||
* If !(isFunctionCall() || isReserved()), sets
|
||||
* If !(isFunctionCall()), sets
|
||||
* `status` to U_INVALID_STATE_ERROR.
|
||||
*
|
||||
* @param status Input/output error code.
|
||||
|
@ -1751,203 +1496,6 @@ template class U_I18N_API LocalArray<message2::data_model::Expression>;
|
|||
|
||||
namespace message2 {
|
||||
namespace data_model {
|
||||
/**
|
||||
* The `UnsupportedStatement` class corresponds to the `reserved-statement` nonterminal in the MessageFormat 2
|
||||
* grammar and the `unsupported-statement` type defined in:
|
||||
* https://github.com/unicode-org/message-format-wg/blob/main/spec/data-model/message.json#L169
|
||||
*
|
||||
* It represents a keyword (string) together with an optional
|
||||
* `Reserved` annotation and a non-empty list of expressions.
|
||||
*
|
||||
* `UnsupportedStatement` is immutable, copyable and movable.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
class U_I18N_API UnsupportedStatement : public UObject {
|
||||
public:
|
||||
/**
|
||||
* Accesses the keyword of this statement.
|
||||
*
|
||||
* @return A reference to a string.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
const UnicodeString& getKeyword() const { return keyword; }
|
||||
/**
|
||||
* Accesses the `reserved-body` of this statement.
|
||||
*
|
||||
* @param status Input/output error code. Set to U_ILLEGAL_ARGUMENT_ERROR
|
||||
* if this unsupported statement has no body.
|
||||
* @return A non-owned pointer to a `Reserved` annotation,
|
||||
* which is non-null if U_SUCCESS(status).
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
const Reserved* getBody(UErrorCode& status) const;
|
||||
/**
|
||||
* Accesses the expressions of this statement.
|
||||
*
|
||||
* @return A vector of Expressions.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
std::vector<Expression> getExpressions() const {
|
||||
if (expressionsLen <= 0 || !expressions.isValid()) {
|
||||
// This case should never happen, but we can't use an assertion here
|
||||
return {};
|
||||
}
|
||||
return toStdVector<Expression>(expressions.getAlias(), expressionsLen);
|
||||
}
|
||||
/**
|
||||
* The mutable `UnsupportedStatement::Builder` class allows the statement to be constructed
|
||||
* incrementally.
|
||||
*
|
||||
* Builder is not copyable or movable.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
class U_I18N_API Builder : public UMemory {
|
||||
private:
|
||||
friend class UnsupportedStatement;
|
||||
friend class message2::Parser;
|
||||
|
||||
UnicodeString keyword;
|
||||
std::optional<Reserved> body;
|
||||
UVector* expressions; // Vector of expressions;
|
||||
// not a LocalPointer for
|
||||
// the same reason as in `SelectorKeys::builder`
|
||||
public:
|
||||
/**
|
||||
* Sets the keyword of this statement.
|
||||
*
|
||||
* @param k The keyword to set.
|
||||
* @return A reference to the builder.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Builder& setKeyword(const UnicodeString& k);
|
||||
/**
|
||||
* Sets the body of this statement.
|
||||
*
|
||||
* @param r The `Reserved` annotation to set as the body. Passed by move.
|
||||
* @return A reference to the builder.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Builder& setBody(Reserved&& r);
|
||||
/**
|
||||
* Adds an expression to this statement.
|
||||
*
|
||||
* @param e The expression to add. Passed by move.
|
||||
* @param status Input/output error code.
|
||||
* @return A reference to the builder.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Builder& addExpression(Expression&& e, UErrorCode& status);
|
||||
/**
|
||||
* Constructs a new immutable `UnsupportedStatement` using the keyword,
|
||||
* body and (if applicable) expressions that were previously set.
|
||||
* If `setKeyword()` was never called, then `status` is set to
|
||||
* U_INVALID_STATE_ERROR. If `setBody()` was never called, the body is
|
||||
* treated as absent (not an error). If `addExpression()` was not called
|
||||
* at least once, then `status` is set to U_INVALID_STATE_ERROR.
|
||||
*
|
||||
* The builder object (`this`) can still be used after calling `build()`.
|
||||
* @param status Input/output error code.
|
||||
* @return The new UnsupportedStatement
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
UnsupportedStatement build(UErrorCode& status) const;
|
||||
/**
|
||||
* Default constructor.
|
||||
* Returns a Builder with no keyword or body set.
|
||||
*
|
||||
* @param status Input/output error code.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Builder(UErrorCode& status);
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
virtual ~Builder();
|
||||
Builder(const Builder&) = delete;
|
||||
Builder& operator=(const Builder&) = delete;
|
||||
Builder(Builder&&) = delete;
|
||||
Builder& operator=(Builder&&) = delete;
|
||||
}; // class UnsupportedStatement::Builder
|
||||
/**
|
||||
* Non-member swap function.
|
||||
* @param s1 will get s2's contents
|
||||
* @param s2 will get s1's contents
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
friend inline void swap(UnsupportedStatement& s1, UnsupportedStatement& s2) noexcept {
|
||||
using std::swap;
|
||||
|
||||
swap(s1.keyword, s2.keyword);
|
||||
swap(s1.body, s2.body);
|
||||
swap(s1.expressions, s2.expressions);
|
||||
swap(s1.expressionsLen, s2.expressionsLen);
|
||||
}
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
UnsupportedStatement(const UnsupportedStatement& other);
|
||||
/**
|
||||
* Assignment operator.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
UnsupportedStatement& operator=(UnsupportedStatement) noexcept;
|
||||
/**
|
||||
* Default constructor.
|
||||
* Puts the UnsupportedStatement into a valid but undefined state.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
UnsupportedStatement() : expressions(LocalArray<Expression>()) {}
|
||||
/**
|
||||
* Destructor.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
virtual ~UnsupportedStatement();
|
||||
private:
|
||||
friend class message2::Serializer;
|
||||
|
||||
/* const */ UnicodeString keyword;
|
||||
/* const */ std::optional<Reserved> body;
|
||||
/* const */ LocalArray<Expression> expressions;
|
||||
/* const */ int32_t expressionsLen = 0;
|
||||
|
||||
const Expression* getExpressionsInternal() const { return expressions.getAlias(); }
|
||||
|
||||
UnsupportedStatement(const UnicodeString&, const std::optional<Reserved>&, const UVector&, UErrorCode&);
|
||||
}; // class UnsupportedStatement
|
||||
|
||||
class Pattern;
|
||||
|
||||
|
@ -2110,8 +1658,6 @@ namespace message2 {
|
|||
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
|
||||
template class U_I18N_API LocalPointerBase<message2::data_model::PatternPart>;
|
||||
template class U_I18N_API LocalArray<message2::data_model::PatternPart>;
|
||||
template class U_I18N_API LocalPointerBase<message2::data_model::UnsupportedStatement>;
|
||||
template class U_I18N_API LocalArray<message2::data_model::UnsupportedStatement>;
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
|
@ -2599,7 +2145,7 @@ namespace message2 {
|
|||
// If non-null, the referent is a member of `expr` so
|
||||
// its lifetime is the same as the lifetime of the enclosing Binding
|
||||
// (as long as there's no mutation)
|
||||
const std::variant<Reserved, Callable>* annotation = nullptr;
|
||||
const Operator* annotation = nullptr;
|
||||
|
||||
const OptionMap& getOptionsInternal() const;
|
||||
|
||||
|
@ -2808,21 +2354,6 @@ namespace message2 {
|
|||
return toStdVector<Variant>(match->variants.getAlias(), match->numVariants);
|
||||
return {};
|
||||
}
|
||||
/**
|
||||
* Accesses the unsupported statements for this data model.
|
||||
*
|
||||
* @return A vector of unsupported statements.
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
std::vector<UnsupportedStatement> getUnsupportedStatements() const {
|
||||
std::vector<UnsupportedStatement> result;
|
||||
if (!bogus) {
|
||||
return toStdVector<UnsupportedStatement>(unsupportedStatements.getAlias(), unsupportedStatementsLen);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
/**
|
||||
* Accesses the pattern (in a message without selectors).
|
||||
* Returns a reference to an empty pattern if the message has selectors.
|
||||
|
@ -2873,8 +2404,6 @@ namespace message2 {
|
|||
swap(m1.body, m2.body);
|
||||
swap(m1.bindings, m2.bindings);
|
||||
swap(m1.bindingsLen, m2.bindingsLen);
|
||||
swap(m1.unsupportedStatements, m2.unsupportedStatements);
|
||||
swap(m1.unsupportedStatementsLen, m2.unsupportedStatementsLen);
|
||||
}
|
||||
/**
|
||||
* Assignment operator
|
||||
|
@ -2918,7 +2447,6 @@ namespace message2 {
|
|||
UVector* selectors = nullptr;
|
||||
UVector* variants = nullptr;
|
||||
UVector* bindings = nullptr;
|
||||
UVector* unsupportedStatements = nullptr;
|
||||
public:
|
||||
/**
|
||||
* Adds a binding, There must not already be a binding
|
||||
|
@ -2933,17 +2461,6 @@ namespace message2 {
|
|||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Builder& addBinding(Binding&& b, UErrorCode& status);
|
||||
/**
|
||||
* Adds an unsupported statement.
|
||||
*
|
||||
* @param s The statement. Passed by move.
|
||||
* @param status Input/output error code.
|
||||
*
|
||||
*
|
||||
* @internal ICU 75 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
Builder& addUnsupportedStatement(UnsupportedStatement&& s, UErrorCode& status);
|
||||
/**
|
||||
* Adds a selector expression. Copies `expression`.
|
||||
* If a pattern was previously set, clears the pattern.
|
||||
|
@ -3046,16 +2563,9 @@ namespace message2 {
|
|||
/* const */ LocalArray<Binding> bindings;
|
||||
int32_t bindingsLen = 0;
|
||||
|
||||
// Unsupported statements
|
||||
// (Treated as a type of `declaration` in the data model spec;
|
||||
// stored separately for convenience)
|
||||
/* const */ LocalArray<UnsupportedStatement> unsupportedStatements;
|
||||
int32_t unsupportedStatementsLen = 0;
|
||||
|
||||
const Binding* getLocalVariablesInternal() const;
|
||||
const Expression* getSelectorsInternal() const;
|
||||
const Variant* getVariantsInternal() const;
|
||||
const UnsupportedStatement* getUnsupportedStatementsInternal() const;
|
||||
|
||||
int32_t numSelectors() const {
|
||||
const Matcher* matcher = std::get_if<Matcher>(&body);
|
||||
|
|
|
@ -34,9 +34,6 @@ static UErrorCode getExpectedRuntimeErrorFromString(const std::string& errorName
|
|||
if (errorName == "unresolved-variable") {
|
||||
return U_MF_UNRESOLVED_VARIABLE_ERROR;
|
||||
}
|
||||
if (errorName == "unsupported-expression") {
|
||||
return U_MF_UNSUPPORTED_EXPRESSION_ERROR;
|
||||
}
|
||||
if (errorName == "bad-operand") {
|
||||
return U_MF_OPERAND_MISMATCH_ERROR;
|
||||
}
|
||||
|
@ -58,11 +55,8 @@ static UErrorCode getExpectedRuntimeErrorFromString(const std::string& errorName
|
|||
if (errorName == "bad-selector") {
|
||||
return U_MF_SELECTOR_ERROR;
|
||||
}
|
||||
if (errorName == "formatting-error") {
|
||||
return U_MF_FORMATTING_ERROR;
|
||||
}
|
||||
// Arbitrary default
|
||||
return U_MF_UNSUPPORTED_STATEMENT_ERROR;
|
||||
return U_MF_FORMATTING_ERROR;
|
||||
}
|
||||
|
||||
static UnicodeString u_str(std::string s) {
|
||||
|
@ -295,17 +289,14 @@ void TestMessageFormat2::jsonTestsFromFiles(IcuTestErrorCode& errorCode) {
|
|||
|
||||
// Do spec tests for syntax errors
|
||||
runTestsFromJsonFile(*this, "spec/syntax-errors.json", errorCode);
|
||||
runTestsFromJsonFile(*this, "unsupported-expressions.json", errorCode);
|
||||
runTestsFromJsonFile(*this, "unsupported-statements.json", errorCode);
|
||||
runTestsFromJsonFile(*this, "syntax-errors-reserved.json", errorCode);
|
||||
|
||||
// Do tests for data model errors
|
||||
runTestsFromJsonFile(*this, "spec/data-model-errors.json", errorCode);
|
||||
runTestsFromJsonFile(*this, "more-data-model-errors.json", errorCode);
|
||||
|
||||
// Do tests for reserved statements/expressions
|
||||
runTestsFromJsonFile(*this, "spec/unsupported-expressions.json", errorCode);
|
||||
runTestsFromJsonFile(*this, "spec/unsupported-statements.json", errorCode);
|
||||
// Uncomment when reserved syntax is removed
|
||||
// runTestsFromJsonFile(*this, "syntax-errors-reserved.json", errorCode);
|
||||
|
||||
// Do valid spec tests
|
||||
runTestsFromJsonFile(*this, "spec/syntax.json", errorCode);
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ public class CoreTest extends CoreTestFmwk {
|
|||
"syntax-errors-end-of-input.json",
|
||||
"syntax-errors-reserved.json",
|
||||
"tricky-declarations.json",
|
||||
"unsupported-expressions.json",
|
||||
"unsupported-statements.json",
|
||||
"valid-tests.json"};
|
||||
|
||||
@Test
|
||||
|
|
28
testdata/message2/more-data-model-errors.json
vendored
28
testdata/message2/more-data-model-errors.json
vendored
|
@ -102,34 +102,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"src": ".match {|horse| ^private}\n 1 {{The value is one.}} * {{The value is not one.}}",
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "missing-selector-annotation"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"src": ".match {$foo !select} |1| {{one}} * {{other}}",
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "missing-selector-annotation"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"src": ".match {$foo ^select} |1| {{one}} * {{other}}",
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "missing-selector-annotation"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"src": ".input {$foo} .match {$foo} one {{one}} * {{other}}",
|
||||
"expErrors": [
|
||||
|
|
9
testdata/message2/resolution-errors.json
vendored
9
testdata/message2/resolution-errors.json
vendored
|
@ -9,13 +9,6 @@
|
|||
{ "src": ".input {$x :number} {{{$x}}}", "exp": "{$x}", "expErrors": [{ "type": "unresolved-variable" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"},
|
||||
{ "src": ".local $foo = {$bar} .match {$foo :number} one {{one}} * {{other}}", "exp": "other", "expErrors": [{ "type": "unresolved-variable" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"},
|
||||
{ "src": ".local $bar = {$none :number} .match {$foo :string} one {{one}} * {{{$bar}}}", "exp": "{$none}", "expErrors": [{ "type": "unresolved-variable" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"},
|
||||
{ "src": "The value is {horse :func}.", "exp": "The value is {|horse|}.", "expErrors": [{ "type": "unknown-function" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"},
|
||||
{ "src": ".matc {-1} {{hello}}",
|
||||
"expErrors": [{ "type": "unsupported-statement" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{ "src": ".m {-1} {{hello}}",
|
||||
"expErrors": [{ "type": "unsupported-statement" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782" }
|
||||
{ "src": "The value is {horse :func}.", "exp": "The value is {|horse|}.", "expErrors": [{ "type": "unknown-function" }], "ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"}
|
||||
]
|
||||
}
|
||||
|
|
271
testdata/message2/spec/syntax.json
vendored
271
testdata/message2/spec/syntax.json
vendored
|
@ -172,13 +172,6 @@
|
|||
"src": ".local $x ={a}.input{$y}{{}}",
|
||||
"exp": ""
|
||||
},
|
||||
{
|
||||
"description": "message -> complex-message -> *(declaration [s]) complex-body -> declaration complex-body -> reserved-statement complex-body -> reserved-keyword expression -> \".\" name expression complex-body",
|
||||
"src": ".n{a}{{}}",
|
||||
"exp": "",
|
||||
"expErrors": [ { "type": "unsupported-statement" } ],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "message -> complex-message -> complex-body -> matcher -> match-statement variant -> match selector key quoted-pattern -> \".match\" expression literal quoted-pattern",
|
||||
"src": ".match{a :f}a{{}}*{{}}",
|
||||
|
@ -298,20 +291,6 @@
|
|||
"expErrors": [{ "type": "unknown-function" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... annotation -> private-use-annotation -> private-start",
|
||||
"src": "{^}",
|
||||
"exp": "{^}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... annotation -> reserved-annotation -> reserved-annotation-start",
|
||||
"src": "{!}",
|
||||
"exp": "{!}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "message -> simple-message -> simple-start pattern -> placeholder -> markup -> \"{\" s \"#\" identifier \"}\"",
|
||||
"src": "{ #a}",
|
||||
|
@ -507,132 +486,6 @@
|
|||
"src": "{0E-1}",
|
||||
"exp": "0E-1"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-statement -> reserved-keyword s reserved-body 1*([s] expression) -> reserved-keyword s reserved-body expression -> \".\" name s reserved-body-part expression -> \".\" name s reserved-char expression ...",
|
||||
"src": ".n .{a}{{}}",
|
||||
"exp": "",
|
||||
"expErrors": [ { "type": "unsupported-statement" } ],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-statement -> reserved-keyword reserved-body 1*([s] expression) -> reserved-keyword s reserved-body s expression -> \".\" name s reserved-body-part expression -> \".\" name s reserved-char expression ...",
|
||||
"src": ".n. {a}{{}}",
|
||||
"exp": "",
|
||||
"expErrors": [ { "type": "unsupported-statement" } ],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-statement -> reserved-keyword reserved-body 1*([s] expression) -> reserved-keyword reserved-body expression expression -> \".\" name reserved-body-part expression expression -> \".\" name s reserved-char expression expression ...",
|
||||
"src": ".n.{a}{b}{{}}",
|
||||
"exp": "",
|
||||
"expErrors": [ { "type": "unsupported-statement" } ],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation -> reserved-annotation-start reserved-body -> \"!\" reserved-body-part -> \"!\" reserved-char ...",
|
||||
"src": "{!.}",
|
||||
"exp": "{!}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation -> reserved-annotation-start s reserved-body -> \"!\" s reserved-body-part -> \"!\" s reserved-char ...",
|
||||
"src": "{! .}",
|
||||
"exp": "{!}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation-start ...",
|
||||
"src": "{%}",
|
||||
"exp": "{%}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation-start ...",
|
||||
"src": "{*}",
|
||||
"exp": "{*}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation-start ...",
|
||||
"src": "{+}",
|
||||
"exp": "{+}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation-start ...",
|
||||
"src": "{<}",
|
||||
"exp": "{<}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation-start ...",
|
||||
"src": "{>}",
|
||||
"exp": "{>}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation-start ...",
|
||||
"src": "{?}",
|
||||
"exp": "{?}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation-start ...",
|
||||
"src": "{~}",
|
||||
"exp": "{~}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... private-use-annotation -> private-start reserved-body -> \"^\" reserved-body-part -> \"^\" reserved-char ...",
|
||||
"src": "{^.}",
|
||||
"exp": "{^}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... private-use-annotation -> private-start s reserved-body -> \"^\" s reserved-body-part -> \"^\" s reserved-char ...",
|
||||
"src": "{^ .}",
|
||||
"exp": "{^}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... private-start ...",
|
||||
"src": "{&}",
|
||||
"exp": "{&}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation -> reserved-annotation-start reserved-body -> \"!\" reserved-body-part reserved-body-part -> \"!\" reserved-char escaped-char ...",
|
||||
"src": "{!.\\{}",
|
||||
"exp": "{!}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation -> reserved-annotation-start reserved-body -> \"!\" reserved-body-part s reserved-body-part -> \"!\" reserved-char s escaped-char ...",
|
||||
"src": "{!. \\{}",
|
||||
"exp": "{!}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"description": "... reserved-annotation -> reserved-annotation-start reserved-body -> \"!\" reserved-body-part -> \"!\" quoted-literal ...",
|
||||
"src": "{!|a|}",
|
||||
"exp": "{!}",
|
||||
"expErrors": [{ "type": "unsupported-expression" }],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"src": "hello { world\t\n}",
|
||||
"exp": "hello world"
|
||||
|
@ -838,130 +691,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"src": "foo {+reserved}",
|
||||
"exp": "foo {+}",
|
||||
"expParts": [
|
||||
{
|
||||
"type": "literal",
|
||||
"value": "foo "
|
||||
},
|
||||
{
|
||||
"type": "fallback",
|
||||
"source": "+"
|
||||
}
|
||||
],
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "unsupported-expression"
|
||||
}
|
||||
],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"src": "foo {&private}",
|
||||
"exp": "foo {&}",
|
||||
"expParts": [
|
||||
{
|
||||
"type": "literal",
|
||||
"value": "foo "
|
||||
},
|
||||
{
|
||||
"type": "fallback",
|
||||
"source": "&"
|
||||
}
|
||||
],
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "unsupported-expression"
|
||||
}
|
||||
],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"src": "foo {?reserved @a @b=$c}",
|
||||
"exp": "foo {?}",
|
||||
"expParts": [
|
||||
{
|
||||
"type": "literal",
|
||||
"value": "foo "
|
||||
},
|
||||
{
|
||||
"type": "fallback",
|
||||
"source": "?"
|
||||
}
|
||||
],
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "unsupported-expression"
|
||||
}
|
||||
],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"src": ".foo {42} {{bar}}",
|
||||
"exp": "bar",
|
||||
"expParts": [
|
||||
{
|
||||
"type": "literal",
|
||||
"value": "bar"
|
||||
}
|
||||
],
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "unsupported-statement"
|
||||
}
|
||||
],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"src": ".foo{42}{{bar}}",
|
||||
"exp": "bar",
|
||||
"expParts": [
|
||||
{
|
||||
"type": "literal",
|
||||
"value": "bar"
|
||||
}
|
||||
],
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "unsupported-statement"
|
||||
}
|
||||
],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"src": ".foo |}lit{| {42}{{bar}}",
|
||||
"exp": "bar",
|
||||
"expParts": [
|
||||
{
|
||||
"type": "literal",
|
||||
"value": "bar"
|
||||
}
|
||||
],
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "unsupported-statement"
|
||||
}
|
||||
],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"src": ".l $y = {|bar|} {{}}",
|
||||
"exp": "",
|
||||
"expParts": [
|
||||
{
|
||||
"type": "literal",
|
||||
"value": "bar"
|
||||
}
|
||||
],
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "unsupported-statement"
|
||||
}
|
||||
],
|
||||
"ignoreJava": "See https://github.com/unicode-org/message-format-wg/issues/782"
|
||||
},
|
||||
{
|
||||
"src": "{{trailing whitespace}} \n",
|
||||
"exp": "trailing whitespace"
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"scenario": "Reserved statements",
|
||||
"description": "Tests for unsupported statements",
|
||||
"defaultTestProperties": {
|
||||
"locale": "en-US",
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "unsupported-statement"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{ "src" : ".i {1} {{}}" },
|
||||
{ "src" : ".l $y = {|bar|} {{}}" },
|
||||
{ "src" : ".l $x.y = {|bar|} {{}}" }
|
||||
]
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"scenario": "Reserved and private annotations",
|
||||
"description": "Tests for unsupported expressions (reserved/private)",
|
||||
"description": "Tests for unsupported expressions (reserved/private) (now syntax errors)",
|
||||
"defaultTestProperties": {
|
||||
"locale": "en-US",
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "unsupported-expression"
|
||||
"type": "syntax-error"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -47,7 +47,31 @@
|
|||
{ "src": "hello {$foo +num x \\\\ abcde |3.14| r }" },
|
||||
{ "src": "hello {$foo >num x \\\\ abcde |aaa||3.14||42| r }" },
|
||||
{ "src": "hello {$foo >num x \\\\ abcde |aaa||3.14| |42| r }" },
|
||||
{ "src" : ".input{ $n ~ }{{{$n}}}" }
|
||||
{ "src" : ".input{ $n ~ }{{{$n}}}" },
|
||||
{ "src": "foo {+reserved}"},
|
||||
{ "src": "foo {&private}" },
|
||||
{ "src": "foo {?reserved @a @b=$c}" },
|
||||
{ "src": "{!.}" },
|
||||
{ "src": "{! .}" },
|
||||
{ "src": "{%}" },
|
||||
{ "src": "{*}" },
|
||||
{ "src": "{+}" },
|
||||
{ "src": "{<}" },
|
||||
{ "src": "{>}" },
|
||||
{ "src": "{?}" },
|
||||
{ "src": "{~}" },
|
||||
{ "src": "{^.}" },
|
||||
{ "src": "{^ .}" },
|
||||
{ "src": "{&}" },
|
||||
{ "src": "{!.\\{}" },
|
||||
{ "src": "{!. \\{}" },
|
||||
{ "src": "{!|a|}" },
|
||||
{ "src": "{^}" },
|
||||
{ "src": "{!}" },
|
||||
{ "src": ".match {$foo !select} |1| {{one}} * {{other}}" },
|
||||
{ "src": ".match {$foo ^select} |1| {{one}} * {{other}}" },
|
||||
{ "src": ".match {|horse| ^private}\n 1 {{The value is one.}} * {{The value is not one.}}" },
|
||||
{ "src": ".match {$foo ^select} |1| {{one}} * {{other}}" }
|
||||
]
|
||||
}
|
||||
|
27
testdata/message2/unsupported-statements.json
vendored
Normal file
27
testdata/message2/unsupported-statements.json
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"scenario": "Reserved statements",
|
||||
"description": "Tests for unsupported statements (now syntax errors)",
|
||||
"defaultTestProperties": {
|
||||
"locale": "en-US",
|
||||
"expErrors": [
|
||||
{
|
||||
"type": "syntax-error"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{ "src" : ".i {1} {{}}" },
|
||||
{ "src" : ".l $y = {|bar|} {{}}" },
|
||||
{ "src" : ".l $x.y = {|bar|} {{}}" },
|
||||
{ "src": ".matc {-1} {{hello}}" },
|
||||
{ "src": ".m {-1} {{hello}}" },
|
||||
{ "src": ".n{a}{{}}" },
|
||||
{ "src": ".foo {42} {{bar}}" },
|
||||
{ "src": ".foo{42}{{bar}}" },
|
||||
{ "src": ".foo |}lit{| {42}{{bar}}" },
|
||||
{ "src": ".n .{a}{{}}" },
|
||||
{ "src": ".n. {a}{{}}" },
|
||||
{ "src": ".n.{a}{b}{{}}" }
|
||||
]
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue