Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 0 additions & 11 deletions eslint_src.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,6 @@
],
"no-implied-eval": 2,
"no-loop-func": 2,
"no-magic-numbers": [
1,
{
"ignore": [
-1,
0,
1,
2
]
}
],
"no-useless-call": 2,
"no-useless-concat": 2,
"no-delete-var": 2,
Expand Down
1 change: 1 addition & 0 deletions fluent-syntax/.gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
test/fixtures_reference/crlf.ftl eol=crlf
test/fixtures_reference/cr.ftl eol=cr
test/fixtures_structure/crlf.ftl eol=crlf
4 changes: 3 additions & 1 deletion fluent-syntax/src/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function getErrorMessage(code, args) {
}
case "E0006": {
const [id] = args;
return `Expected term "${id}" to have a value`;
return `Expected term "-${id}" to have a value`;
}
case "E0007":
return "Keyword cannot end with a whitespace";
Expand Down Expand Up @@ -74,6 +74,8 @@ function getErrorMessage(code, args) {
const [char] = args;
return `Invalid Unicode escape sequence: \\u${char}.`;
}
case "E0027":
return "Unbalanced closing brace in TextElement.";
default:
return code;
}
Expand Down
44 changes: 19 additions & 25 deletions fluent-syntax/src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { ParseError } from "./errors";


const trailingWSRe = /[ \t\n\r]+$/;
// The Fluent Syntax spec uses /.*/ to parse comment lines. It matches all
// characters except the following ones, which are considered line endings by
// the regex engine.
const COMMENT_EOL = ["\n", "\r", "\u2028", "\u2029"];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just reviewed the opposite of this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is only for part 1 of #303. The change you're talking about, projectfluent/fluent#219, will be implemented later on. I chose this approach to minimize the amount of work related to porting reference tests to fluent.js.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other words, const COMMENT_EOL = ["\n", "\r", "\u2028", "\u2029"]; corresponds to the Fluent Syntax spec as of projectfluent/fluent@bf46e18. I'll remove it before all of Syntax 0.8 is implemented.



function withSpan(fn) {
Expand Down Expand Up @@ -39,10 +43,9 @@ export default class FluentParser {
// Poor man's decorators.
const methodNames = [
"getComment", "getMessage", "getTerm", "getAttribute", "getIdentifier",
"getTermIdentifier", "getVariant", "getNumber",
"getValue", "getPattern", "getVariantList", "getTextElement",
"getPlaceable", "getExpression", "getSelectorExpression", "getCallArg",
"getString", "getLiteral"
"getVariant", "getNumber", "getValue", "getPattern", "getVariantList",
"getTextElement", "getPlaceable", "getExpression",
"getSelectorExpression", "getCallArg", "getString", "getLiteral"
];
for (const name of methodNames) {
this[name] = withSpan(this[name]);
Expand Down Expand Up @@ -189,10 +192,10 @@ export default class FluentParser {
level = i;
}

if (ps.currentChar !== EOL) {
if (!COMMENT_EOL.includes(ps.currentChar)) {
ps.expectChar(" ");
let ch;
while ((ch = ps.takeChar(x => x !== EOL))) {
while ((ch = ps.takeChar(x => !COMMENT_EOL.includes(x)))) {
content += ch;
}
}
Expand Down Expand Up @@ -242,7 +245,8 @@ export default class FluentParser {
}

getTerm(ps) {
const id = this.getTermIdentifier(ps);
ps.expectChar("-");
const id = this.getIdentifier(ps);

ps.skipBlankInline();
ps.expectChar("=");
Expand Down Expand Up @@ -301,13 +305,6 @@ export default class FluentParser {
return new AST.Identifier(name);
}

getTermIdentifier(ps) {
ps.expectChar("-");
const id = this.getIdentifier(ps);
return new AST.Identifier(`-${id.name}`);

}

getVariantKey(ps) {
const ch = ps.currentChar;

Expand Down Expand Up @@ -455,6 +452,8 @@ export default class FluentParser {
if (ch === "{") {
const element = this.getPlaceable(ps);
elements.push(element);
} else if (ch === "}") {
throw new ParseError("E0027");
} else {
const element = this.getTextElement(ps);
elements.push(element);
Expand All @@ -478,7 +477,7 @@ export default class FluentParser {

let ch;
while ((ch = ps.currentChar)) {
if (ch === "{") {
if (ch === "{" || ch === "}") {
return new AST.TextElement(buffer);
}

Expand All @@ -494,23 +493,17 @@ export default class FluentParser {
continue;
}

if (ch === "\\") {
ps.next();
buffer += this.getEscapeSequence(ps);
continue;
}

buffer += ch;
ps.next();
}

return new AST.TextElement(buffer);
}

getEscapeSequence(ps, specials = ["{", "\\"]) {
getEscapeSequence(ps) {
const next = ps.currentChar;

if (specials.includes(next)) {
if (next === "\\" || next === "\"") {
ps.next();
return `\\${next}`;
}
Expand Down Expand Up @@ -738,7 +731,7 @@ export default class FluentParser {
let ch;
while ((ch = ps.takeChar(x => x !== '"' && x !== EOL))) {
if (ch === "\\") {
val += this.getEscapeSequence(ps, ["{", "\\", "\""]);
val += this.getEscapeSequence(ps);
} else {
val += ch;
}
Expand Down Expand Up @@ -777,7 +770,8 @@ export default class FluentParser {
}

if (ch === "-") {
const id = this.getTermIdentifier(ps);
ps.next();
const id = this.getIdentifier(ps);
return new AST.TermReference(id);
}

Expand Down
33 changes: 29 additions & 4 deletions fluent-syntax/src/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ export default class FluentSerializer {
serializeEntry(entry, state = 0) {
switch (entry.type) {
case "Message":
case "Term":
return serializeMessage(entry);
case "Term":
return serializeTerm(entry);
case "Comment":
if (state & HAS_ENTRIES) {
return `\n${serializeComment(entry, "#")}\n`;
Expand Down Expand Up @@ -95,8 +96,7 @@ function serializeMessage(message) {
parts.push(serializeComment(message.comment));
}

parts.push(serializeIdentifier(message.id));
parts.push(" =");
parts.push(`${serializeIdentifier(message.id)} =`);

if (message.value) {
parts.push(serializeValue(message.value));
Expand All @@ -111,6 +111,25 @@ function serializeMessage(message) {
}


function serializeTerm(term) {
const parts = [];

if (term.comment) {
parts.push(serializeComment(term.comment));
}

parts.push(`-${serializeIdentifier(term.id)} =`);
parts.push(serializeValue(term.value));

for (const attribute of term.attributes) {
parts.push(serializeAttribute(attribute));
}

parts.push("\n");
return parts.join("");
}


function serializeAttribute(attribute) {
const id = serializeIdentifier(attribute.id);
const value = indent(serializeValue(attribute.value));
Expand Down Expand Up @@ -202,8 +221,9 @@ function serializeExpression(expr) {
case "NumberLiteral":
return serializeNumberLiteral(expr);
case "MessageReference":
case "TermReference":
return serializeMessageReference(expr);
case "TermReference":
return serializeTermReference(expr);
case "VariableReference":
return serializeVariableReference(expr);
case "AttributeExpression":
Expand Down Expand Up @@ -237,6 +257,11 @@ function serializeMessageReference(expr) {
}


function serializeTermReference(expr) {
return `-${serializeIdentifier(expr.id)}`;
}


function serializeVariableReference(expr) {
return `$${serializeIdentifier(expr.id)}`;
}
Expand Down
22 changes: 14 additions & 8 deletions fluent-syntax/test/fixtures_behavior/escape_sequences.ftl
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# ~ERROR E0025, pos 8, args "A"
key1 = \A
## Backslash is a regular character in text elements.
key01 = \A
key02 = \u0041
key03 = \\u0041
key04 = \u000z
key05 = \{Value}

# ~ERROR E0026, pos 23, args "000z"
key2 = \u000z
key06 = {"Escaped \" quote"}
key07 = {"Escaped \\ backslash"}
key08 = {"Escaped \u0041 A"}

key3 = \{Escaped}
key4 = {"Escaped \" quote"}
key5 = \u0041
key6 = \\u0041
# ~ERROR E0025, pos 232, args "A"
key09 = {"\A"}

# ~ERROR E0026, pos 252, args "000z"
key10 = {"\u000z"}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ key2 = { { foo } }
# { foo }
# }

key4 = { { foo }
# ~ERROR E0003, pos 96, args "}"
key4 = { { foo }


# ~ERROR E0027, pos 111
key5 = { foo } }
4 changes: 2 additions & 2 deletions fluent-syntax/test/fixtures_behavior/term.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ err4 = { -brand() }
# ~ERROR E0008, pos 339

-err5 =
# ~ERROR E0006, pos 351, args "-err5"
# ~ERROR E0006, pos 351, args "err5"

-err6 =
.attr = Attribute
# ~ERROR E0006, pos 360, args "-err6"
# ~ERROR E0006, pos 360, args "err6"
20 changes: 20 additions & 0 deletions fluent-syntax/test/fixtures_reference/astral.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
face-with-tears-of-joy = 😂
tetragram-for-centre = 𝌆

surrogates-in-text = \uD83D\uDE02
surrogates-in-string = {"\uD83D\uDE02"}
surrogates-in-adjacent-strings = {"\uD83D"}{"\uDE02"}

emoji-in-text = A face 😂 with tears of joy.
emoji-in-string = {"A face 😂 with tears of joy."}

# ERROR Invalid identifier
err-😂 = Value

# ERROR Invalid expression
err-invalid-expression = { 😂 }

# ERROR Invalid variant key
err-invalid-variant-key = { $sel ->
*[😂] Value
}
Loading