Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: src/parser.cc

Issue 934323004: Teach ModuleDescriptor about basic local exports (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Handled review comments, added message tests Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/api.h" 7 #include "src/api.h"
8 #include "src/ast.h" 8 #include "src/ast.h"
9 #include "src/bailout-reason.h" 9 #include "src/bailout-reason.h"
10 #include "src/base/platform/platform.h" 10 #include "src/base/platform/platform.h"
(...skipping 1263 matching lines...) Expand 10 before | Expand all | Expand 10 after
1274 } 1274 }
1275 } 1275 }
1276 1276
1277 scope->set_end_position(scanner()->location().end_pos); 1277 scope->set_end_position(scanner()->location().end_pos);
1278 body->set_scope(scope); 1278 body->set_scope(scope);
1279 1279
1280 // Check that all exports are bound. 1280 // Check that all exports are bound.
1281 ModuleDescriptor* descriptor = scope->module(); 1281 ModuleDescriptor* descriptor = scope->module();
1282 for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done(); 1282 for (ModuleDescriptor::Iterator it = descriptor->iterator(); !it.done();
1283 it.Advance()) { 1283 it.Advance()) {
1284 if (scope->LookupLocal(it.name()) == NULL) { 1284 if (scope->LookupLocal(it.local_name()) == NULL) {
1285 ParserTraits::ReportMessage("module_export_undefined", it.name()); 1285 // TODO(adamk): Pass both local_name and export_name once ParserTraits
1286 // supports multiple arg error messages.
1287 // Also try to report this at a better location.
1288 ParserTraits::ReportMessage("module_export_undefined", it.local_name());
1286 *ok = false; 1289 *ok = false;
1287 return NULL; 1290 return NULL;
1288 } 1291 }
1289 } 1292 }
1290 1293
1291 scope->module()->Freeze(); 1294 scope->module()->Freeze();
1292 return body; 1295 return body;
1293 } 1296 }
1294 1297
1295 1298
1296 Literal* Parser::ParseModuleSpecifier(bool* ok) { 1299 Literal* Parser::ParseModuleSpecifier(bool* ok) {
1297 // ModuleSpecifier : 1300 // ModuleSpecifier :
1298 // StringLiteral 1301 // StringLiteral
1299 1302
1300 int pos = peek_position(); 1303 int pos = peek_position();
1301 Expect(Token::STRING, CHECK_OK); 1304 Expect(Token::STRING, CHECK_OK);
1302 return factory()->NewStringLiteral(GetSymbol(scanner()), pos); 1305 return factory()->NewStringLiteral(GetSymbol(scanner()), pos);
1303 } 1306 }
1304 1307
1305 1308
1306 void* Parser::ParseExportClause(ZoneList<const AstRawString*>* names, 1309 void* Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names,
1310 ZoneList<Scanner::Location>* export_locations,
1311 ZoneList<const AstRawString*>* local_names,
1307 Scanner::Location* reserved_loc, bool* ok) { 1312 Scanner::Location* reserved_loc, bool* ok) {
1308 // ExportClause : 1313 // ExportClause :
1309 // '{' '}' 1314 // '{' '}'
1310 // '{' ExportsList '}' 1315 // '{' ExportsList '}'
1311 // '{' ExportsList ',' '}' 1316 // '{' ExportsList ',' '}'
1312 // 1317 //
1313 // ExportsList : 1318 // ExportsList :
1314 // ExportSpecifier 1319 // ExportSpecifier
1315 // ExportsList ',' ExportSpecifier 1320 // ExportsList ',' ExportSpecifier
1316 // 1321 //
1317 // ExportSpecifier : 1322 // ExportSpecifier :
1318 // IdentifierName 1323 // IdentifierName
1319 // IdentifierName 'as' IdentifierName 1324 // IdentifierName 'as' IdentifierName
1320 1325
1321 Expect(Token::LBRACE, CHECK_OK); 1326 Expect(Token::LBRACE, CHECK_OK);
1322 1327
1323 Token::Value name_tok; 1328 Token::Value name_tok;
1324 while ((name_tok = peek()) != Token::RBRACE) { 1329 while ((name_tok = peek()) != Token::RBRACE) {
1325 // Keep track of the first reserved word encountered in case our 1330 // Keep track of the first reserved word encountered in case our
1326 // caller needs to report an error. 1331 // caller needs to report an error.
1327 if (!reserved_loc->IsValid() && 1332 if (!reserved_loc->IsValid() &&
1328 !Token::IsIdentifier(name_tok, STRICT, false)) { 1333 !Token::IsIdentifier(name_tok, STRICT, false)) {
1329 *reserved_loc = scanner()->location(); 1334 *reserved_loc = scanner()->location();
1330 } 1335 }
1331 const AstRawString* name = ParseIdentifierName(CHECK_OK); 1336 const AstRawString* local_name = ParseIdentifierName(CHECK_OK);
1332 names->Add(name, zone());
1333 const AstRawString* export_name = NULL; 1337 const AstRawString* export_name = NULL;
1334 if (CheckContextualKeyword(CStrVector("as"))) { 1338 if (CheckContextualKeyword(CStrVector("as"))) {
1335 export_name = ParseIdentifierName(CHECK_OK); 1339 export_name = ParseIdentifierName(CHECK_OK);
1336 } 1340 }
1337 // TODO(ES6): Return the export_name as well as the name. 1341 if (export_name == NULL) {
1338 USE(export_name); 1342 export_name = local_name;
1343 }
1344 export_names->Add(export_name, zone());
1345 local_names->Add(local_name, zone());
1346 export_locations->Add(scanner()->location(), zone());
1339 if (peek() == Token::RBRACE) break; 1347 if (peek() == Token::RBRACE) break;
1340 Expect(Token::COMMA, CHECK_OK); 1348 Expect(Token::COMMA, CHECK_OK);
1341 } 1349 }
1342 1350
1343 Expect(Token::RBRACE, CHECK_OK); 1351 Expect(Token::RBRACE, CHECK_OK);
1344 1352
1345 return 0; 1353 return 0;
1346 } 1354 }
1347 1355
1348 1356
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
1472 return factory()->NewEmptyStatement(pos); 1480 return factory()->NewEmptyStatement(pos);
1473 } 1481 }
1474 1482
1475 1483
1476 Statement* Parser::ParseExportDefault(bool* ok) { 1484 Statement* Parser::ParseExportDefault(bool* ok) {
1477 // Supports the following productions, starting after the 'default' token: 1485 // Supports the following productions, starting after the 'default' token:
1478 // 'export' 'default' FunctionDeclaration 1486 // 'export' 'default' FunctionDeclaration
1479 // 'export' 'default' ClassDeclaration 1487 // 'export' 'default' ClassDeclaration
1480 // 'export' 'default' AssignmentExpression[In] ';' 1488 // 'export' 'default' AssignmentExpression[In] ';'
1481 1489
1490 Expect(Token::DEFAULT, CHECK_OK);
1491 Scanner::Location default_loc = scanner()->location();
1492
1493 ZoneList<const AstRawString*> names(1, zone());
1482 Statement* result = NULL; 1494 Statement* result = NULL;
1483 switch (peek()) { 1495 switch (peek()) {
1484 case Token::FUNCTION: 1496 case Token::FUNCTION:
1485 // TODO(ES6): Support parsing anonymous function declarations here. 1497 // TODO(ES6): Support parsing anonymous function declarations here.
1486 result = ParseFunctionDeclaration(NULL, CHECK_OK); 1498 result = ParseFunctionDeclaration(&names, CHECK_OK);
1487 break; 1499 break;
1488 1500
1489 case Token::CLASS: 1501 case Token::CLASS:
1490 // TODO(ES6): Support parsing anonymous class declarations here. 1502 // TODO(ES6): Support parsing anonymous class declarations here.
1491 result = ParseClassDeclaration(NULL, CHECK_OK); 1503 result = ParseClassDeclaration(&names, CHECK_OK);
1492 break; 1504 break;
1493 1505
1494 default: { 1506 default: {
1495 int pos = peek_position(); 1507 int pos = peek_position();
1496 Expression* expr = ParseAssignmentExpression(true, CHECK_OK); 1508 Expression* expr = ParseAssignmentExpression(true, CHECK_OK);
1497 ExpectSemicolon(CHECK_OK); 1509 ExpectSemicolon(CHECK_OK);
1498 result = factory()->NewExpressionStatement(expr, pos); 1510 result = factory()->NewExpressionStatement(expr, pos);
1499 break; 1511 break;
1500 } 1512 }
1501 } 1513 }
1502 1514
1503 // TODO(ES6): Add default export to scope_->module() 1515 const AstRawString* default_string = ast_value_factory()->default_string();
1516
1517 DCHECK_LE(names.length(), 1);
1518 if (names.length() == 1) {
1519 scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok);
1520 if (!*ok) {
1521 ParserTraits::ReportMessageAt(default_loc, "duplicate_export",
1522 default_string);
1523 return NULL;
1524 }
1525 } else {
1526 // TODO(ES6): Assign result to a const binding with the name "*default*"
1527 // and add an export entry with "*default*" as the local name.
1528 }
1504 1529
1505 return result; 1530 return result;
1506 } 1531 }
1507 1532
1508 1533
1509 Statement* Parser::ParseExportDeclaration(bool* ok) { 1534 Statement* Parser::ParseExportDeclaration(bool* ok) {
1510 // ExportDeclaration: 1535 // ExportDeclaration:
1511 // 'export' '*' 'from' ModuleSpecifier ';' 1536 // 'export' '*' 'from' ModuleSpecifier ';'
1512 // 'export' ExportClause ('from' ModuleSpecifier)? ';' 1537 // 'export' ExportClause ('from' ModuleSpecifier)? ';'
1513 // 'export' VariableStatement 1538 // 'export' VariableStatement
1514 // 'export' Declaration 1539 // 'export' Declaration
1515 // 'export' 'default' ... (handled in ParseExportDefault) 1540 // 'export' 'default' ... (handled in ParseExportDefault)
1516 1541
1517 int pos = peek_position(); 1542 int pos = peek_position();
1518 Expect(Token::EXPORT, CHECK_OK); 1543 Expect(Token::EXPORT, CHECK_OK);
1519 1544
1520 Statement* result = NULL; 1545 Statement* result = NULL;
1521 ZoneList<const AstRawString*> names(1, zone()); 1546 ZoneList<const AstRawString*> names(1, zone());
1522 bool is_export_from = false;
1523 switch (peek()) { 1547 switch (peek()) {
1524 case Token::DEFAULT: 1548 case Token::DEFAULT:
1525 Consume(Token::DEFAULT);
1526 return ParseExportDefault(ok); 1549 return ParseExportDefault(ok);
1527 1550
1528 case Token::MUL: { 1551 case Token::MUL: {
1529 Consume(Token::MUL); 1552 Consume(Token::MUL);
1530 ExpectContextualKeyword(CStrVector("from"), CHECK_OK); 1553 ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
1531 Literal* module = ParseModuleSpecifier(CHECK_OK); 1554 Literal* module = ParseModuleSpecifier(CHECK_OK);
1532 ExpectSemicolon(CHECK_OK); 1555 ExpectSemicolon(CHECK_OK);
1533 // TODO(ES6): Do something with the return value 1556 // TODO(ES6): scope_->module()->AddStarExport(...)
1534 // of ParseModuleSpecifier.
1535 USE(module); 1557 USE(module);
1536 is_export_from = true; 1558 return factory()->NewEmptyStatement(pos);
1537 result = factory()->NewEmptyStatement(pos);
1538 break;
1539 } 1559 }
1540 1560
1541 case Token::LBRACE: { 1561 case Token::LBRACE: {
1542 // There are two cases here: 1562 // There are two cases here:
1543 // 1563 //
1544 // 'export' ExportClause ';' 1564 // 'export' ExportClause ';'
1545 // and 1565 // and
1546 // 'export' ExportClause FromClause ';' 1566 // 'export' ExportClause FromClause ';'
1547 // 1567 //
1548 // In the first case, the exported identifiers in ExportClause must 1568 // In the first case, the exported identifiers in ExportClause must
1549 // not be reserved words, while in the latter they may be. We 1569 // not be reserved words, while in the latter they may be. We
1550 // pass in a location that gets filled with the first reserved word 1570 // pass in a location that gets filled with the first reserved word
1551 // encountered, and then throw a SyntaxError if we are in the 1571 // encountered, and then throw a SyntaxError if we are in the
1552 // non-FromClause case. 1572 // non-FromClause case.
1553 Scanner::Location reserved_loc = Scanner::Location::invalid(); 1573 Scanner::Location reserved_loc = Scanner::Location::invalid();
1554 ParseExportClause(&names, &reserved_loc, CHECK_OK); 1574 ZoneList<const AstRawString*> export_names(1, zone());
1575 ZoneList<Scanner::Location> export_locations(1, zone());
1576 ZoneList<const AstRawString*> local_names(1, zone());
1577 ParseExportClause(&export_names, &export_locations, &local_names,
1578 &reserved_loc, CHECK_OK);
1579 Literal* indirect_export_module_specifier = NULL;
1555 if (CheckContextualKeyword(CStrVector("from"))) { 1580 if (CheckContextualKeyword(CStrVector("from"))) {
1556 Literal* module = ParseModuleSpecifier(CHECK_OK); 1581 indirect_export_module_specifier = ParseModuleSpecifier(CHECK_OK);
1557 // TODO(ES6): Do something with the return value
1558 // of ParseModuleSpecifier.
1559 USE(module);
1560 is_export_from = true;
1561 } else if (reserved_loc.IsValid()) { 1582 } else if (reserved_loc.IsValid()) {
1562 // No FromClause, so reserved words are invalid in ExportClause. 1583 // No FromClause, so reserved words are invalid in ExportClause.
1563 *ok = false; 1584 *ok = false;
1564 ReportMessageAt(reserved_loc, "unexpected_reserved"); 1585 ReportMessageAt(reserved_loc, "unexpected_reserved");
1565 return NULL; 1586 return NULL;
1566 } 1587 }
1567 ExpectSemicolon(CHECK_OK); 1588 ExpectSemicolon(CHECK_OK);
1568 result = factory()->NewEmptyStatement(pos); 1589 const int length = export_names.length();
1569 break; 1590 DCHECK_EQ(length, local_names.length());
1591 DCHECK_EQ(length, export_locations.length());
1592 if (indirect_export_module_specifier == NULL) {
1593 for (int i = 0; i < length; ++i) {
1594 scope_->module()->AddLocalExport(export_names[i], local_names[i],
1595 zone(), ok);
1596 if (!*ok) {
1597 ParserTraits::ReportMessageAt(export_locations[i],
1598 "duplicate_export", export_names[i]);
1599 return NULL;
1600 }
1601 }
1602 } else {
1603 for (int i = 0; i < length; ++i) {
1604 // TODO(ES6): scope_->module()->AddIndirectExport(...);(
1605 }
1606 }
1607 return factory()->NewEmptyStatement(pos);
1570 } 1608 }
1571 1609
1572 case Token::FUNCTION: 1610 case Token::FUNCTION:
1573 result = ParseFunctionDeclaration(&names, CHECK_OK); 1611 result = ParseFunctionDeclaration(&names, CHECK_OK);
1574 break; 1612 break;
1575 1613
1576 case Token::CLASS: 1614 case Token::CLASS:
1577 result = ParseClassDeclaration(&names, CHECK_OK); 1615 result = ParseClassDeclaration(&names, CHECK_OK);
1578 break; 1616 break;
1579 1617
1580 case Token::VAR: 1618 case Token::VAR:
1581 case Token::LET: 1619 case Token::LET:
1582 case Token::CONST: 1620 case Token::CONST:
1583 result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK); 1621 result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
1584 break; 1622 break;
1585 1623
1586 default: 1624 default:
1587 *ok = false; 1625 *ok = false;
1588 ReportUnexpectedToken(scanner()->current_token()); 1626 ReportUnexpectedToken(scanner()->current_token());
1589 return NULL; 1627 return NULL;
1590 } 1628 }
1591 1629
1592 // Every export of a module may be assigned. 1630 // Extract declared names into export declarations.
1631 ModuleDescriptor* descriptor = scope_->module();
1593 for (int i = 0; i < names.length(); ++i) { 1632 for (int i = 0; i < names.length(); ++i) {
1594 Variable* var = scope_->Lookup(names[i]); 1633 descriptor->AddLocalExport(names[i], names[i], zone(), ok);
1595 if (var == NULL) { 1634 if (!*ok) {
1596 // TODO(sigurds) This is an export that has no definition yet, 1635 // TODO(adamk): Possibly report this error at the right place.
1597 // not clear what to do in this case. 1636 ParserTraits::ReportMessage("duplicate_export", names[i]);
1598 continue; 1637 return NULL;
1599 }
1600 if (!IsImmutableVariableMode(var->mode())) {
1601 var->set_maybe_assigned();
1602 } 1638 }
1603 } 1639 }
1604 1640
1605 // TODO(ES6): Handle 'export from' once imports are properly implemented. 1641 DCHECK_NOT_NULL(result);
1606 // For now we just drop such exports on the floor.
1607 if (!is_export_from) {
1608 // Extract declared names into export declarations and module descriptor.
1609 ModuleDescriptor* descriptor = scope_->module();
1610 for (int i = 0; i < names.length(); ++i) {
1611 // TODO(adamk): Make early errors here provide the right error message
1612 // (duplicate exported names).
1613 descriptor->Add(names[i], zone(), CHECK_OK);
1614 // TODO(rossberg): Rethink whether we actually need to store export
1615 // declarations (for compilation?).
1616 // ExportDeclaration* declaration =
1617 // factory()->NewExportDeclaration(proxy, scope_, position);
1618 // scope_->AddDeclaration(declaration);
1619 }
1620 }
1621
1622 DCHECK(result != NULL);
1623 return result; 1642 return result;
1624 } 1643 }
1625 1644
1626 1645
1627 Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels, 1646 Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
1628 bool* ok) { 1647 bool* ok) {
1629 // Statement :: 1648 // Statement ::
1630 // EmptyStatement 1649 // EmptyStatement
1631 // ... 1650 // ...
1632 1651
(...skipping 3807 matching lines...) Expand 10 before | Expand all | Expand 10 after
5440 } else { 5459 } else {
5441 const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data()); 5460 const uc16* data = reinterpret_cast<const uc16*>(raw_string->raw_data());
5442 running_hash = StringHasher::ComputeRunningHash(running_hash, data, 5461 running_hash = StringHasher::ComputeRunningHash(running_hash, data,
5443 raw_string->length()); 5462 raw_string->length());
5444 } 5463 }
5445 } 5464 }
5446 5465
5447 return running_hash; 5466 return running_hash;
5448 } 5467 }
5449 } } // namespace v8::internal 5468 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/parser.h ('k') | src/scopeinfo.cc » ('j') | test/message/export-duplicate.out » ('J')

Powered by Google App Engine
This is Rietveld 408576698