Skip to content

Commit 0640785

Browse files
committed
Define the escapes lexically
1 parent 11b5a8e commit 0640785

File tree

2 files changed

+50
-31
lines changed

2 files changed

+50
-31
lines changed

spec/fluent.ebnf

+16-13
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ InlineExpression ::= StringLiteral
5757
| inline_placeable
5858

5959
/* Literals */
60-
StringLiteral ::= "\"" quoted_text_char* "\""
60+
StringLiteral ::= "\"" quoted_char* "\""
6161
NumberLiteral ::= "-"? digit+ ("." digit+)?
6262

6363
/* Inline Expressions */
@@ -88,23 +88,26 @@ identifier ::= [a-zA-Z] [a-zA-Z0-9_-]*
8888

8989
/* Characters */
9090
/* Any Unicode character excluding C0 control characters (but including tab),
91-
* space, surrogate blocks and non-characters (U+FFFE, U+FFFF).
91+
* surrogate blocks and non-characters (U+FFFE, U+FFFF).
9292
* Cf. https://www.w3.org/TR/REC-xml/#NT-Char */
93-
regular_char ::= [\\u{9}\\u{21}-\\u{D7FF}\\u{E000}-\\u{FFFD}]
93+
regular_char ::= [\\u{9}\\u{20}-\\u{D7FF}\\u{E000}-\\u{FFFD}]
9494
| [\\u{10000}-\\u{10FFFF}]
9595
/* The opening brace in text starts a placeable. */
96-
text_char ::= (regular_char - "{")
97-
| "\u0020"
96+
special_text_char ::= "{"
97+
/* Double quote and backslash need to be escaped in string literals. */
98+
special_quoted_char ::= "\""
99+
| "\\"
100+
text_char ::= regular_char - special_text_char
98101
/* Indented text may not start with characters which mark its end. */
99102
indented_char ::= text_char - "}" - "[" - "*" - "."
100-
/* Backslash can be used to escape the double quote and the backslash itself.
101-
* The literal opening brace { is allowed because StringLiterals may not have
102-
* placeables. \uXXXX Unicode escape sequences are recognized, too. */
103-
quoted_text_char ::= (text_char - "\"" - "\\")
104-
| /\\u[0-9a-fA-F]{4}/
105-
| "{"
106-
| "\\\\"
107-
| "\\\""
103+
literal_escape ::= "\\" special_quoted_char
104+
unicode_escape ::= "\\u" /[0-9a-fA-F]{4}/
105+
/* The literal opening brace { is allowed in string literals because they may
106+
* not have placeables. */
107+
quoted_char ::= (text_char - special_quoted_char)
108+
| special_text_char
109+
| literal_escape
110+
| unicode_escape
108111
digit ::= [0-9]
109112

110113
/* Whitespace */

syntax/grammar.mjs

+34-18
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ let InlineExpression = defer(() =>
199199
let StringLiteral = defer(() =>
200200
sequence(
201201
string("\""),
202-
repeat(quoted_text_char),
202+
repeat(quoted_char),
203203
string("\""))
204204
.map(element_at(1))
205205
.map(join)
@@ -381,20 +381,27 @@ let identifier =
381381
/* Characters */
382382

383383
/* Any Unicode character excluding C0 control characters (but including tab),
384-
* space, surrogate blocks and non-characters (U+FFFE, U+FFFF).
384+
* surrogate blocks and non-characters (U+FFFE, U+FFFF).
385385
* Cf. https://www.w3.org/TR/REC-xml/#NT-Char */
386386
let regular_char =
387387
either(
388-
charset("\\u{9}\\u{21}-\\u{D7FF}\\u{E000}-\\u{FFFD}"),
388+
charset("\\u{9}\\u{20}-\\u{D7FF}\\u{E000}-\\u{FFFD}"),
389389
charset("\\u{10000}-\\u{10FFFF}"));
390390

391391
/* The opening brace in text starts a placeable. */
392-
let text_char =
392+
let special_text_char =
393+
string("{");
394+
395+
/* Double quote and backslash need to be escaped in string literals. */
396+
let special_quoted_char =
393397
either(
394-
and(
395-
not(string("{")),
396-
regular_char),
397-
string("\u0020"));
398+
string("\""),
399+
string("\\"));
400+
401+
let text_char =
402+
and(
403+
not(special_text_char),
404+
regular_char);
398405

399406
/* Indented text may not start with characters which mark its end. */
400407
let indented_char =
@@ -405,19 +412,28 @@ let indented_char =
405412
not(string("}")),
406413
text_char);
407414

408-
/* Backslash can be used to escape the double quote and the backslash itself.
409-
* The literal opening brace { is allowed because StringLiterals may not have
410-
* placeables. \uXXXX Unicode escape sequences are recognized, too. */
411-
let quoted_text_char =
415+
let literal_escape =
416+
sequence(
417+
string("\\"),
418+
special_quoted_char)
419+
.map(join);
420+
421+
let unicode_escape =
422+
sequence(
423+
string("\\u"),
424+
regex(/[0-9a-fA-F]{4}/))
425+
.map(join);
426+
427+
/* The literal opening brace { is allowed in string literals because they may
428+
* not have placeables. */
429+
let quoted_char =
412430
either(
413431
and(
414-
not(string("\\")),
415-
not(string("\"")),
432+
not(special_quoted_char),
416433
text_char),
417-
regex(/\\u[0-9a-fA-F]{4}/),
418-
string("{"),
419-
string("\\\\"),
420-
string("\\\""));
434+
special_text_char,
435+
literal_escape,
436+
unicode_escape);
421437

422438
let digit = charset("0-9");
423439

0 commit comments

Comments
 (0)