Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT: WIP on function composition #3228

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Comments; renaming fields to be more informative
  • Loading branch information
catamorphism committed Oct 1, 2024
commit 135fec0a77e6885b7b4b593f0b0ace737ff6da2b
8 changes: 4 additions & 4 deletions icu4c/source/i18n/messageformat2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ static Formattable evalLiteral(const Literal& lit) {
str += var;
const Formattable* val = context.getGlobal(var, errorCode);
if (U_SUCCESS(errorCode)) {
return (FormattedPlaceholder(*val, str, errorCode));
return FormattedPlaceholder(*val, str);
}
}
return {};
}

// Returns the contents of the literal
[[nodiscard]] FormattedPlaceholder MessageFormatter::formatLiteral(const Literal& lit, UErrorCode& errorCode) const {
[[nodiscard]] FormattedPlaceholder MessageFormatter::formatLiteral(const Literal& lit) const {
// The fallback for a literal is itself.
return FormattedPlaceholder(evalLiteral(lit), lit.quoted(), errorCode);
return FormattedPlaceholder(evalLiteral(lit), lit.quoted());
}

[[nodiscard]] InternalValue MessageFormatter::formatOperand(const Environment& env,
Expand Down Expand Up @@ -93,7 +93,7 @@ static Formattable evalLiteral(const Literal& lit) {
return InternalValue(std::move(result));
} else {
U_ASSERT(rand.isLiteral());
return InternalValue(formatLiteral(rand.asLiteral(), status));
return InternalValue(formatLiteral(rand.asLiteral()));
}
}

Expand Down
6 changes: 6 additions & 0 deletions icu4c/source/i18n/messageformat2_evaluation.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ namespace message2 {

using namespace data_model;

// InternalValue tracks a value along with, possibly, a function that needs
// to be applied to it in the future (once the value is required
// (by a .match or pattern));
// while FormattedPlaceholder tracks a value and how it was constructed in the
// past (by a function, or from a literal or argument).

// InternalValue represents an intermediate value in the message
// formatter. An InternalValue can either be a fallback value (representing
// an error that occurred during formatting); a "suspension", meaning a function
Expand Down
95 changes: 26 additions & 69 deletions icu4c/source/i18n/messageformat2_formattable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,27 +174,17 @@ namespace message2 {


FormattedPlaceholder& FormattedPlaceholder::operator=(FormattedPlaceholder&& other) noexcept {
type = other.type;
origin = other.origin;
source = other.source;
if (type == kEvaluated) {
formatted = std::move(other.formatted);
}
if (previousOptions != nullptr) {
delete previousOptions;
}
if (other.previousOptions != nullptr) {
previousOptions = other.previousOptions;
other.previousOptions = nullptr;
} else {
previousOptions = nullptr;
}
formatted = std::move(other.formatted);
previousOptions = std::move(other.previousOptions);
fallback = other.fallback;
return *this;
}

const Formattable* FormattedPlaceholder::getSource(UErrorCode& errorCode) const {
if (U_SUCCESS(errorCode)) {
if (type != kNull) {
if (origin != kNull) {
return &source;
} else {
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
Expand All @@ -205,7 +195,7 @@ namespace message2 {

FormattedPlaceholder FormattedPlaceholder::withResult(FormattedValue&& result) {
formatted = std::move(result);
type = kEvaluated;
origin = kFunctionResult;
return std::move(*this);
}

Expand All @@ -216,70 +206,38 @@ namespace message2 {
return {};
}
formatted = std::move(result);
type = kEvaluated;
delete previousOptions;
previousOptions = create<FunctionOptions>(std::move(opts), status);
if (U_FAILURE(status)) {
previousOptions = nullptr;
return {};
}
origin = kFunctionResult;
previousOptions = std::move(opts);
return std::move(*this);
}

FormattedPlaceholder::FormattedPlaceholder(const FormattedPlaceholder& input,
FunctionOptions&& opts,
FormattedValue&& output,
UErrorCode& status)
FormattedValue&& output)
: fallback(input.fallback),
source(input.source),
formatted(std::move(output)),
previousOptions(nullptr),
type(kEvaluated) {
CHECK_ERROR(status);

LocalPointer<FunctionOptions> temp(create<FunctionOptions>(std::move(opts), status));
CHECK_ERROR(status);
previousOptions = temp.orphan();
}
previousOptions(std::move(opts)),
origin(kFunctionResult) {}

FormattedPlaceholder::FormattedPlaceholder(const FormattedPlaceholder& input,
FormattedValue&& output,
UErrorCode& status)
FormattedValue&& output)
: fallback(input.fallback),
source(input.source),
formatted(std::move(output)),
type(kEvaluated) {
initOptions(status);
}
origin(kFunctionResult) {}

FormattedPlaceholder::FormattedPlaceholder(const Formattable& input,
const UnicodeString& fb,
UErrorCode& status)
: fallback(fb), source(input), type(kUnevaluated) {
initOptions(status);
}

FormattedPlaceholder::FormattedPlaceholder() : type(kNull) {
previousOptions = nullptr;
}
const UnicodeString& fb)
: fallback(fb), source(input), origin(kArgumentOrLiteral) {}

void FormattedPlaceholder::initOptions(UErrorCode& status) {
LocalPointer<FunctionOptions> temp(create<FunctionOptions>(FunctionOptions(), status));
CHECK_ERROR(status);
previousOptions = temp.orphan();
}
FormattedPlaceholder::FormattedPlaceholder() : origin(kNull) {}

const message2::FunctionOptions& FormattedPlaceholder::getOptions() const {
U_ASSERT(previousOptions != nullptr);
return *previousOptions;
return previousOptions;
}

FormattedPlaceholder::~FormattedPlaceholder() {
if (previousOptions != nullptr) {
delete previousOptions;
previousOptions = nullptr;
}
}
FormattedPlaceholder::~FormattedPlaceholder() {}

// Default formatters
// ------------------
Expand Down Expand Up @@ -340,8 +298,7 @@ namespace message2 {
}
if (asDecimal != nullptr) {
return FormattedPlaceholder(input,
FormattedValue(formatNumberWithDefaults(locale, asDecimal, status)),
status);
FormattedValue(formatNumberWithDefaults(locale, asDecimal, status)));
}
}

Expand All @@ -352,27 +309,27 @@ namespace message2 {
UDate d = toFormat->getDate(status);
U_ASSERT(U_SUCCESS(status));
formatDateWithDefaults(locale, d, result, status);
return FormattedPlaceholder(input, FormattedValue(std::move(result)), status);
return FormattedPlaceholder(input, FormattedValue(std::move(result)));
}
case UFMT_DOUBLE: {
double d = toFormat->getDouble(status);
U_ASSERT(U_SUCCESS(status));
return FormattedPlaceholder(input, FormattedValue(formatNumberWithDefaults(locale, d, status)), status);
return FormattedPlaceholder(input, FormattedValue(formatNumberWithDefaults(locale, d, status)));
}
case UFMT_LONG: {
int32_t l = toFormat->getLong(status);
U_ASSERT(U_SUCCESS(status));
return FormattedPlaceholder(input, FormattedValue(formatNumberWithDefaults(locale, l, status)), status);
return FormattedPlaceholder(input, FormattedValue(formatNumberWithDefaults(locale, l, status)));
}
case UFMT_INT64: {
int64_t i = toFormat->getInt64Value(status);
U_ASSERT(U_SUCCESS(status));
return FormattedPlaceholder(input, FormattedValue(formatNumberWithDefaults(locale, i, status)), status);
return FormattedPlaceholder(input, FormattedValue(formatNumberWithDefaults(locale, i, status)));
}
case UFMT_STRING: {
const UnicodeString& s = toFormat->getString(status);
U_ASSERT(U_SUCCESS(status));
return FormattedPlaceholder(input, FormattedValue(UnicodeString(s)), status);
return FormattedPlaceholder(input, FormattedValue(UnicodeString(s)));
}
default: {
// No default formatters for other types; use fallback
Expand All @@ -393,16 +350,16 @@ namespace message2 {
return {};
}

// Evaluated value: either just return the string, or format the number
// Function result: either just return the string, or format the number
// as a string and return it
if (isEvaluated()) {
if (isFunctionResult()) {
if (formatted.isString()) {
return formatted.getString();
} else {
return formatted.getNumber().toString(status);
}
}
// Unevaluated value: first evaluate it fully, then format
// Unannotated value: apply default formatters
UErrorCode savedStatus = status;
FormattedPlaceholder evaluated = formatWithDefaults(locale, *this, status);
if (status == U_MF_FORMATTING_ERROR) {
Expand Down
15 changes: 8 additions & 7 deletions icu4c/source/i18n/messageformat2_function_registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,8 +439,8 @@ Formatter* StandardFunctions::IntegerFactory::createFormatter(const Locale& loca

StandardFunctions::IntegerFactory::~IntegerFactory() {}

static FormattedPlaceholder notANumber(const FormattedPlaceholder& input, UErrorCode& status) {
return FormattedPlaceholder(input, FormattedValue(UnicodeString("NaN")), status);
static FormattedPlaceholder notANumber(const FormattedPlaceholder& input) {
return FormattedPlaceholder(input, FormattedValue(UnicodeString("NaN")));
}

static double parseNumberLiteral(const UnicodeString& inputStr, UErrorCode& errorCode) {
Expand Down Expand Up @@ -600,12 +600,12 @@ FormattedPlaceholder StandardFunctions::Number::format(FormattedPlaceholder&& ar
default: {
// Other types can't be parsed as a number
errorCode = U_MF_OPERAND_MISMATCH_ERROR;
return notANumber(arg, errorCode);
return notANumber(arg);
}
}
}

return FormattedPlaceholder(arg, FormattedValue(std::move(numberResult)), errorCode);
return FormattedPlaceholder(arg, FormattedValue(std::move(numberResult)));
}

StandardFunctions::Number::~Number() {}
Expand Down Expand Up @@ -660,7 +660,8 @@ void StandardFunctions::Plural::selectKey(FormattedPlaceholder&& toFormat,
errorCode);
CHECK_ERROR(errorCode);

U_ASSERT(resolvedSelector.isEvaluated() && resolvedSelector.output().isNumber());
U_ASSERT(resolvedSelector.isFunctionResult()
&& resolvedSelector.output().isNumber());

// See https://github.com/unicode-org/message-format-wg/blob/main/spec/registry.md#number-selection
// 1. Let exact be the JSON string representation of the numeric value of resolvedSelector
Expand Down Expand Up @@ -1107,7 +1108,7 @@ FormattedPlaceholder StandardFunctions::DateTime::format(FormattedPlaceholder&&
// in the returned FormattedPlaceholder; this is necessary
// so the date can be re-formatted
toFormat = FormattedPlaceholder(message2::Formattable::forDate(d),
toFormat.getFallback(), errorCode);
toFormat.getFallback());
df->format(d, result, 0, errorCode);
}
break;
Expand All @@ -1130,7 +1131,7 @@ FormattedPlaceholder StandardFunctions::DateTime::format(FormattedPlaceholder&&
if (U_FAILURE(errorCode)) {
return {};
}
return FormattedPlaceholder(toFormat, std::move(opts), FormattedValue(std::move(result)), errorCode);
return FormattedPlaceholder(toFormat, std::move(opts), FormattedValue(std::move(result)));
}

StandardFunctions::DateTimeFactory::~DateTimeFactory() {}
Expand Down
2 changes: 1 addition & 1 deletion icu4c/source/i18n/unicode/messageformat2.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ namespace message2 {
void resolvePreferences(MessageContext&, UVector&, UVector&, UErrorCode&) const;

// Formatting methods
[[nodiscard]] FormattedPlaceholder formatLiteral(const data_model::Literal&, UErrorCode&) const;
[[nodiscard]] FormattedPlaceholder formatLiteral(const data_model::Literal&) const;
void formatPattern(MessageContext&, const Environment&, const data_model::Pattern&, UErrorCode&, UnicodeString&) const;
[[nodiscard]] InternalValue eval(MessageContext&, InternalValue, UErrorCode&) const;
// Dispatches on argument type
Expand Down
Loading
Loading