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

Require = after the id (but not really) #132

Merged
merged 1 commit into from
Jan 24, 2018

Conversation

stasm
Copy link
Contributor

@stasm stasm commented Jan 23, 2018

In Fluent Syntax 0.5, the identifier must be followed by an equals sign (=)
even if the message doesn't have a value.

key =
    .attribute = Attribute Value

For some time fluent.js will allow both the new (0.5) and the old 0.4 syntax,
which means that the following will still parse but the Serializer will insert
the = after the key.

key
    .attribute = Attribute Value

This patch also fixes Bug 1406880 - Decide where multiline Pattern spans should
start. The patterns now start when their first

key =
    Value
    ^---- Pattern span start

Lastly, this patch forbids null variant values. Empty values should be written
with the {""} idiom:

key =
    {
       *[valid] {""}
        [invalid]
    }

@stasm
Copy link
Contributor Author

stasm commented Jan 23, 2018

@zbraniecki This isn't ready to land yet; I'm still working on implementing the same thing in the runtime parser. The full AST parser is good to go, however. Perhaps you'd like to take a look?

I had to rework most of getMessage because it used to always go to getPattern upon seeing a = which isn't the proper behavior for Syntax 0.5.

@stasm stasm force-pushed the require-equals branch 2 times, most recently from 9a8294d to 6dc5dc9 Compare January 24, 2018 12:36
@@ -234,7 +261,7 @@ export class FTLParserStream extends ParserStream {
return false;
}

isPeekNextNonBlankLinePattern() {
isPeekNextLinePatternStart() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

All of the isPeekNextLine* methods only consider non-blank lines so I renamed this one to match the naming of all others.

break;
}
this.next();
maybeExpectIndent() {
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 skips inline whitespace as well as new lines but the latter only if there's indentation afterwards. It throws if there isn't. (I'll put this in a comment in the code.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I ended up removing this method and replacing it with ps.isPeekPatternStart checks combined with a simple ps.skipIndent.

@@ -459,18 +460,12 @@ export default class FluentParser {
const elements = [];
ps.skipInlineWS();

// Special-case: trim leading whitespace and newlines.
if (ps.isPeekNextNonBlankLinePattern()) {
Copy link
Contributor Author

@stasm stasm Jan 24, 2018

Choose a reason for hiding this comment

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

This isn't needed any more because calls to getPattern are guarded by isPeekPatternStart, followed by skipIndent. This effectively fixes Bug 1406880 - Decide where multiline Pattern spans should start.

@@ -1,2 +1,3 @@
key = Value
.label =
//~ ERROR E0003, pos 25, args " "
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 isn't terribly useful but kind of makes sense (the parser expects an indent after the newline in line 2). Let's try to improve the error in the future.

let val;

if (ch === '=') {
if (this._source[this._index] === '=') {
this._index++;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just skip = here which means things like a b c will be parsed as a = b c. I'd prefer to fix it later on when we remove the support for Syntax 0.4.

// This is a fast-path for the most common
// case of `key = Value` where the value
// is in the same line as the key.
val = this.getPattern();
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 fast path wasn't needed because it's essentially almost the same as what getPattern does. Overall, I'm seeing a slight speed-up with my patch, around -7%.

@stasm stasm force-pushed the require-equals branch 4 times, most recently from 768991e to bd23dd8 Compare January 24, 2018 16:44
"val": "Value 1",
"attrs": {
"attr": {
"val": null
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are all syntax errors in the tooling parser. In the runtime parser I chose to parse them as null values, at least for now, to reduce the complexity of this PR and to keep the performance benefits.

@stasm stasm requested a review from zbraniecki January 24, 2018 16:48
@stasm
Copy link
Contributor Author

stasm commented Jan 24, 2018

@zbraniecki This is now ready for your review. I wrestled a bit with the runtime parser; I think I finally managed to get it acceptably right :) Let me know what you think, thanks!

@@ -294,7 +294,8 @@ function Type(env, expr) {
}
case undefined: {
// If it's a node with a value, resolve the value.
if (expr.val !== undefined) {
// eslint-disable-next-line eqeqeq
if (expr.val != null) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

why != instead of !==?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just to make it clear in case it came across wrong: I don't suppose you don't know the difference :) Just wanted to link to the Loose comparison matrix for reference of what != null evaluates to.

Copy link
Collaborator

Choose a reason for hiding this comment

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

since we usually use strict comparison, can you add a comment on why we use a different strategy here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll just use the more explicit double comparison. Can't hurt the readability. Thanks!

Copy link
Collaborator

@zbraniecki zbraniecki left a comment

Choose a reason for hiding this comment

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

lgtm!

In Fluent Syntax 0.5, the identifier must be followed by an equals sign (=)
even if the message doesn't have a value.

    key =
        .attribute = Attribute Value

For some time fluent.js will allow both the new (0.5) and the old 0.4 syntax,
which means that the following will still parse but the Serializer will insert
the = after the key.

    key
        .attribute = Attribute Value

This patch also fixes Bug 1406880 - Decide where multiline Pattern spans should
start. The patterns now start when their first

    key =
        Value
        ^---- Pattern span start

Lastly, this patch forbids null variant and attribute values in the tooling
parser. Empty values should be written with the {""} idiom:

    key =
        {
           *[valid] {""}
            [invalid]
        }

The runtime parser parses them as {val: null} for performance reasons.
@stasm stasm merged commit 4d1a41f into projectfluent:master Jan 24, 2018
@stasm stasm deleted the require-equals branch January 24, 2018 18:57
@zbraniecki zbraniecki mentioned this pull request Jan 26, 2018
4 tasks
@stasm stasm added this to fluent-syntax 0.6.0 in fluent-syntax May 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
fluent-syntax
fluent-syntax 0.6.0
Development

Successfully merging this pull request may close these issues.

None yet

2 participants