⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 270923 in webkit


Ignore:
Timestamp:
Dec 16, 2020, 6:46:48 PM (6 years ago)
Author:
ysuzuki@apple.com
Message:

[JSC] Accept arbitrary module namespace identifier names
​https://bugs.webkit.org/show_bug.cgi?id=217576
JSTests:

<rdar://problem/70416104>

Reviewed by Darin Adler.

  • modules/arbitrary-module-names.js: Added.
  • modules/arbitrary-module-names/export.js: Added.
  • modules/arbitrary-module-names/export2.js: Added.
  • stress/modules-syntax-error.js:
  • test262/config.yaml:

Source/JavaScriptCore:

<rdar://problem/70416104>

Reviewed by Darin Adler.

This patch implements arbitrary module namespace identifier names[1].
After this, we can export and import arbitrary module export names which are not valid as a variable identifier.
For example,

import { "delete" as deletedValue } from "./ok.js";

...

export {

deletedValue as "delete"

};

[1]: ​https://github.com/tc39/ecma262/pull/2154

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseImportClauseItem):
(JSC::Parser<LexerType>::parseImportDeclaration):
(JSC::Parser<LexerType>::parseExportSpecifier):
(JSC::Parser<LexerType>::parseExportDeclaration):

  • parser/Parser.h:

Source/WebCore:

Reviewed by Darin Adler.

  • bindings/js/JSDOMConvertStrings.cpp:

(WebCore::hasUnpairedSurrogate): Deleted.

Source/WTF:

Reviewed by Darin Adler.

  • wtf/text/StringView.h:

(WTF::hasUnpairedSurrogate):

Location:
trunk
Files:
4 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r270874 r270923  
     12020-12-15  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Accept arbitrary module namespace identifier names
     4        https://bugs.webkit.org/show_bug.cgi?id=217576
     5        <rdar://problem/70416104>
     6
     7        Reviewed by Darin Adler.
     8
     9        * modules/arbitrary-module-names.js: Added.
     10        * modules/arbitrary-module-names/export.js: Added.
     11        * modules/arbitrary-module-names/export2.js: Added.
     12        * stress/modules-syntax-error.js:
     13        * test262/config.yaml:
     14
    1152020-12-15  Alexey Shvayka  <shvaikalesh@gmail.com>
    216
  • trunk/JSTests/stress/modules-syntax-error.js

    r267186 r270923  
    2222checkModuleSyntaxError(String.raw`
    2323import {,} from "Cocoa"
    24 `, `SyntaxError: Unexpected token ','. Expected an imported name for the import declaration.:2`);
     24`, `SyntaxError: Unexpected token ','. Expected an imported name or a module export name string for the import declaration.:2`);
    2525
    2626checkModuleSyntaxError(String.raw`
    … …  
    159159checkModuleSyntaxError(String.raw`
    160160import a, { [assign] as c } from "Cocoa"
    161 `, `SyntaxError: Unexpected token '['. Expected an imported name for the import declaration.:2`);
     161`, `SyntaxError: Unexpected token '['. Expected an imported name or a module export name string for the import declaration.:2`);
    162162
    163163checkModuleSyntaxError(String.raw`
    … …  
    167167checkModuleSyntaxError(String.raw`
    168168import d, { {obj} } from "Cappuccino"
    169 `, `SyntaxError: Unexpected token '{'. Expected an imported name for the import declaration.:2`);
     169`, `SyntaxError: Unexpected token '{'. Expected an imported name or a module export name string for the import declaration.:2`);
    170170
    171171checkModuleSyntaxError(String.raw`
    … …  
    185185checkModuleSyntaxError(String.raw`
    186186export { , } from "Cocoa"
    187 `, `SyntaxError: Unexpected token ','. Expected a variable name for the export declaration.:2`);
     187`, `SyntaxError: Unexpected token ','. Expected a variable name or a module export name string for the export declaration.:2`);
    188188
    189189checkModuleSyntaxError(String.raw`
    190190export { a, , } from "Cocoa"
    191 `, `SyntaxError: Unexpected token ','. Expected a variable name for the export declaration.:2`);
     191`, `SyntaxError: Unexpected token ','. Expected a variable name or a module export name string for the export declaration.:2`);
    192192
    193193checkModuleSyntaxError(String.raw`
    … …  
    201201checkModuleSyntaxError(String.raw`
    202202export { * as b } from "Cocoa"
    203 `, `SyntaxError: Unexpected token '*'. Expected a variable name for the export declaration.:2`);
     203`, `SyntaxError: Unexpected token '*'. Expected a variable name or a module export name string for the export declaration.:2`);
    204204
    205205checkModuleSyntaxError(String.raw`
    … …  
    209209checkModuleSyntaxError(String.raw`
    210210export * as 42 from "Cocoa"
    211 `, `SyntaxError: Unexpected number '42'. Expected an exported name for the export declaration.:2`);
     211`, `SyntaxError: Unexpected number '42'. Expected an exported name or a module export name string for the export declaration.:2`);
    212212
    213213checkModuleSyntaxError(String.raw`
    … …  
    317317`, `SyntaxError: Unexpected keyword 'export':3`);
    318318
     319checkModuleSyntaxError(String.raw`
     320import { "\ud800" as test } from "./ok.js"
     321`, String.raw`SyntaxError: Unexpected string literal "\ud800". Expected a well-formed-unicode string for the module export name.:2`);
     322
     323checkModuleSyntaxError(String.raw`
     324import { "test" } from "./ok.js"
     325`, String.raw`SyntaxError: Unexpected token '}'. Expected 'as' after the module export name string.:2`);
     326
     327checkModuleSyntaxError(String.raw`
     328export { "test" }
     329`, String.raw`SyntaxError: Cannot use module export names if they reference variable names in the current module.:3`);
     330
     331checkModuleSyntaxError(String.raw`
     332export { "test" as "ok" }
     333`, String.raw`SyntaxError: Cannot use module export names if they reference variable names in the current module.:3`);
     334
     335checkModuleSyntaxError(String.raw`
     336export { "\ud800" } from "./ok.js"
     337`, String.raw`SyntaxError: Unexpected string literal "\ud800". Expected a well-formed-unicode string for the module export name.:2`);
     338
     339checkModuleSyntaxError(String.raw`
     340export { ok as "\ud800" } from "./ok.js"
     341`, String.raw`SyntaxError: Unexpected string literal "\ud800". Expected a well-formed-unicode string for the module export name.:2`);
     342
     343checkModuleSyntaxError(String.raw`
     344export { "hello" as "\ud800" } from "./ok.js"
     345`, String.raw`SyntaxError: Unexpected string literal "\ud800". Expected a well-formed-unicode string for the module export name.:2`);
     346
     347checkModuleSyntaxError(String.raw`
     348export { "\ud800" as "hello" } from "./ok.js"
     349`, String.raw`SyntaxError: Unexpected string literal "\ud800". Expected a well-formed-unicode string for the module export name.:2`);
     350
     351checkModuleSyntaxError(String.raw`
     352export * as "\ud800" from "./ok.js"
     353`, String.raw`SyntaxError: Unexpected string literal "\ud800". Expected a well-formed-unicode string for the module export name.:2`);
     354
    319355// --------------- other ---------------------
    320356
  • trunk/JSTests/test262/config.yaml

    r270043 r270923  
    2020    - legacy-regexp
    2121
    22     - arbitrary-module-namespace-names
    2322    - class-methods-private
    2423    - class-static-methods-private
  • trunk/Source/JavaScriptCore/ChangeLog

    r270888 r270923  
     12020-12-15  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Accept arbitrary module namespace identifier names
     4        https://bugs.webkit.org/show_bug.cgi?id=217576
     5        <rdar://problem/70416104>
     6
     7        Reviewed by Darin Adler.
     8
     9        This patch implements arbitrary module namespace identifier names[1].
     10        After this, we can export and import arbitrary module export names which are not valid as a variable identifier.
     11        For example,
     12
     13            import { "delete" as deletedValue } from "./ok.js";
     14
     15            ...
     16
     17            export {
     18                deletedValue as "delete"
     19            };
     20
     21        [1]: https://github.com/tc39/ecma262/pull/2154
     22
     23        * parser/Parser.cpp:
     24        (JSC::Parser<LexerType>::parseImportClauseItem):
     25        (JSC::Parser<LexerType>::parseImportDeclaration):
     26        (JSC::Parser<LexerType>::parseExportSpecifier):
     27        (JSC::Parser<LexerType>::parseExportDeclaration):
     28        * parser/Parser.h:
     29
    1302020-12-16  Yusuke Suzuki  <ysuzuki@apple.com>
    231
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r270487 r270923  
    34153415        // ImportedBinding
    34163416        // IdentifierName as ImportedBinding
     3417        // ModuleExportName as ImportedBinding
    34173418        // e.g.
    34183419        //     A
    34193420        //     A as B
    3420         ASSERT(matchIdentifierOrKeyword());
    3421         localNameToken = m_token;
     3421        ASSERT(matchIdentifierOrKeyword() || match(STRING));
     3422        bool isModuleExportName = match(STRING);
    34223423        localName = m_token.m_data.ident;
    34233424        importedName = localName;
    3424         next();
    3425 
    3426         if (matchContextualKeyword(m_vm.propertyNames->as)) {
     3425        localNameToken = m_token;
     3426        if (isModuleExportName)
     3427            failIfTrue(hasUnpairedSurrogate(localName->string()), "Expected a well-formed-unicode string for the module export name");
     3428        next();
     3429
     3430        bool useAs = matchContextualKeyword(m_vm.propertyNames->as);
     3431        if (isModuleExportName)
     3432            failIfFalse(useAs, "Expected 'as' after the module export name string");
     3433        if (useAs) {
    34273434            next();
    34283435            failIfFalse(matchSpecIdentifier(), "Expected a variable name for the import declaration");
    … …  
    35033510
    35043511            while (!match(CLOSEBRACE)) {
    3505                 failIfFalse(matchIdentifierOrKeyword(), "Expected an imported name for the import declaration");
     3512                failIfFalse(matchIdentifierOrKeyword() || match(STRING), "Expected an imported name or a module export name string for the import declaration");
    35063513                auto specifier = parseImportClauseItem(context, ImportSpecifierType::NamedImport);
    35073514                failIfFalse(specifier, "Cannot parse the named import");
    … …  
    35293536
    35303537template <typename LexerType>
    3531 template <class TreeBuilder> typename TreeBuilder::ExportSpecifier Parser<LexerType>::parseExportSpecifier(TreeBuilder& context, Vector<std::pair<const Identifier*, const Identifier*>>& maybeExportedLocalNames, bool& hasKeywordForLocalBindings)
     3538template <class TreeBuilder> typename TreeBuilder::ExportSpecifier Parser<LexerType>::parseExportSpecifier(TreeBuilder& context, Vector<std::pair<const Identifier*, const Identifier*>>& maybeExportedLocalNames, bool& hasKeywordForLocalBindings, bool& hasReferencedModuleExportNames)
    35323539{
    35333540    // ExportSpecifier :
    35343541    // IdentifierName
    35353542    // IdentifierName as IdentifierName
     3543    // IdentifierName as ModuleExportName
     3544    // ModuleExportName
     3545    // ModuleExportName as IdentifierName
     3546    // ModuleExportName as ModuleExportName
    35363547    // http://www.ecma-international.org/ecma-262/6.0/#sec-exports
    3537     ASSERT(matchIdentifierOrKeyword());
     3548    ASSERT(matchIdentifierOrKeyword() || match(STRING));
    35383549    JSTokenLocation specifierLocation(tokenLocation());
    3539     if (m_token.m_type & KeywordTokenFlag)
    3540         hasKeywordForLocalBindings = true;
    35413550    const Identifier* localName = m_token.m_data.ident;
    35423551    const Identifier* exportedName = localName;
     3552    if (match(STRING)) {
     3553        hasReferencedModuleExportNames = true;
     3554        failIfTrue(hasUnpairedSurrogate(exportedName->string()), "Expected a well-formed-unicode string for the module export name");
     3555    } else {
     3556        if (m_token.m_type & KeywordTokenFlag)
     3557            hasKeywordForLocalBindings = true;
     3558    }
    35433559    next();
    35443560
    35453561    if (matchContextualKeyword(m_vm.propertyNames->as)) {
    35463562        next();
    3547         failIfFalse(matchIdentifierOrKeyword(), "Expected an exported name for the export declaration");
     3563        failIfFalse(matchIdentifierOrKeyword() || match(STRING), "Expected an exported name or a module export name string for the export declaration");
    35483564        exportedName = m_token.m_data.ident;
     3565        if (match(STRING))
     3566            failIfTrue(hasUnpairedSurrogate(exportedName->string()), "Expected a well-formed-unicode string for the module export name");
    35493567        next();
    35503568    }
    … …  
    35673585        // export * FromClause ;
    35683586        // export * as IdentifierName FromClause ;
     3587        // export * as ModuleExportName FromClause ;
    35693588        next();
    35703589
    … …  
    35743593            next();
    35753594            specifierLocation = JSTokenLocation(tokenLocation());
    3576             failIfFalse(matchIdentifierOrKeyword(), "Expected an exported name for the export declaration");
     3595            failIfFalse(matchIdentifierOrKeyword() || match(STRING), "Expected an exported name or a module export name string for the export declaration");
    35773596            exportedName = m_token.m_data.ident;
     3597            if (match(STRING))
     3598                failIfTrue(hasUnpairedSurrogate(exportedName->string()), "Expected a well-formed-unicode string for the module export name");
    35783599            next();
    35793600        }
    … …  
    37043725
    37053726        bool hasKeywordForLocalBindings = false;
     3727        bool hasReferencedModuleExportNames = false;
    37063728        while (!match(CLOSEBRACE)) {
    3707             failIfFalse(matchIdentifierOrKeyword(), "Expected a variable name for the export declaration");
    3708             auto specifier = parseExportSpecifier(context, maybeExportedLocalNames, hasKeywordForLocalBindings);
     3729            failIfFalse(matchIdentifierOrKeyword() || match(STRING), "Expected a variable name or a module export name string for the export declaration");
     3730            auto specifier = parseExportSpecifier(context, maybeExportedLocalNames, hasKeywordForLocalBindings, hasReferencedModuleExportNames);
    37093731            failIfFalse(specifier, "Cannot parse the named export");
    37103732            context.appendExportSpecifier(specifierList, specifier);
    … …  
    37193741            moduleName = parseModuleName(context);
    37203742            failIfFalse(moduleName, "Cannot parse the 'from' clause");
    3721         }
     3743        } else
     3744            semanticFailIfTrue(hasReferencedModuleExportNames, "Cannot use module export names if they reference variable names in the current module");
    37223745        failIfFalse(autoSemiColon(), "Expected a ';' following a targeted export declaration");
    37233746
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r270481 r270923  
    17851785    template <class TreeBuilder> typename TreeBuilder::ModuleName parseModuleName(TreeBuilder&);
    17861786    template <class TreeBuilder> TreeStatement parseImportDeclaration(TreeBuilder&);
    1787     template <class TreeBuilder> typename TreeBuilder::ExportSpecifier parseExportSpecifier(TreeBuilder& context, Vector<std::pair<const Identifier*, const Identifier*>>& maybeExportedLocalNames, bool& hasKeywordForLocalBindings);
     1787    template <class TreeBuilder> typename TreeBuilder::ExportSpecifier parseExportSpecifier(TreeBuilder& context, Vector<std::pair<const Identifier*, const Identifier*>>& maybeExportedLocalNames, bool& hasKeywordForLocalBindings, bool& hasReferencedModuleExportNames);
    17881788    template <class TreeBuilder> TreeStatement parseExportDeclaration(TreeBuilder&);
    17891789
  • trunk/Source/WTF/ChangeLog

    r270872 r270923  
     12020-12-15  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Accept arbitrary module namespace identifier names
     4        https://bugs.webkit.org/show_bug.cgi?id=217576
     5
     6        Reviewed by Darin Adler.
     7
     8        * wtf/text/StringView.h:
     9        (WTF::hasUnpairedSurrogate):
     10
    1112020-12-15  Jer Noble  <jer.noble@apple.com>
    212
  • trunk/Source/WTF/wtf/text/StringView.h

    r266973 r270923  
    10881088WTF_EXPORT_PRIVATE int codePointCompare(StringView, StringView);
    10891089
     1090inline bool hasUnpairedSurrogate(StringView string)
     1091{
     1092    // Fast path for 8-bit strings; they can't have any surrogates.
     1093    if (string.is8Bit())
     1094        return false;
     1095    for (auto codePoint : string.codePoints()) {
     1096        if (U_IS_SURROGATE(codePoint))
     1097            return true;
     1098    }
     1099    return false;
     1100}
     1101
    10901102} // namespace WTF
    10911103
    … …  
    10941106using WTF::StringView;
    10951107using WTF::StringViewWithUnderlyingString;
     1108using WTF::hasUnpairedSurrogate;
  • trunk/Source/WebCore/ChangeLog

    r270919 r270923  
     12020-12-15  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Accept arbitrary module namespace identifier names
     4        https://bugs.webkit.org/show_bug.cgi?id=217576
     5
     6        Reviewed by Darin Adler.
     7
     8        * bindings/js/JSDOMConvertStrings.cpp:
     9        (WebCore::hasUnpairedSurrogate): Deleted.
     10
    1112020-12-16  Peng Liu  <peng.liu6@apple.com>
    212
  • trunk/Source/WebCore/bindings/js/JSDOMConvertStrings.cpp

    r251425 r270923  
    6363}
    6464
    65 static inline bool hasUnpairedSurrogate(StringView string)
    66 {
    67     // Fast path for 8-bit strings; they can't have any surrogates.
    68     if (string.is8Bit())
    69         return false;
    70     for (auto codePoint : string.codePoints()) {
    71         if (U_IS_SURROGATE(codePoint))
    72             return true;
    73     }
    74     return false;
    75 }
    76 
    7765static inline String stringToUSVString(String&& string)
    7866{
Note: See TracChangeset for help on using the changeset viewer.