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

Could the AST be based on a reduced subset of productions? #74

Open
dead-claudia opened this issue Feb 20, 2019 · 1 comment
Open

Could the AST be based on a reduced subset of productions? #74

dead-claudia opened this issue Feb 20, 2019 · 1 comment

Comments

@dead-claudia
Copy link

I'm reflecting back on the AST and the overzealous #37 and thinking I could probably narrow it down a bit further. JS has a lot of cases where there's multiple ways to do things and it semantically makes no difference even in the general case:

  • function foo() { ... } vs var foo + foo = function foo() { ... } at the top of the enclosing block's scope
  • export class Foo { ... } vs export {Foo}; class Foo { ... } and similar
  • import foo, * as Foo from "mod" vs import foo from "mod"; import * as Foo from "mod"
  • import foo from "mod" vs import {default as foo} from "mod"
  • export {foo, bar} vs export {foo}; export {bar}
  • export {foo} vs export {foo as foo}
  • var foo = ... vs let foo at the top of the enclosing function's scope + foo = ...
  • void expr vs (expr, void 0)
  • In strict mode contexts, when any non-configurable, non-writable global is referenced (like undefined, Infinity, NaN, and similar), they could be converted to literals
  • Labeled statements other than block statements, loops, and eval expressions can't possibly be broken or continued from. These might as well be nixed, and you could always create synthetic blocks as necessary.
  • {foo: foo} vs {foo} - Gzip can remove the redundancy if we let it.
  • {foo: 1} vs {"foo": 1}, {1: foo} vs {"1": foo}, etc.
  • x => result vs x => { return result }
  • And many others I didn't list.

There's also a few cases where the spec ends up complicating encoding if followed to the letter.

  • export default 1 in the spec is desugared to var *default*; *default* = 1; export {*default* as default}, where *default* is a spec-internal production. You could get away with replacing this with default and simplify it some - default is still a reserved keyword.
  • The list of bindings is really defined per-block, so you could define their names and just use a separate initialization operation, potentially just to a void 0.
  • All imports and exports are hoisted, and local exports already defer missing binding errors to runtime. Hoisting these in the encoding would allow engines to immediately fetch for the module's static imports before processing the rest of the module.
  • There's a lot of internal duplication between import ... from "mod" and export ... from "mod".
  • Labels cannot be empty strings. Empty strings could be super convenient to just

So I'm thinking the AST could be reduced to a smaller, significantly more easily parsed and consumed subset so engines can realize parsing gains much quicker.

  • Directives would just be strings. The node type isn't used anywhere as far as I can tell.

  • The only things that can carry labels are block statements and loops. Labeled statements that contain eval or a do expression should just emit a synthetic block.

  • Modules would be reduced to this:

    • Directives
    • Static import dependency list, a list of entries like this:
      • Source
      • Is anonymous (i.e. import "mod" or export ... from "mod")
      • Namespace import name, * for export * from "mod", or empty string if no named import
      • List of named imports, including default import
    • Export name list, a list of entries of one of these variants:
      • Export synthetic: export binding + import index + import name index
      • Export local: export binding + export name
    • Import local list, a list of import index + import name index + export name triples
    • Statement list
  • Function bodies would be reduced to this:

    • Type: method/arrow, generator, ES5-style
    • Parameter names
    • Closed-over names, including this as applicable
    • Is async
    • Statement list
  • Getter/setter bodies would be reduced to this:

    • Closed-over names, including this as applicable
    • Setter parameter
    • Getter statement list
    • Setter statement list
  • Statement lists would be reduced to this:

    • Contains eval
    • List of declared variable names
    • List of statements
  • Declared variables would be unified to either let or const, with no vars permitted.

  • void expr is represented identically to (expr, undefined), but using the undefined literal production rather than the undefined value.

  • Unlabeled break/continue statements could just have their "label" set to the impossible empty string.

  • To simplify/streamline initialization, it'd have its own node type, mirroring assignment functionally. A node can't be assigned more than once.

    • Default exports are performed by initializing the empty string variable to the value.
  • And to simplify the spec, statement lists should be generally unified.

    • Block statements can just consist of a block + label/empty string (if unlabeled) + statement list

Of course there's ways to further reduce this (reducing block labels to break depth), but most of that's beyond the scope of this bug. I'm just looking at stuff that still mirrors JS while removing the duplication.

@dead-claudia
Copy link
Author

BTW, to clarify, the intent isn't to extend, but just to simplify and compress. There's only two things I added:

  • An "initialize" assignment node to replace let/const. This specifically ends the TDZ for its assignee(s) and assigns the value to the target pattern.
  • An "undefined" literal, specifically for void expr and the new "initialize" node (let foo without initializers), but it also provides a plugin point for minifiers to produce a better engine hint.

These two added could really be considered replacements for let/const and void, respectively, and don't really add anything that wouldn't have existed before.

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

No branches or pull requests

1 participant