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

Treat backslash as normal char in TextElements #181

Merged
merged 5 commits into from
Oct 30, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
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
10 changes: 10 additions & 0 deletions spec/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@
consistent with how `Identifiers` of variables don't include the `$`
sigil either.

- Treat backslash (`\`) as a regular character in `TextElements`. (#123)

Backslash does no longer have special escaping powers when used in
`TextElements`. It's still recognized as special in `StringLiterals`,
however. `StringLiterals` can be used to insert all special-purpose
characters in text. For instance, `{"{"}` will insert the literal opening
curly brace (`{`), `{"\u00A0"}` will insert the non-breaking space, and
`{" "}` can be used to make a translation start or end with whitespace,
which would otherwise by trimmed by `Pattern.`

## 0.7.0 (October 15, 2018)

- Relax the indentation requirement. (#87)
Expand Down
34 changes: 19 additions & 15 deletions spec/fluent.ebnf
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ InlineExpression ::= StringLiteral
| inline_placeable

/* Literals */
StringLiteral ::= quote quoted_text_char* quote
StringLiteral ::= "\"" quoted_char* "\""
NumberLiteral ::= "-"? digit+ ("." digit+)?

/* Inline Expressions */
Expand All @@ -84,22 +84,26 @@ Identifier ::= [a-zA-Z] [a-zA-Z0-9_-]*
Function ::= [A-Z] [A-Z_?-]*

/* Characters */
backslash ::= "\\"
quote ::= "\""
/* Any Unicode character from BMP excluding C0 control characters, space,
/* Any Unicode character excluding C0 control characters (but including tab),
* surrogate blocks and non-characters (U+FFFE, U+FFFF).
* Cf. https://www.w3.org/TR/REC-xml/#NT-Char
*/
regular_char ::= [\\u{21}-\\u{D7FF}\\u{E000}-\\u{FFFD}\\u{10000}-\\u{10FFFF}]
text_char ::= blank_inline
| "\u0009"
| /\\u[0-9a-fA-F]{4}/
| (backslash backslash)
| (backslash "{")
| (regular_char - "{" - backslash)
* Cf. https://www.w3.org/TR/REC-xml/#NT-Char */
any_char ::= [\\u{9}\\u{20}-\\u{D7FF}\\u{E000}-\\u{FFFD}]
| [\\u{10000}-\\u{10FFFF}]
/* The opening brace in text starts a placeable. */
special_text_char ::= "{"
/* Double quote and backslash need to be escaped in string literals. */
special_quoted_char ::= "\""
| "\\"
text_char ::= any_char - special_text_char
/* Indented text may not start with characters which mark its end. */
indented_char ::= text_char - "}" - "[" - "*" - "."
quoted_text_char ::= (text_char - quote)
| (backslash quote)
special_escape ::= "\\" special_quoted_char
unicode_escape ::= "\\u" /[0-9a-fA-F]{4}/
/* The literal opening brace { is allowed in string literals because they may
* not have placeables. */
quoted_char ::= (any_char - special_quoted_char)
| special_escape
| unicode_escape
digit ::= [0-9]

/* Whitespace */
Expand Down
77 changes: 44 additions & 33 deletions syntax/grammar.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,9 @@ let InlineExpression = defer(() =>
/* Literals */
let StringLiteral = defer(() =>
sequence(
quote,
repeat(quoted_text_char),
quote)
string("\""),
repeat(quoted_char),
string("\""))
.map(element_at(1))
.map(join)
.chain(into(FTL.StringLiteral)));
Expand Down Expand Up @@ -373,48 +373,59 @@ let Function =
/* ---------- */
/* Characters */

let backslash = string("\\");
let quote = string("\"");

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

let text_char = defer(() =>
/* The opening brace in text starts a placeable. */
let special_text_char =
string("{");

/* Double quote and backslash need to be escaped in string literals. */
let special_quoted_char =
either(
blank_inline,
string("\u0009"),
regex(/\\u[0-9a-fA-F]{4}/),
sequence(
backslash,
backslash).map(join),
sequence(
backslash,
string("{")).map(join),
and(
not(backslash),
not(string("{")),
regular_char)));
string("\""),
string("\\"));

let text_char =
and(
not(special_text_char),
any_char);

let indented_char = defer(() =>
/* Indented text may not start with characters which mark its end. */
let indented_char =
and(
not(string(".")),
not(string("*")),
not(string("[")),
not(string("}")),
text_char));
text_char);
stasm marked this conversation as resolved.
Show resolved Hide resolved

let special_escape =
sequence(
string("\\"),
special_quoted_char)
.map(join);

let quoted_text_char =
let unicode_escape =
sequence(
string("\\u"),
regex(/[0-9a-fA-F]{4}/))
.map(join);

/* The literal opening brace { is allowed in string literals because they may
* not have placeables. */
let quoted_char =
either(
and(
not(quote),
text_char),
sequence(
backslash,
quote).map(join));
not(special_quoted_char),
any_char),
special_escape,
unicode_escape);

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

Expand Down
23 changes: 18 additions & 5 deletions test/fixtures/escaped_characters.ftl
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
backslash = Value with \\ (an escaped backslash)
closing-brace = Value with \{ (a closing brace)
unicode-escape = \u0041
escaped-unicode = \\u0041
## Literal text
text-backslash-one = Value with \ a backslash
text-backslash-two = Value with \\ two backslashes
text-backslash-brace = Value with \{placeable}
text-backslash-u = \u0041
text-backslash-backslash-u = \\u0041

## String Expressions
## String literals
quote-in-string = {"\""}
backslash-in-string = {"\\"}
# ERROR Mismatched quote
mismatched-quote = {"\\""}
# ERROR Unknown escape
unknown-escape = {"\x"}

## Unicode escapes
string-unicode-sequence = {"\u0041"}
string-escaped-unicode = {"\\u0041"}

## Literal braces
brace-open = An opening {"{"} brace.
brace-close = A closing } brace.
Loading