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

Implement Syntax 0.8, part3 #310

Merged
merged 3 commits into from
Nov 29, 2018
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
18 changes: 10 additions & 8 deletions fluent-syntax/src/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,10 @@ export class Placeable extends PatternElement {
export class Expression extends SyntaxNode {}

export class StringLiteral extends Expression {
constructor(value) {
constructor(raw, value) {
super();
this.type = "StringLiteral";
this.raw = raw;
this.value = value;
}
}
Expand Down Expand Up @@ -135,6 +136,14 @@ export class VariableReference extends Expression {
}
}

export class FunctionReference extends Expression {
constructor(id) {
super();
this.type = "FunctionReference";
this.id = id;
}
}

export class SelectExpression extends Expression {
constructor(selector, variants) {
super();
Expand Down Expand Up @@ -236,13 +245,6 @@ export class ResourceComment extends BaseComment {
}
}

export class Function extends Identifier {
constructor(name) {
super(name);
this.type = "Function";
}
}

export class Junk extends SyntaxNode {
constructor(content) {
super();
Expand Down
27 changes: 19 additions & 8 deletions fluent-syntax/src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ export default class FluentParser {

if (next === "\\" || next === "\"") {
ps.next();
return `\\${next}`;
return [`\\${next}`, next];
}

if (next === "u") {
Expand All @@ -618,7 +618,15 @@ export default class FluentParser {
sequence += ch;
}

return `\\u${sequence}`;
const codepoint = parseInt(sequence, 16);
const unescaped = codepoint <= 0xD7FF || 0xE000 <= codepoint
// It's a Unicode scalar value.
? String.fromCodePoint(codepoint)
// Escape sequences reresenting surrogate code points are well-formed
// but invalid in Fluent. Replace them with U+FFFD REPLACEMENT
// CHARACTER.
: "�";
return [`\\u${sequence}`, unescaped];
}

throw new ParseError("E0025", next);
Expand Down Expand Up @@ -718,7 +726,7 @@ export default class FluentParser {

ps.expectChar(")");

const func = new AST.Function(literal.id.name);
const func = new AST.FunctionReference(literal.id);
if (this.withSpans) {
func.addSpan(literal.span.start, literal.span.end);
}
Expand Down Expand Up @@ -805,16 +813,20 @@ export default class FluentParser {
}

getString(ps) {
let val = "";
let raw = "";
let value = "";

ps.expectChar("\"");

let ch;
while ((ch = ps.takeChar(x => x !== '"' && x !== EOL))) {
if (ch === "\\") {
val += this.getEscapeSequence(ps);
const [sequence, unescaped] = this.getEscapeSequence(ps);
raw += sequence;
value += unescaped;
} else {
val += ch;
raw += ch;
value += ch;
}
}

Expand All @@ -824,8 +836,7 @@ export default class FluentParser {

ps.expectChar("\"");

return new AST.StringLiteral(val);

return new AST.StringLiteral(raw, value);
}

getLiteral(ps) {
Expand Down
87 changes: 16 additions & 71 deletions fluent-syntax/src/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ function serializeMessage(message) {
parts.push(serializeComment(message.comment));
}

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

if (message.value) {
parts.push(serializeValue(message.value));
Expand All @@ -118,7 +118,7 @@ function serializeTerm(term) {
parts.push(serializeComment(term.comment));
}

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

for (const attribute of term.attributes) {
Expand All @@ -131,9 +131,8 @@ function serializeTerm(term) {


function serializeAttribute(attribute) {
const id = serializeIdentifier(attribute.id);
const value = indent(serializeValue(attribute.value));
return `\n .${id} =${value}`;
return `\n .${attribute.id.name} =${value}`;
}


Expand Down Expand Up @@ -184,7 +183,7 @@ function serializeVariant(variant) {
function serializeElement(element) {
switch (element.type) {
case "TextElement":
return serializeTextElement(element);
return element.value;
case "Placeable":
return serializePlaceable(element);
default:
Expand All @@ -193,11 +192,6 @@ function serializeElement(element) {
}


function serializeTextElement(text) {
return text.value;
}


function serializePlaceable(placeable) {
const expr = placeable.expression;

Expand All @@ -217,15 +211,16 @@ function serializePlaceable(placeable) {
function serializeExpression(expr) {
switch (expr.type) {
case "StringLiteral":
return serializeStringLiteral(expr);
return `"${expr.raw}"`;
case "NumberLiteral":
return serializeNumberLiteral(expr);
return expr.value;
case "MessageReference":
return serializeMessageReference(expr);
case "FunctionReference":
return expr.id.name;
case "TermReference":
return serializeTermReference(expr);
return `-${expr.id.name}`;
case "VariableReference":
return serializeVariableReference(expr);
return `$${expr.id.name}`;
case "AttributeExpression":
return serializeAttributeExpression(expr);
case "VariantExpression":
Expand All @@ -242,31 +237,6 @@ function serializeExpression(expr) {
}


function serializeStringLiteral(expr) {
return `"${expr.value}"`;
}


function serializeNumberLiteral(expr) {
return expr.value;
}


function serializeMessageReference(expr) {
return serializeIdentifier(expr.id);
}


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


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


function serializeSelectExpression(expr) {
const parts = [];
const selector = `${serializeExpression(expr.selector)} ->`;
Expand All @@ -283,8 +253,7 @@ function serializeSelectExpression(expr) {

function serializeAttributeExpression(expr) {
const ref = serializeExpression(expr.ref);
const name = serializeIdentifier(expr.name);
return `${ref}.${name}`;
return `${ref}.${expr.name.name}`;
}


Expand All @@ -296,7 +265,7 @@ function serializeVariantExpression(expr) {


function serializeCallExpression(expr) {
const fun = serializeFunction(expr.callee);
const fun = serializeExpression(expr.callee);
const positional = expr.positional.map(serializeExpression).join(", ");
const named = expr.named.map(serializeNamedArgument).join(", ");
if (expr.positional.length > 0 && expr.named.length > 0) {
Expand All @@ -307,40 +276,16 @@ function serializeCallExpression(expr) {


function serializeNamedArgument(arg) {
const name = serializeIdentifier(arg.name);
const value = serializeArgumentValue(arg.value);
return `${name}: ${value}`;
const value = serializeExpression(arg.value);
return `${arg.name.name}: ${value}`;
}


function serializeArgumentValue(argval) {
switch (argval.type) {
case "StringLiteral":
return serializeStringLiteral(argval);
case "NumberLiteral":
return serializeNumberLiteral(argval);
default:
throw new Error(`Unknown argument type: ${argval.type}`);
}
}


function serializeIdentifier(identifier) {
return identifier.name;
}

function serializeVariantKey(key) {
switch (key.type) {
case "Identifier":
return serializeIdentifier(key);
case "NumberLiteral":
return serializeNumberLiteral(key);
return key.name;
default:
throw new Error(`Unknown variant key type: ${key.type}`);
return serializeExpression(key);
}
}


function serializeFunction(fun) {
return fun.name;
}
10 changes: 7 additions & 3 deletions fluent-syntax/test/fixtures_reference/astral.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
"type": "Placeable",
"expression": {
"type": "StringLiteral",
"value": "\\uD83D\\uDE02"
"raw": "\\uD83D\\uDE02",
"value": "��"
}
}
]
Expand All @@ -89,14 +90,16 @@
"type": "Placeable",
"expression": {
"type": "StringLiteral",
"value": "\\uD83D"
"raw": "\\uD83D",
"value": "�"
}
},
{
"type": "Placeable",
"expression": {
"type": "StringLiteral",
"value": "\\uDE02"
"raw": "\\uDE02",
"value": "�"
}
}
]
Expand Down Expand Up @@ -135,6 +138,7 @@
"type": "Placeable",
"expression": {
"type": "StringLiteral",
"raw": "A face 😂 with tears of joy.",
"value": "A face 😂 with tears of joy."
}
}
Expand Down
16 changes: 16 additions & 0 deletions fluent-syntax/test/fixtures_reference/call_expressions.ftl
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## Callees

function-callee = {FUNCTION()}

# ERROR Equivalent to a MessageReference callee.
mixed-case-callee = {Function()}

# ERROR MessageReference is not a valid callee.
message-callee = {message()}
# ERROR TermReference is not a valid callee.
term-callee = {-term()}
# ERROR VariableReference is not a valid callee.
variable-callee = {$variable()}

## Arguments

positional-args = {FUN(1, "a", msg)}
named-args = {FUN(x: 1, y: "Y")}
dense-named-args = {FUN(x:1, y:"Y")}
Expand Down
Loading