icu/icu4c/source/i18n/messageformat2_errors.h
Tim Chevalier d0e30acc68 ICU-23059 ICU4C MF2: Spec test updates
Update spec tests to current version from message-format-wg

  - Update parser for changed name-start grammar rule
  - Validate number literals in :number implementation (since parser no longer does this)
  - Disallow `:number`/`:integer` select option set from variable

    See https://github.com/unicode-org/message-format-wg/pull/1016

    As part of this, un-skip tests where the `bad-option` error is
    expected, and implement validating digit size options
    (pending PR https://github.com/unicode-org/icu/pull/2973 is intended
    to do this more fully)
2025-03-27 15:20:49 -07:00

178 lines
5.6 KiB
C++

// © 2024 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#include "unicode/utypes.h"
#ifndef U_HIDE_DEPRECATED_API
#ifndef MESSAGEFORMAT2_ERRORS_H
#define MESSAGEFORMAT2_ERRORS_H
#if U_SHOW_CPLUSPLUS_API
/**
* \file
* \brief C++ API: Formats messages using the draft MessageFormat 2.0.
*/
#if !UCONFIG_NO_NORMALIZATION
#if !UCONFIG_NO_FORMATTING
#if !UCONFIG_NO_MF2
#include "unicode/messageformat2_data_model_names.h"
#include "unicode/unistr.h"
#include "uvector.h"
U_NAMESPACE_BEGIN
namespace message2 {
using namespace data_model;
// Errors
// ----------
class DynamicErrors;
class StaticErrors;
// Internal class -- used as a private field in MessageFormatter
template <typename ErrorType>
class Error : public UObject {
public:
Error(ErrorType ty) : type(ty) {}
Error(ErrorType ty, const UnicodeString& s) : type(ty), contents(s) {}
virtual ~Error();
private:
friend class DynamicErrors;
friend class StaticErrors;
ErrorType type;
UnicodeString contents;
}; // class Error
enum StaticErrorType {
DuplicateDeclarationError,
DuplicateOptionName,
DuplicateVariant,
MissingSelectorAnnotation,
NonexhaustivePattern,
SyntaxError,
VariantKeyMismatchError
};
enum DynamicErrorType {
UnresolvedVariable,
FormattingError,
BadOptionError,
/**
This is used to signal errors from :number and :integer when a
bad `select` option is passed. In this case, fallback output
is not used, so it must be distinguished from a regular bad
option error (but it maps to a bad option error in the final
error code).
See https://github.com/unicode-org/message-format-wg/blob/main/spec/functions/number.md#number-selection
"The formatting of the _resolved value_ is not affected by the `select` option.")
*/
RecoverableBadOptionError,
OperandMismatchError,
SelectorError,
UnknownFunction,
};
using StaticError = Error<StaticErrorType>;
using DynamicError = Error<DynamicErrorType>;
// These explicit instantiations have to come before the
// destructor definitions
template<>
Error<StaticErrorType>::~Error();
template<>
Error<DynamicErrorType>::~Error();
class StaticErrors : public UObject {
private:
friend class DynamicErrors;
LocalPointer<UVector> syntaxAndDataModelErrors;
bool dataModelError = false;
bool missingSelectorAnnotationError = false;
bool syntaxError = false;
public:
StaticErrors(UErrorCode&);
void setMissingSelectorAnnotation(UErrorCode&);
void setDuplicateOptionName(UErrorCode&);
void addSyntaxError(UErrorCode&);
bool hasDataModelError() const { return dataModelError; }
bool hasSyntaxError() const { return syntaxError; }
bool hasMissingSelectorAnnotationError() const { return missingSelectorAnnotationError; }
void addError(StaticError&&, UErrorCode&);
void checkErrors(UErrorCode&) const;
void clear();
const StaticError& first() const;
StaticErrors(const StaticErrors&, UErrorCode&);
StaticErrors(StaticErrors&&) noexcept;
virtual ~StaticErrors();
}; // class StaticErrors
class DynamicErrors : public UObject {
private:
const StaticErrors& staticErrors;
LocalPointer<UVector> resolutionAndFormattingErrors;
bool formattingError = false;
bool badOptionError = false;
bool selectorError = false;
bool unknownFunctionError = false;
bool unresolvedVariableError = false;
public:
DynamicErrors(const StaticErrors&, UErrorCode&);
int32_t count() const;
void setSelectorError(const FunctionName&, UErrorCode&);
void setUnresolvedVariable(const VariableName&, UErrorCode&);
void setUnknownFunction(const FunctionName&, UErrorCode&);
void setFormattingError(const FunctionName&, UErrorCode&);
// Used when the name of the offending formatter is unknown
void setFormattingError(UErrorCode&);
void setBadOption(const FunctionName&, UErrorCode&);
void setRecoverableBadOption(const FunctionName&, UErrorCode&);
void setOperandMismatchError(const FunctionName&, UErrorCode&);
bool hasDataModelError() const { return staticErrors.hasDataModelError(); }
bool hasFormattingError() const { return formattingError; }
bool hasBadOptionError() const { return badOptionError; }
bool hasSelectorError() const { return selectorError; }
bool hasSyntaxError() const { return staticErrors.hasSyntaxError(); }
bool hasUnknownFunctionError() const { return unknownFunctionError; }
bool hasMissingSelectorAnnotationError() const { return staticErrors.hasMissingSelectorAnnotationError(); }
bool hasUnresolvedVariableError() const { return unresolvedVariableError; }
void addError(DynamicError&&, UErrorCode&);
void checkErrors(UErrorCode&) const;
bool hasError() const;
bool hasStaticError() const;
const DynamicError& first() const;
virtual ~DynamicErrors();
}; // class DynamicErrors
} // namespace message2
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_MF2 */
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif /* #if !UCONFIG_NO_NORMALIZATION */
#endif /* U_SHOW_CPLUSPLUS_API */
#endif // MESSAGEFORMAT2_ERRORS_H
#endif // U_HIDE_DEPRECATED_API
// eof