Skip to content

Commit 51f75ae

Browse files
committed
Fix rebasing issues
1 parent be097f0 commit 51f75ae

File tree

6 files changed

+314
-365
lines changed

6 files changed

+314
-365
lines changed

icu4c/source/i18n/messageformat2.cpp

Lines changed: 65 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,66 @@ static UnicodeString reserialize(const UnicodeString& s) {
118118
return {};
119119
}
120120

121+
[[nodiscard]] InternalValue& MessageFormatter::evalVariableReference(const UnicodeString& fallback,
122+
Environment& env,
123+
const VariableName& var,
124+
MessageContext& context,
125+
UErrorCode &status) const {
126+
// Check if it's local or global
127+
// Note: there is no name shadowing; this is enforced by the parser
128+
129+
// This code implements lazy call-by-need evaluation of locals.
130+
// That is, the environment binds names to a closure, not a resolved value.
131+
// The spec does not require either eager or lazy evaluation.
132+
133+
// NFC-normalize the variable name. See
134+
// https://github.com/unicode-org/message-format-wg/blob/main/spec/syntax.md#names-and-identifiers
135+
const VariableName normalized = StandardFunctions::normalizeNFC(var);
136+
137+
// Look up the variable in the environment
138+
if (env.has(normalized)) {
139+
// `var` is a local -- look it up
140+
InternalValue& rhs = env.lookup(normalized);
141+
// Evaluate the expression using the environment from the closure
142+
// The name of this local variable is the fallback for its RHS.
143+
UnicodeString newFallback(DOLLAR);
144+
newFallback += var;
145+
146+
if (!rhs.isEvaluated()) {
147+
Closure& c = rhs.asClosure();
148+
InternalValue& result = evalExpression(newFallback,
149+
c.getEnv(),
150+
c.getExpr(),
151+
context,
152+
status);
153+
// Overwrite the closure with the result of evaluation
154+
if (result.isFallback()) {
155+
rhs.update(result.asFallback());
156+
} else {
157+
U_ASSERT(result.isEvaluated());
158+
// Create an indirection to the result returned
159+
// by evalExpression()
160+
rhs.update(result);
161+
}
162+
return rhs;
163+
}
164+
// If it's already evaluated, just return the value
165+
return rhs;
166+
}
167+
// Variable wasn't found in locals -- check if it's global
168+
InternalValue result = evalArgument(fallback, normalized, context, status);
169+
if (status == U_ILLEGAL_ARGUMENT_ERROR) {
170+
status = U_ZERO_ERROR;
171+
// Unbound variable -- set a resolution error
172+
context.getErrors().setUnresolvedVariable(var, status);
173+
// Use fallback per
174+
// https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#fallback-resolution
175+
return env.createFallback(varFallback(var), status);
176+
}
177+
// Looking up the global variable succeeded; return it
178+
return env.createUnnamed(std::move(result), status);
179+
}
180+
121181
// InternalValues are passed as references into a global environment object
122182
// that is live for the duration of one formatter call.
123183
// They are mutable references so that they can be updated with a new value
@@ -141,60 +201,7 @@ static UnicodeString reserialize(const UnicodeString& s) {
141201
}
142202
// Variable reference
143203
if (rand.isVariable()) {
144-
// Check if it's local or global
145-
// Note: there is no name shadowing; this is enforced by the parser
146-
const VariableName& var = rand.asVariable();
147-
148-
// This code implements lazy call-by-need evaluation of locals.
149-
// That is, the environment binds names to a closure, not a resolved value.
150-
// The spec does not require either eager or lazy evaluation.
151-
152-
// NFC-normalize the variable name. See
153-
// https://github.com/unicode-org/message-format-wg/blob/main/spec/syntax.md#names-and-identifiers
154-
const VariableName normalized = StandardFunctions::normalizeNFC(var);
155-
156-
// Look up the variable in the environment
157-
if (env.has(normalized)) {
158-
// `var` is a local -- look it up
159-
InternalValue& rhs = env.lookup(var);
160-
// Evaluate the expression using the environment from the closure
161-
// The name of this local variable is the fallback for its RHS.
162-
UnicodeString newFallback(DOLLAR);
163-
newFallback += var;
164-
165-
if (!rhs.isEvaluated()) {
166-
Closure& c = rhs.asClosure();
167-
InternalValue& result = evalExpression(newFallback,
168-
c.getEnv(),
169-
c.getExpr(),
170-
context,
171-
status);
172-
// Overwrite the closure with the result of evaluation
173-
if (result.isFallback()) {
174-
rhs.update(result.asFallback());
175-
} else {
176-
U_ASSERT(result.isEvaluated());
177-
// Create an indirection to the result returned
178-
// by evalExpression()
179-
rhs.update(result);
180-
}
181-
return rhs;
182-
}
183-
// If it's already evaluated, just return the value
184-
return rhs;
185-
}
186-
// Variable wasn't found in locals -- check if it's global
187-
InternalValue result = evalArgument(fallback, var, context, status);
188-
if (status == U_ILLEGAL_ARGUMENT_ERROR) {
189-
status = U_ZERO_ERROR;
190-
// Unbound variable -- set a resolution error
191-
context.getErrors().setUnresolvedVariable(var, status);
192-
// Use fallback per
193-
// https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#fallback-resolution
194-
return env.createFallback(varFallback(var), status);
195-
}
196-
// Looking up the global variable succeeded; return it
197-
return env.createUnnamed(std::move(result), status);
204+
return evalVariableReference(fallback, env, rand.asVariable(), context, status);
198205
}
199206
// Literal
200207
else {
@@ -462,7 +469,7 @@ void MessageFormatter::resolveSelectors(MessageContext& context, Environment& en
462469
// 2. For each expression exp of the message's selectors
463470
for (int32_t i = 0; i < dataModel.numSelectors(); i++) {
464471
// 2i. Let rv be the resolved value of exp.
465-
InternalValue& rv = evalExpression({}, env, selectors[i], context, status);
472+
InternalValue& rv = evalVariableReference({}, env, selectors[i], context, status);
466473
if (rv.isSelectable()) {
467474
// 2ii. If selection is supported for rv:
468475
// (True if this code has been reached)
@@ -783,6 +790,9 @@ void MessageFormatter::formatSelectors(MessageContext& context,
783790
UnicodeString MessageFormatter::formatToString(const MessageArguments& arguments, UErrorCode &status) {
784791
EMPTY_ON_ERROR(status);
785792

793+
// Create a new environment that will store closures for all local variables
794+
Environment* env = Environment::create(status);
795+
786796
// Create a new context with the given arguments and the `errors` structure
787797
MessageContext context(arguments, *errors, status);
788798

icu4c/source/i18n/messageformat2_evaluation.cpp

Lines changed: 0 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -466,157 +466,6 @@ PrioritizedVariant::~PrioritizedVariant() {}
466466

467467
MessageContext::~MessageContext() {}
468468

469-
// InternalValue
470-
// -------------
471-
472-
InternalValue::InternalValue(FormattedPlaceholder&& arg) {
473-
argument = std::move(arg);
474-
selector = nullptr;
475-
formatter = nullptr;
476-
}
477-
478-
InternalValue::InternalValue(InternalValue* operand,
479-
FunctionOptions&& opts,
480-
const FunctionName& functionName,
481-
const Formatter* f,
482-
const Selector* s) {
483-
argument = operand;
484-
options = std::move(opts);
485-
name = functionName;
486-
selector = s;
487-
formatter = f;
488-
U_ASSERT(selector != nullptr || formatter != nullptr);
489-
}
490-
491-
// `this` cannot be used after calling this method
492-
void InternalValue::forceSelection(DynamicErrors& errs,
493-
const UnicodeString* keys,
494-
int32_t keysLen,
495-
UnicodeString* prefs,
496-
int32_t& prefsLen,
497-
UErrorCode& errorCode) {
498-
if (U_FAILURE(errorCode)) {
499-
return;
500-
}
501-
502-
if (!canSelect()) {
503-
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
504-
return;
505-
}
506-
// Find the argument and complete set of options by traversing `argument`
507-
FunctionOptions opts;
508-
InternalValue* p = this;
509-
FunctionName selectorName = name;
510-
while (std::holds_alternative<InternalValue*>(p->argument)) {
511-
if (p->name != selectorName) {
512-
// Can only compose calls to the same selector
513-
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
514-
return;
515-
}
516-
// First argument to mergeOptions takes precedence
517-
opts = opts.mergeOptions(std::move(p->options), errorCode);
518-
if (U_FAILURE(errorCode)) {
519-
return;
520-
}
521-
InternalValue* next = *std::get_if<InternalValue*>(&p->argument);
522-
p = next;
523-
}
524-
FormattedPlaceholder arg = std::move(*std::get_if<FormattedPlaceholder>(&p->argument));
525-
526-
selector->selectKey(std::move(arg), std::move(opts),
527-
keys, keysLen,
528-
prefs, prefsLen, errorCode);
529-
if (U_FAILURE(errorCode)) {
530-
errorCode = U_ZERO_ERROR;
531-
errs.setSelectorError(selectorName, errorCode);
532-
}
533-
}
534-
535-
FormattedPlaceholder InternalValue::forceFormatting(DynamicErrors& errs, UErrorCode& errorCode) {
536-
if (U_FAILURE(errorCode)) {
537-
return {};
538-
}
539-
540-
if (formatter == nullptr && selector == nullptr) {
541-
U_ASSERT(std::holds_alternative<FormattedPlaceholder>(argument));
542-
return std::move(*std::get_if<FormattedPlaceholder>(&argument));
543-
}
544-
if (formatter == nullptr) {
545-
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
546-
return {};
547-
}
548-
549-
FormattedPlaceholder arg;
550-
551-
if (std::holds_alternative<FormattedPlaceholder>(argument)) {
552-
arg = std::move(*std::get_if<FormattedPlaceholder>(&argument));
553-
} else {
554-
arg = (*std::get_if<InternalValue*>(&argument))->forceFormatting(errs,
555-
errorCode);
556-
}
557-
558-
if (U_FAILURE(errorCode)) {
559-
return {};
560-
}
561-
562-
if (arg.isFallback()) {
563-
return arg;
564-
}
565-
566-
// The fallback for a nullary function call is the function name
567-
UnicodeString fallback;
568-
if (arg.isNullOperand()) {
569-
fallback = u":";
570-
fallback += name;
571-
} else {
572-
fallback = arg.getFallback();
573-
}
574-
575-
// Call the function with the argument
576-
FormattedPlaceholder result = formatter->format(std::move(arg), std::move(options), errorCode);
577-
if (U_FAILURE(errorCode)) {
578-
if (errorCode == U_MF_OPERAND_MISMATCH_ERROR) {
579-
errorCode = U_ZERO_ERROR;
580-
errs.setOperandMismatchError(name, errorCode);
581-
} else {
582-
errorCode = U_ZERO_ERROR;
583-
// Convey any error generated by the formatter
584-
// as a formatting error, except for operand mismatch errors
585-
errs.setFormattingError(name, errorCode);
586-
}
587-
}
588-
// Ignore the output if any error occurred
589-
if (errs.hasFormattingError()) {
590-
return FormattedPlaceholder(fallback);
591-
}
592-
593-
return result;
594-
}
595-
596-
InternalValue& InternalValue::operator=(InternalValue&& other) noexcept {
597-
argument = std::move(other.argument);
598-
other.argument = nullptr;
599-
options = std::move(other.options);
600-
name = other.name;
601-
selector = other.selector;
602-
formatter = other.formatter;
603-
other.selector = nullptr;
604-
other.formatter = nullptr;
605-
606-
return *this;
607-
}
608-
609-
InternalValue::~InternalValue() {
610-
delete selector;
611-
selector = nullptr;
612-
delete formatter;
613-
formatter = nullptr;
614-
if (std::holds_alternative<InternalValue*>(argument)) {
615-
delete *std::get_if<InternalValue*>(&argument);
616-
argument = nullptr;
617-
}
618-
}
619-
620469
} // namespace message2
621470
U_NAMESPACE_END
622471

0 commit comments

Comments
 (0)