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

Store attribute access and call args on reference expressions #221

Merged
merged 2 commits into from
Jan 10, 2019

Conversation

stasm
Copy link
Contributor

@stasm stasm commented Nov 29, 2018

Right now, we store complex member expressions as nested trees of AST nodes. As an example, a parameterized term attribute of the form -term.attr(arg: "value") parses as:

CallExpression {
    callee: AttributeExpression {
        ref: TermReference {
            id: Identifier {name: "term"}
        },
        name: Identifier {name: "attr"}
    },
    positional: [],
    named: [NamedArgument {...}]
}

This is a well established pattern in general-purpose languages. It is capable of handling deeply nested hierarchies of expressions. In Fluent, however, we only ever go so deep. All the possible nestings are known up-front and are defined by the grammar.

Furthermore, the above AST structure makes tooling harder. Checking for a TermReference means checking for four different AST structures (corresponding to -term, -term(), -term.attr, and -term.attr()).

In this PR, I've tried a different approach: the attribute access and the call arguments are stored on the reference node itself:

TermReference {
    id: Identifier {name: "term"},
    attribute: Identifier {name: "attr"}
    args: CallArguments {
        positional: [],
        named: [NamedArgument {...}]
    }
}

I implemented this approach for MessageReference, TermReference, VariableReference and FunctionReference.

@stasm stasm requested a review from Pike November 29, 2018 15:04
super();
this.type = "CallArguments";
this.positional = positional;
this.named = named;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

CallArguments is a separate SyntaxNode for two reasons:

  1. The tooling parser can store the span of (...) on it.
  2. In TermReference, the args field is nullable. This allows us to distinguish between -term and -term(), which are functionally the same, but require different serialization.

spec/fluent.ebnf Show resolved Hide resolved
super();
this.type = "TermReference";
this.id = id;
this.attribute = attribute;
this.args = 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.

Naming things... attribute or attr to make it consistent with id and args?

Copy link
Contributor

Choose a reason for hiding this comment

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

Full name sounds about right to me. attr is less obvious about the fact that this is exactly one or none.

Copy link
Contributor

@Pike Pike left a comment

Choose a reason for hiding this comment

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

I like this. In particular the ease in abstract.mjs is nice, I've struggled with reviewing the Term.attr the first time around.

There's a nit about left-overs in abstract.mjs for AttributeExpression, make that 💥 ?

Independently of the r=me, we should talk about when to do this.

super();
this.type = "TermReference";
this.id = id;
this.attribute = attribute;
this.args = args;
Copy link
Contributor

Choose a reason for hiding this comment

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

Full name sounds about right to me. attr is less obvious about the fact that this is exactly one or none.

spec/fluent.ebnf Show resolved Hide resolved
@stasm
Copy link
Contributor Author

stasm commented Nov 30, 2018

There's a nit about left-overs in abstract.mjs for AttributeExpression, make that 💥 ?

Ah yes, thanks, I forgot about that part.

Independently of the r=me, we should talk about when to do this.

I think we should do this in 0.9, perhaps after #214 lands, so that we don't have to deal with VariantExpression any longer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants