struct DiffPiece : Piece {
DiffPiece() : Piece(DiffPieceClass) {}
- Piece *Options[2] = {};
+ Piece *Parts[4] = {};
int Indexes[2] = {};
static bool classof(const Piece *P) {
}
DiagText(DiagnosticTextBuilder &Builder, StringRef Text)
- : Builder(Builder), Root(parseDiagText(Text)) {}
-
- Piece *parseDiagText(StringRef &Text, bool Nested = false);
+ : Builder(Builder), Root(parseDiagText(Text, StopAt::End)) {}
+
+ enum class StopAt {
+ // Parse until the end of the string.
+ End,
+ // Additionally stop if we hit a non-nested '|' or '}'.
+ PipeOrCloseBrace,
+ // Additionally stop if we hit a non-nested '$'.
+ Dollar,
+ };
+
+ Piece *parseDiagText(StringRef &Text, StopAt Stop);
int parseModifier(StringRef &) const;
public:
void VisitPlural(PluralPiece *P) { VisitSelect(P); }
- void VisitDiff(DiffPiece *P) { Visit(P->Options[1]); }
+ void VisitDiff(DiffPiece *P) {
+ // Render %diff{a $ b $ c|d}e,f as %select{a %e b %f c|d}.
+ PlaceholderPiece E(MT_Placeholder, P->Indexes[0]);
+ PlaceholderPiece F(MT_Placeholder, P->Indexes[1]);
+
+ MultiPiece FirstOption;
+ FirstOption.Pieces.push_back(P->Parts[0]);
+ FirstOption.Pieces.push_back(&E);
+ FirstOption.Pieces.push_back(P->Parts[1]);
+ FirstOption.Pieces.push_back(&F);
+ FirstOption.Pieces.push_back(P->Parts[2]);
+
+ SelectPiece Select(MT_Diff);
+ Select.Options.push_back(&FirstOption);
+ Select.Options.push_back(P->Parts[3]);
+
+ VisitSelect(&Select);
+ }
std::vector<std::string> &RST;
};
void VisitDiff(DiffPiece *P) {
Result += "%diff{";
- Visit(P->Options[0]);
+ Visit(P->Parts[0]);
+ Result += "$";
+ Visit(P->Parts[1]);
+ Result += "$";
+ Visit(P->Parts[2]);
Result += "|";
- Visit(P->Options[1]);
+ Visit(P->Parts[3]);
Result += "}";
addInt(mapIndex(P->Indexes[0]));
Result += ",";
}
Piece *DiagnosticTextBuilder::DiagText::parseDiagText(StringRef &Text,
- bool Nested) {
+ StopAt Stop) {
std::vector<Piece *> Parsed;
+ constexpr llvm::StringLiteral StopSets[] = {"%", "%|}", "%|}$"};
+ llvm::StringRef StopSet = StopSets[static_cast<int>(Stop)];
+
while (!Text.empty()) {
size_t End = (size_t)-2;
do
- End = Nested ? Text.find_first_of("%|}", End + 2)
- : Text.find_first_of('%', End + 2);
- while (End < Text.size() - 1 && Text[End] == '%' &&
- (Text[End + 1] == '%' || Text[End + 1] == '|'));
+ End = Text.find_first_of(StopSet, End + 2);
+ while (
+ End < Text.size() - 1 && Text[End] == '%' &&
+ (Text[End + 1] == '%' || Text[End + 1] == '|' || Text[End + 1] == '$'));
if (End) {
Parsed.push_back(New<TextPiece>(Text.slice(0, End), "diagtext"));
break;
}
- if (Text[0] == '|' || Text[0] == '}')
+ if (Text[0] == '|' || Text[0] == '}' || Text[0] == '$')
break;
// Drop the '%'.
.Case("", MT_Placeholder)
.Default(MT_Unknown);
+ auto ExpectAndConsume = [&](StringRef Prefix) {
+ if (!Text.consume_front(Prefix))
+ Builder.PrintFatalError("expected '" + Prefix + "' while parsing %" +
+ Modifier);
+ };
+
switch (ModType) {
case MT_Unknown:
Builder.PrintFatalError("Unknown modifier type: " + Modifier);
SelectPiece *Select = New<SelectPiece>(MT_Select);
do {
Text = Text.drop_front(); // '{' or '|'
- Select->Options.push_back(parseDiagText(Text, true));
+ Select->Options.push_back(
+ parseDiagText(Text, StopAt::PipeOrCloseBrace));
assert(!Text.empty() && "malformed %select");
} while (Text.front() == '|');
- // Drop the trailing '}'.
- Text = Text.drop_front(1);
+ ExpectAndConsume("}");
Select->Index = parseModifier(Text);
Parsed.push_back(Select);
continue;
Plural->OptionPrefixes.push_back(
New<TextPiece>(Text.slice(0, End), "diagtext"));
Text = Text.slice(End, StringRef::npos);
- Plural->Options.push_back(parseDiagText(Text, true));
- assert(!Text.empty() && "malformed %select");
+ Plural->Options.push_back(
+ parseDiagText(Text, StopAt::PipeOrCloseBrace));
+ assert(!Text.empty() && "malformed %plural");
} while (Text.front() == '|');
- // Drop the trailing '}'.
- Text = Text.drop_front(1);
+ ExpectAndConsume("}");
Plural->Index = parseModifier(Text);
Parsed.push_back(Plural);
continue;
}
case MT_Sub: {
SubstitutionPiece *Sub = New<SubstitutionPiece>();
- Text = Text.drop_front(); // '{'
+ ExpectAndConsume("{");
size_t NameSize = Text.find_first_of('}');
assert(NameSize != size_t(-1) && "failed to find the end of the name");
assert(NameSize != 0 && "empty name?");
Sub->Name = Text.substr(0, NameSize).str();
Text = Text.drop_front(NameSize);
- Text = Text.drop_front(); // '}'
+ ExpectAndConsume("}");
if (!Text.empty()) {
while (true) {
if (!isdigit(Text[0]))
}
case MT_Diff: {
DiffPiece *Diff = New<DiffPiece>();
- Text = Text.drop_front(); // '{'
- Diff->Options[0] = parseDiagText(Text, true);
- Text = Text.drop_front(); // '|'
- Diff->Options[1] = parseDiagText(Text, true);
-
- Text = Text.drop_front(); // '}'
+ ExpectAndConsume("{");
+ Diff->Parts[0] = parseDiagText(Text, StopAt::Dollar);
+ ExpectAndConsume("$");
+ Diff->Parts[1] = parseDiagText(Text, StopAt::Dollar);
+ ExpectAndConsume("$");
+ Diff->Parts[2] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
+ ExpectAndConsume("|");
+ Diff->Parts[3] = parseDiagText(Text, StopAt::PipeOrCloseBrace);
+ ExpectAndConsume("}");
Diff->Indexes[0] = parseModifier(Text);
- Text = Text.drop_front(); // ','
+ ExpectAndConsume(",");
Diff->Indexes[1] = parseModifier(Text);
Parsed.push_back(Diff);
continue;