Home | History | Annotate | Download | only in ast
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_AST_MODULES_H_
      6 #define V8_AST_MODULES_H_
      7 
      8 #include "src/parsing/scanner.h"  // Only for Scanner::Location.
      9 #include "src/zone/zone-containers.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 
     15 class AstRawString;
     16 class ModuleInfo;
     17 class ModuleInfoEntry;
     18 class PendingCompilationErrorHandler;
     19 
     20 class ModuleDescriptor : public ZoneObject {
     21  public:
     22   explicit ModuleDescriptor(Zone* zone)
     23       : module_requests_(zone),
     24         special_exports_(1, zone),
     25         namespace_imports_(1, zone),
     26         regular_exports_(zone),
     27         regular_imports_(zone) {}
     28 
     29   // The following Add* methods are high-level convenience functions for use by
     30   // the parser.
     31 
     32   // import x from "foo.js";
     33   // import {x} from "foo.js";
     34   // import {x as y} from "foo.js";
     35   void AddImport(
     36     const AstRawString* import_name, const AstRawString* local_name,
     37     const AstRawString* module_request, const Scanner::Location loc,
     38     Zone* zone);
     39 
     40   // import * as x from "foo.js";
     41   void AddStarImport(
     42     const AstRawString* local_name, const AstRawString* module_request,
     43     const Scanner::Location loc, Zone* zone);
     44 
     45   // import "foo.js";
     46   // import {} from "foo.js";
     47   // export {} from "foo.js";  (sic!)
     48   void AddEmptyImport(const AstRawString* module_request);
     49 
     50   // export {x};
     51   // export {x as y};
     52   // export VariableStatement
     53   // export Declaration
     54   // export default ...
     55   void AddExport(
     56     const AstRawString* local_name, const AstRawString* export_name,
     57     const Scanner::Location loc, Zone* zone);
     58 
     59   // export {x} from "foo.js";
     60   // export {x as y} from "foo.js";
     61   void AddExport(
     62     const AstRawString* export_name, const AstRawString* import_name,
     63     const AstRawString* module_request, const Scanner::Location loc,
     64     Zone* zone);
     65 
     66   // export * from "foo.js";
     67   void AddStarExport(
     68     const AstRawString* module_request, const Scanner::Location loc,
     69     Zone* zone);
     70 
     71   // Check if module is well-formed and report error if not.
     72   // Also canonicalize indirect exports.
     73   bool Validate(ModuleScope* module_scope,
     74                 PendingCompilationErrorHandler* error_handler, Zone* zone);
     75 
     76   struct Entry : public ZoneObject {
     77     Scanner::Location location;
     78     const AstRawString* export_name;
     79     const AstRawString* local_name;
     80     const AstRawString* import_name;
     81 
     82     // The module_request value records the order in which modules are
     83     // requested. It also functions as an index into the ModuleInfo's array of
     84     // module specifiers and into the Module's array of requested modules.  A
     85     // negative value means no module request.
     86     int module_request;
     87 
     88     // Import/export entries that are associated with a MODULE-allocated
     89     // variable (i.e. regular_imports and regular_exports after Validate) use
     90     // the cell_index value to encode the location of their cell.  During
     91     // variable allocation, this will be be copied into the variable's index
     92     // field.
     93     // Entries that are not associated with a MODULE-allocated variable have
     94     // GetCellIndexKind(cell_index) == kInvalid.
     95     int cell_index;
     96 
     97     // TODO(neis): Remove local_name component?
     98     explicit Entry(Scanner::Location loc)
     99         : location(loc),
    100           export_name(nullptr),
    101           local_name(nullptr),
    102           import_name(nullptr),
    103           module_request(-1),
    104           cell_index(0) {}
    105 
    106     // (De-)serialization support.
    107     // Note that the location value is not preserved as it's only needed by the
    108     // parser.  (A Deserialize'd entry has an invalid location.)
    109     Handle<ModuleInfoEntry> Serialize(Isolate* isolate) const;
    110     static Entry* Deserialize(Isolate* isolate, AstValueFactory* avfactory,
    111                               Handle<ModuleInfoEntry> entry);
    112   };
    113 
    114   enum CellIndexKind { kInvalid, kExport, kImport };
    115   static CellIndexKind GetCellIndexKind(int cell_index);
    116 
    117   // Module requests.
    118   const ZoneMap<const AstRawString*, int>& module_requests() const {
    119     return module_requests_;
    120   }
    121 
    122   // Namespace imports.
    123   const ZoneList<const Entry*>& namespace_imports() const {
    124     return namespace_imports_;
    125   }
    126 
    127   // All the remaining imports, indexed by local name.
    128   const ZoneMap<const AstRawString*, Entry*>& regular_imports() const {
    129     return regular_imports_;
    130   }
    131 
    132   // Star exports and explicitly indirect exports.
    133   const ZoneList<const Entry*>& special_exports() const {
    134     return special_exports_;
    135   }
    136 
    137   // All the remaining exports, indexed by local name.
    138   // After canonicalization (see Validate), these are exactly the local exports.
    139   const ZoneMultimap<const AstRawString*, Entry*>& regular_exports() const {
    140     return regular_exports_;
    141   }
    142 
    143   void AddRegularExport(Entry* entry) {
    144     DCHECK_NOT_NULL(entry->export_name);
    145     DCHECK_NOT_NULL(entry->local_name);
    146     DCHECK_NULL(entry->import_name);
    147     DCHECK_LT(entry->module_request, 0);
    148     regular_exports_.insert(std::make_pair(entry->local_name, entry));
    149   }
    150 
    151   void AddSpecialExport(const Entry* entry, Zone* zone) {
    152     DCHECK_NULL(entry->local_name);
    153     DCHECK_LE(0, entry->module_request);
    154     special_exports_.Add(entry, zone);
    155   }
    156 
    157   void AddRegularImport(Entry* entry) {
    158     DCHECK_NOT_NULL(entry->import_name);
    159     DCHECK_NOT_NULL(entry->local_name);
    160     DCHECK_NULL(entry->export_name);
    161     DCHECK_LE(0, entry->module_request);
    162     regular_imports_.insert(std::make_pair(entry->local_name, entry));
    163     // We don't care if there's already an entry for this local name, as in that
    164     // case we will report an error when declaring the variable.
    165   }
    166 
    167   void AddNamespaceImport(const Entry* entry, Zone* zone) {
    168     DCHECK_NULL(entry->import_name);
    169     DCHECK_NULL(entry->export_name);
    170     DCHECK_NOT_NULL(entry->local_name);
    171     DCHECK_LE(0, entry->module_request);
    172     namespace_imports_.Add(entry, zone);
    173   }
    174 
    175   Handle<FixedArray> SerializeRegularExports(Isolate* isolate,
    176                                              Zone* zone) const;
    177   void DeserializeRegularExports(Isolate* isolate, AstValueFactory* avfactory,
    178                                  Handle<ModuleInfo> module_info);
    179 
    180  private:
    181   // TODO(neis): Use STL datastructure instead of ZoneList?
    182   ZoneMap<const AstRawString*, int> module_requests_;
    183   ZoneList<const Entry*> special_exports_;
    184   ZoneList<const Entry*> namespace_imports_;
    185   ZoneMultimap<const AstRawString*, Entry*> regular_exports_;
    186   ZoneMap<const AstRawString*, Entry*> regular_imports_;
    187 
    188   // If there are multiple export entries with the same export name, return the
    189   // last of them (in source order).  Otherwise return nullptr.
    190   const Entry* FindDuplicateExport(Zone* zone) const;
    191 
    192   // Find any implicitly indirect exports and make them explicit.
    193   //
    194   // An explicitly indirect export is an export entry arising from an export
    195   // statement of the following form:
    196   //   export {a as c} from "X";
    197   // An implicitly indirect export corresponds to
    198   //   export {b as c};
    199   // in the presence of an import statement of the form
    200   //   import {a as b} from "X";
    201   // This function finds such implicitly indirect export entries and rewrites
    202   // them by filling in the import name and module request, as well as nulling
    203   // out the local name.  Effectively, it turns
    204   //   import {a as b} from "X"; export {b as c};
    205   // into:
    206   //   import {a as b} from "X"; export {a as c} from "X";
    207   // (The import entry is never deleted.)
    208   void MakeIndirectExportsExplicit(Zone* zone);
    209 
    210   // Assign a cell_index of -1,-2,... to regular imports.
    211   // Assign a cell_index of +1,+2,... to regular (local) exports.
    212   // Assign a cell_index of 0 to anything else.
    213   void AssignCellIndices();
    214 
    215   int AddModuleRequest(const AstRawString* specifier) {
    216     DCHECK_NOT_NULL(specifier);
    217     auto it = module_requests_
    218                   .insert(std::make_pair(specifier, module_requests_.size()))
    219                   .first;
    220     return it->second;
    221   }
    222 };
    223 
    224 }  // namespace internal
    225 }  // namespace v8
    226 
    227 #endif  // V8_AST_MODULES_H_
    228