You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
The text was updated successfully, but these errors were encountered:
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.
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() { ... }
vsvar foo
+foo = function foo() { ... }
at the top of the enclosing block's scopeexport class Foo { ... }
vsexport {Foo}; class Foo { ... }
and similarimport foo, * as Foo from "mod"
vsimport foo from "mod"; import * as Foo from "mod"
import foo from "mod"
vsimport {default as foo} from "mod"
export {foo, bar}
vsexport {foo}; export {bar}
export {foo}
vsexport {foo as foo}
var foo = ...
vslet foo
at the top of the enclosing function's scope +foo = ...
void expr
vs(expr, void 0)
undefined
,Infinity
,NaN
, and similar), they could be converted to literalseval
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
vsx => { return result }
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 tovar *default*; *default* = 1; export {*default* as default}
, where*default*
is a spec-internal production. You could get away with replacing this withdefault
and simplify it some -default
is still a reserved keyword.void 0
.import ... from "mod"
andexport ... from "mod"
.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 ado
expression should just emit a synthetic block.Modules would be reduced to this:
import "mod"
orexport ... from "mod"
)*
forexport * from "mod"
, or empty string if no named importFunction bodies would be reduced to this:
this
as applicableGetter/setter bodies would be reduced to this:
this
as applicableStatement lists would be reduced to this:
eval
Declared variables would be unified to either
let
orconst
, with novar
s permitted.void expr
is represented identically to(expr, undefined)
, but using theundefined
literal production rather than theundefined
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.
And to simplify the spec, statement lists should be generally unified.
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.The text was updated successfully, but these errors were encountered: