| Index: vm/parser.cc
|
| ===================================================================
|
| --- vm/parser.cc (revision 4054)
|
| +++ vm/parser.cc (working copy)
|
| @@ -3224,14 +3224,16 @@
|
|
|
| Dart_Handle Parser::CallLibraryTagHandler(Dart_LibraryTag tag,
|
| intptr_t token_pos,
|
| - const String& url) {
|
| + const String& url,
|
| + const Array& import_map) {
|
| Dart_LibraryTagHandler handler = Isolate::Current()->library_tag_handler();
|
| if (handler == NULL) {
|
| ErrorMsg(token_pos, "no library handler registered");
|
| }
|
| Dart_Handle result = handler(tag,
|
| Api::NewLocalHandle(library_),
|
| - Api::NewLocalHandle(url));
|
| + Api::NewLocalHandle(url),
|
| + Api::NewLocalHandle(import_map));
|
| if (Dart_IsError(result)) {
|
| ErrorMsg(token_pos, "library handler failed: %s", Dart_GetError(result));
|
| }
|
| @@ -3247,8 +3249,7 @@
|
| if (CurrentToken() != Token::kSTRING) {
|
| ErrorMsg("library url expected");
|
| }
|
| - const String& url = *CurrentLiteral();
|
| - ConsumeToken();
|
| + const String& url = *ParseImportStringLiteral();
|
| String& prefix = String::Handle();
|
| if (CurrentToken() == Token::kCOMMA) {
|
| ConsumeToken();
|
| @@ -3269,15 +3270,17 @@
|
| }
|
| ExpectToken(Token::kRPAREN);
|
| ExpectToken(Token::kSEMICOLON);
|
| + const Array& import_map = Array::Handle(library_.import_map());
|
| Dart_Handle handle = CallLibraryTagHandler(kCanonicalizeUrl,
|
| import_pos,
|
| - url);
|
| + url,
|
| + import_map);
|
| const String& canon_url = String::CheckedHandle(Api::UnwrapHandle(handle));
|
| // Lookup the library URL.
|
| Library& library = Library::Handle(Library::LookupLibrary(canon_url));
|
| if (library.IsNull()) {
|
| // Call the library tag handler to load the library.
|
| - CallLibraryTagHandler(kImportTag, import_pos, canon_url);
|
| + CallLibraryTagHandler(kImportTag, import_pos, canon_url, import_map);
|
| // If the library tag handler succeded without registering the
|
| // library we create an empty library to import.
|
| library = Library::LookupLibrary(canon_url);
|
| @@ -3302,6 +3305,7 @@
|
|
|
|
|
| void Parser::ParseLibraryInclude() {
|
| + const Array& import_map = Array::Handle(library_.import_map());
|
| while (CurrentToken() == Token::kSOURCE) {
|
| const intptr_t source_pos = token_index_;
|
| ConsumeToken();
|
| @@ -3309,15 +3313,15 @@
|
| if (CurrentToken() != Token::kSTRING) {
|
| ErrorMsg("source url expected");
|
| }
|
| - const String& url = *CurrentLiteral();
|
| - ConsumeToken();
|
| + const String& url = *ParseImportStringLiteral();
|
| ExpectToken(Token::kRPAREN);
|
| ExpectToken(Token::kSEMICOLON);
|
| Dart_Handle handle = CallLibraryTagHandler(kCanonicalizeUrl,
|
| source_pos,
|
| - url);
|
| + url,
|
| + import_map);
|
| const String& canon_url = String::CheckedHandle(Api::UnwrapHandle(handle));
|
| - CallLibraryTagHandler(kSourceTag, source_pos, canon_url);
|
| + CallLibraryTagHandler(kSourceTag, source_pos, canon_url, import_map);
|
| }
|
| }
|
|
|
| @@ -6646,6 +6650,22 @@
|
| }
|
|
|
|
|
| +// Resolve variables used in an import string literal.
|
| +// If the variable name cannot be resolved issue an error message.
|
| +// Currently we only resolve against the global map which is passed in
|
| +// when the script is loaded.
|
| +RawString* Parser::ResolveImportVar(intptr_t ident_pos, const String& ident) {
|
| + TRACE_PARSER("ResolveImportVar");
|
| + String& map_name = String::Handle(library_.LookupImportMap(ident));
|
| + if (!map_name.IsNull()) {
|
| + return map_name.raw();
|
| + }
|
| + ErrorMsg(ident_pos, "import variable '%s' has not been defined",
|
| + ident.ToCString());
|
| + return String::null();
|
| +}
|
| +
|
| +
|
| // Parses type = [ident "."] ident ["<" type { "," type } ">"].
|
| // Returns the class object if the type can be resolved. Otherwise, either give
|
| // an error if type resolution was required, or return the unresolved name as a
|
| @@ -7323,7 +7343,6 @@
|
| }
|
| // String interpolation needed.
|
| ArrayNode* values = new ArrayNode(token_index_, TypeArguments::ZoneHandle());
|
| - GrowableArray<const Object*> arg_values;
|
| while (CurrentToken() == Token::kSTRING) {
|
| values->AddElement(new LiteralNode(token_index_, *CurrentLiteral()));
|
| ConsumeToken();
|
| @@ -7359,6 +7378,61 @@
|
| }
|
|
|
|
|
| +// An import string literal consists of the concatenation of the next n tokens
|
| +// that satisfy the EBNF grammar:
|
| +// literal = kSTRING {{ interpol }+ kSTRING }
|
| +// interpol = kINTERPOL_VAR
|
| +// In other words, the scanner breaks down interpolated strings so that
|
| +// a string literal always begins and ends with a kSTRING token, and
|
| +// there are never two kSTRING tokens next to each other.
|
| +String* Parser::ParseImportStringLiteral() {
|
| + if ((CurrentToken() == Token::kSTRING) &&
|
| + (LookaheadToken(1) != Token::kINTERPOL_VAR) &&
|
| + (LookaheadToken(1) != Token::kINTERPOL_START)) {
|
| + // Common case: no interpolation.
|
| + String* result = CurrentLiteral();
|
| + ConsumeToken();
|
| + return result;
|
| + }
|
| + // String interpolation needed.
|
| + String& result = String::ZoneHandle(String::New(""));
|
| + String& resolved_name = String::Handle();
|
| + while (CurrentToken() == Token::kSTRING) {
|
| + result = String::Concat(result, *CurrentLiteral());
|
| + ConsumeToken();
|
| + if ((CurrentToken() != Token::kINTERPOL_VAR) &&
|
| + (CurrentToken() != Token::kINTERPOL_START)) {
|
| + break;
|
| + }
|
| + while ((CurrentToken() == Token::kINTERPOL_VAR) ||
|
| + (CurrentToken() == Token::kINTERPOL_START)) {
|
| + if (CurrentToken() == Token::kINTERPOL_START) {
|
| + ConsumeToken();
|
| + if (IsIdentifier()) {
|
| + resolved_name = ResolveImportVar(token_index_, *CurrentLiteral());
|
| + result = String::Concat(result, resolved_name);
|
| + ConsumeToken();
|
| + if (CurrentToken() != Token::kINTERPOL_END) {
|
| + ErrorMsg("'}' expected");
|
| + }
|
| + ConsumeToken();
|
| + } else {
|
| + ErrorMsg("identifier expected");
|
| + }
|
| + } else {
|
| + ASSERT(CurrentToken() == Token::kINTERPOL_VAR);
|
| + resolved_name = ResolveImportVar(token_index_, *CurrentLiteral());
|
| + result = String::Concat(result, resolved_name);
|
| + ConsumeToken();
|
| + }
|
| + }
|
| + // A string literal always ends with a kSTRING token.
|
| + ASSERT(CurrentToken() == Token::kSTRING);
|
| + }
|
| + return &result;
|
| +}
|
| +
|
| +
|
| AstNode* Parser::ParsePrimary() {
|
| TRACE_PARSER("ParsePrimary");
|
| ASSERT(!is_top_level_);
|
|
|