support optional chaining operator (#4899)

This commit is contained in:
Alex Lam S.L
2021-05-03 03:08:29 +01:00
committed by GitHub
parent 203f4b7ad9
commit f0de9a8b5d
12 changed files with 353 additions and 71 deletions

View File

@@ -261,9 +261,9 @@ var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_s
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
functions: "[Object/S] like `variables`, but only lists function declarations",
functions: "[Dictionary/S] like `variables`, but only lists function declarations",
parent_scope: "[AST_Scope?/S] link to the parent scope",
variables: "[Object/S] a map of name ---> SymbolDef for all variables/functions defined in this scope",
variables: "[Dictionary/S] a map of name ---> SymbolDef for all variables/functions defined in this scope",
},
clone: function(deep) {
var node = this._clone(deep);
@@ -506,7 +506,7 @@ var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", {
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
$documentation: "The toplevel scope",
$propdoc: {
globals: "[Object/S] a map of name ---> SymbolDef for all undeclared names",
globals: "[Dictionary/S] a map of name ---> SymbolDef for all undeclared names",
},
wrap: function(name) {
var body = this.body;
@@ -1293,11 +1293,13 @@ function must_be_expressions(node, prop, allow_spread, allow_hole) {
});
}
var AST_Call = DEFNODE("Call", "expression args pure", {
var AST_Call = DEFNODE("Call", "args expression optional pure", {
$documentation: "A function call expression",
$propdoc: {
args: "[AST_Node*] array of arguments",
expression: "[AST_Node] expression to invoke as function",
args: "[AST_Node*] array of arguments"
optional: "[boolean] whether the expression is optional chaining",
pure: "[string/S] marker for side-effect-free call expression",
},
walk: function(visitor) {
var node = this;
@@ -1315,7 +1317,10 @@ var AST_Call = DEFNODE("Call", "expression args pure", {
});
var AST_New = DEFNODE("New", null, {
$documentation: "An object instantiation. Derives from a function call since it has exactly the same properties"
$documentation: "An object instantiation. Derives from a function call since it has exactly the same properties",
_validate: function() {
if (this.optional) throw new Error("optional must be false");
},
}, AST_Call);
var AST_Sequence = DEFNODE("Sequence", "expressions", {
@@ -1337,11 +1342,12 @@ var AST_Sequence = DEFNODE("Sequence", "expressions", {
},
});
var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
var AST_PropAccess = DEFNODE("PropAccess", "expression optional property", {
$documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
$propdoc: {
expression: "[AST_Node] the “container” expression",
property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node"
optional: "[boolean] whether the expression is optional chaining",
property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node",
},
getProperty: function() {
var p = this.property;