| | |
| | | } |
| | | if (S.token.value == "import" && !is_token(peek(), "punc", "(") && !is_token(peek(), "punc", ".")) { |
| | | next(); |
| | | var node = import_(); |
| | | var node = import_statement(); |
| | | semicolon(); |
| | | return node; |
| | | } |
| | |
| | | case "export": |
| | | if (!is_token(peek(), "punc", "(")) { |
| | | next(); |
| | | var node = export_(); |
| | | var node = export_statement(); |
| | | if (is("punc", ";")) semicolon(); |
| | | return node; |
| | | } |
| | |
| | | }); |
| | | }; |
| | | |
| | | function track_used_binding_identifiers(is_parameter, strict) { |
| | | var parameters = new Set(); |
| | | var duplicate = false; |
| | | var default_assignment = false; |
| | | var spread = false; |
| | | var strict_mode = !!strict; |
| | | var tracker = { |
| | | add_parameter: function(token) { |
| | | if (parameters.has(token.value)) { |
| | | if (duplicate === false) { |
| | | duplicate = token; |
| | | } |
| | | tracker.check_strict(); |
| | | } else { |
| | | parameters.add(token.value); |
| | | if (is_parameter) { |
| | | switch (token.value) { |
| | | case "arguments": |
| | | case "eval": |
| | | case "yield": |
| | | if (strict_mode) { |
| | | token_error(token, "Unexpected " + token.value + " identifier as parameter inside strict mode"); |
| | | } |
| | | break; |
| | | default: |
| | | if (RESERVED_WORDS.has(token.value)) { |
| | | unexpected(); |
| | | } |
| | | class UsedParametersTracker { |
| | | constructor(is_parameter, strict, duplicates_ok = false) { |
| | | this.is_parameter = is_parameter; |
| | | this.duplicates_ok = duplicates_ok; |
| | | this.parameters = new Set(); |
| | | this.duplicate = null; |
| | | this.default_assignment = false; |
| | | this.spread = false; |
| | | this.strict_mode = !!strict; |
| | | } |
| | | add_parameter(token) { |
| | | if (this.parameters.has(token.value)) { |
| | | if (this.duplicate === null) { |
| | | this.duplicate = token; |
| | | } |
| | | this.check_strict(); |
| | | } else { |
| | | this.parameters.add(token.value); |
| | | if (this.is_parameter) { |
| | | switch (token.value) { |
| | | case "arguments": |
| | | case "eval": |
| | | case "yield": |
| | | if (this.strict_mode) { |
| | | token_error(token, "Unexpected " + token.value + " identifier as parameter inside strict mode"); |
| | | } |
| | | break; |
| | | default: |
| | | if (RESERVED_WORDS.has(token.value)) { |
| | | unexpected(); |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | mark_default_assignment: function(token) { |
| | | if (default_assignment === false) { |
| | | default_assignment = token; |
| | | } |
| | | }, |
| | | mark_spread: function(token) { |
| | | if (spread === false) { |
| | | spread = token; |
| | | } |
| | | }, |
| | | mark_strict_mode: function() { |
| | | strict_mode = true; |
| | | }, |
| | | is_strict: function() { |
| | | return default_assignment !== false || spread !== false || strict_mode; |
| | | }, |
| | | check_strict: function() { |
| | | if (tracker.is_strict() && duplicate !== false) { |
| | | token_error(duplicate, "Parameter " + duplicate.value + " was used already"); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | return tracker; |
| | | } |
| | | mark_default_assignment(token) { |
| | | if (this.default_assignment === false) { |
| | | this.default_assignment = token; |
| | | } |
| | | } |
| | | mark_spread(token) { |
| | | if (this.spread === false) { |
| | | this.spread = token; |
| | | } |
| | | } |
| | | mark_strict_mode() { |
| | | this.strict_mode = true; |
| | | } |
| | | is_strict() { |
| | | return this.default_assignment !== false || this.spread !== false || this.strict_mode; |
| | | } |
| | | check_strict() { |
| | | if (this.is_strict() && this.duplicate !== null && !this.duplicates_ok) { |
| | | token_error(this.duplicate, "Parameter " + this.duplicate.value + " was used already"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | function parameters(params) { |
| | | var used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict")); |
| | | var used_parameters = new UsedParametersTracker(true, S.input.has_directive("use strict")); |
| | | |
| | | expect("("); |
| | | |
| | |
| | | var param; |
| | | var expand = false; |
| | | if (used_parameters === undefined) { |
| | | used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict")); |
| | | used_parameters = new UsedParametersTracker(true, S.input.has_directive("use strict")); |
| | | } |
| | | if (is("expand", "...")) { |
| | | expand = S.token; |
| | |
| | | var expand_token; |
| | | var first_token = S.token; |
| | | if (used_parameters === undefined) { |
| | | used_parameters = track_used_binding_identifiers(false, S.input.has_directive("use strict")); |
| | | const strict = S.input.has_directive("use strict"); |
| | | const duplicates_ok = symbol_type === AST_SymbolVar; |
| | | used_parameters = new UsedParametersTracker(false, strict, duplicates_ok); |
| | | } |
| | | symbol_type = symbol_type === undefined ? AST_SymbolFunarg : symbol_type; |
| | | if (is("punc", "[")) { |
| | |
| | | if (is("punc", "{") || is("punc", "[")) { |
| | | def = new AST_VarDef({ |
| | | start: S.token, |
| | | name: binding_element(undefined ,sym_type), |
| | | name: binding_element(undefined, sym_type), |
| | | value: is("operator", "=") ? (expect_token("operator", "="), expression(false, no_in)) : null, |
| | | end: prev() |
| | | }); |
| | |
| | | }; |
| | | |
| | | const is_not_method_start = () => |
| | | !is("punc", "(") && !is("punc", ",") && !is("punc", "}") && !is("operator", "="); |
| | | !is("punc", "(") && !is("punc", ",") && !is("punc", "}") && !is("punc", ";") && !is("operator", "="); |
| | | |
| | | var is_async = false; |
| | | var is_static = false; |
| | |
| | | } |
| | | } |
| | | |
| | | function import_() { |
| | | function maybe_import_assertion() { |
| | | if (is("name", "assert") && !has_newline_before(S.token)) { |
| | | next(); |
| | | return object_or_destructuring_(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | function import_statement() { |
| | | var start = prev(); |
| | | |
| | | var imported_name; |
| | |
| | | unexpected(); |
| | | } |
| | | next(); |
| | | |
| | | const assert_clause = maybe_import_assertion(); |
| | | |
| | | return new AST_Import({ |
| | | start: start, |
| | | imported_name: imported_name, |
| | | imported_names: imported_names, |
| | | start, |
| | | imported_name, |
| | | imported_names, |
| | | module_name: new AST_String({ |
| | | start: mod_str, |
| | | value: mod_str.value, |
| | | quote: mod_str.quote, |
| | | end: mod_str, |
| | | }), |
| | | assert_clause, |
| | | end: S.token, |
| | | }); |
| | | } |
| | |
| | | return names; |
| | | } |
| | | |
| | | function export_() { |
| | | function export_statement() { |
| | | var start = S.token; |
| | | var is_default; |
| | | var exported_names; |
| | |
| | | } |
| | | next(); |
| | | |
| | | const assert_clause = maybe_import_assertion(); |
| | | |
| | | return new AST_Export({ |
| | | start: start, |
| | | is_default: is_default, |
| | |
| | | end: mod_str, |
| | | }), |
| | | end: prev(), |
| | | assert_clause |
| | | }); |
| | | } else { |
| | | return new AST_Export({ |
| | |
| | | exported_value: exported_value, |
| | | exported_definition: exported_definition, |
| | | end: prev(), |
| | | assert_clause: null |
| | | }); |
| | | } |
| | | |