Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Commit

Permalink
Fix lexer issue where select/plural/other/underscores cannot be in id…
Browse files Browse the repository at this point in the history
…entifier names. (#119190)
  • Loading branch information
thkim1011 authored Jan 25, 2023
1 parent a45727d commit 02a9c15
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 9 deletions.
25 changes: 16 additions & 9 deletions packages/flutter_tools/lib/src/localizations/message_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -158,20 +158,14 @@ RegExp normalString = RegExp(r'[^{}]+');
RegExp brace = RegExp(r'{|}');

RegExp whitespace = RegExp(r'\s+');
RegExp pluralKeyword = RegExp(r'plural');
RegExp selectKeyword = RegExp(r'select');
RegExp otherKeyword = RegExp(r'other');
RegExp numeric = RegExp(r'[0-9]+');
RegExp alphanumeric = RegExp(r'[a-zA-Z0-9]+');
RegExp alphanumeric = RegExp(r'[a-zA-Z0-9|_]+');
RegExp comma = RegExp(r',');
RegExp equalSign = RegExp(r'=');

// List of token matchers ordered by precedence
Map<ST, RegExp> matchers = <ST, RegExp>{
ST.empty: whitespace,
ST.plural: pluralKeyword,
ST.select: selectKeyword,
ST.other: otherKeyword,
ST.number: numeric,
ST.comma: comma,
ST.equalSign: equalSign,
Expand Down Expand Up @@ -303,12 +297,25 @@ class Parser {
// Do not add whitespace as a token.
startIndex = match.end;
continue;
} else if (<ST>[ST.plural, ST.select].contains(matchedType) && tokens.last.type == ST.openBrace) {
// Treat "plural" or "select" as identifier if it comes right after an open brace.
} else if (<ST>[ST.identifier].contains(matchedType) && tokens.last.type == ST.openBrace) {
// Treat any token as identifier if it comes right after an open brace, whether it's a keyword or not.
tokens.add(Node(ST.identifier, startIndex, value: match.group(0)));
startIndex = match.end;
continue;
} else {
// Handle keywords separately. Otherwise, lexer will assume parts of identifiers may be keywords.
final String tokenStr = match.group(0)!;
switch(tokenStr) {
case 'plural':
matchedType = ST.plural;
break;
case 'select':
matchedType = ST.select;
break;
case 'other':
matchedType = ST.other;
break;
}
tokens.add(Node(matchedType!, startIndex, value: match.group(0)));
startIndex = match.end;
continue;
Expand Down
16 changes: 16 additions & 0 deletions packages/flutter_tools/test/general.shard/message_parser_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,22 @@ void main() {
expect(tokens[5].type, equals(ST.identifier));
});

testWithoutContext('lexer identifier names can contain underscores', () {
final List<Node> tokens = Parser('keywords', 'app_en.arb', '{ test_placeholder } { test_select, select, singular{test} other{hmm} }').lexIntoTokens();
expect(tokens[1].value, equals('test_placeholder'));
expect(tokens[1].type, equals(ST.identifier));
expect(tokens[5].value, equals('test_select'));
expect(tokens[5].type, equals(ST.identifier));
});

testWithoutContext('lexer identifier names can contain the strings select or plural', () {
final List<Node> tokens = Parser('keywords', 'app_en.arb', '{ selectTest } { pluralTest, select, singular{test} other{hmm} }').lexIntoTokens();
expect(tokens[1].value, equals('selectTest'));
expect(tokens[1].type, equals(ST.identifier));
expect(tokens[5].value, equals('pluralTest'));
expect(tokens[5].type, equals(ST.identifier));
});

testWithoutContext('lexer: lexically correct but syntactically incorrect', () {
final List<Node> tokens = Parser(
'syntax',
Expand Down

0 comments on commit 02a9c15

Please sign in to comment.