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

Side by Side Diff: vm/parser.cc

Issue 9359009: Implement support for specifying string interopolation style variable substitution in the import ... (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
Patch Set: '' Created 8 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 | Annotate | Revision Log
« no previous file with comments | « vm/parser.h ('k') | vm/raw_object.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/parser.h" 5 #include "vm/parser.h"
6 6
7 #include "vm/bigint_operations.h" 7 #include "vm/bigint_operations.h"
8 #include "vm/class_finalizer.h" 8 #include "vm/class_finalizer.h"
9 #include "vm/compiler.h" 9 #include "vm/compiler.h"
10 #include "vm/compiler_stats.h" 10 #include "vm/compiler_stats.h"
(...skipping 3206 matching lines...) Expand 10 before | Expand all | Expand 10 after
3217 ConsumeToken(); 3217 ConsumeToken();
3218 ExpectToken(Token::kRPAREN); 3218 ExpectToken(Token::kRPAREN);
3219 ExpectToken(Token::kSEMICOLON); 3219 ExpectToken(Token::kSEMICOLON);
3220 library_.SetName(name); 3220 library_.SetName(name);
3221 } 3221 }
3222 } 3222 }
3223 3223
3224 3224
3225 Dart_Handle Parser::CallLibraryTagHandler(Dart_LibraryTag tag, 3225 Dart_Handle Parser::CallLibraryTagHandler(Dart_LibraryTag tag,
3226 intptr_t token_pos, 3226 intptr_t token_pos,
3227 const String& url) { 3227 const String& url,
3228 const Array& import_map) {
3228 Dart_LibraryTagHandler handler = Isolate::Current()->library_tag_handler(); 3229 Dart_LibraryTagHandler handler = Isolate::Current()->library_tag_handler();
3229 if (handler == NULL) { 3230 if (handler == NULL) {
3230 ErrorMsg(token_pos, "no library handler registered"); 3231 ErrorMsg(token_pos, "no library handler registered");
3231 } 3232 }
3232 Dart_Handle result = handler(tag, 3233 Dart_Handle result = handler(tag,
3233 Api::NewLocalHandle(library_), 3234 Api::NewLocalHandle(library_),
3234 Api::NewLocalHandle(url)); 3235 Api::NewLocalHandle(url),
3236 Api::NewLocalHandle(import_map));
3235 if (Dart_IsError(result)) { 3237 if (Dart_IsError(result)) {
3236 ErrorMsg(token_pos, "library handler failed: %s", Dart_GetError(result)); 3238 ErrorMsg(token_pos, "library handler failed: %s", Dart_GetError(result));
3237 } 3239 }
3238 return result; 3240 return result;
3239 } 3241 }
3240 3242
3241 3243
3242 void Parser::ParseLibraryImport() { 3244 void Parser::ParseLibraryImport() {
3243 while (CurrentToken() == Token::kIMPORT) { 3245 while (CurrentToken() == Token::kIMPORT) {
3244 const intptr_t import_pos = token_index_; 3246 const intptr_t import_pos = token_index_;
3245 ConsumeToken(); 3247 ConsumeToken();
3246 ExpectToken(Token::kLPAREN); 3248 ExpectToken(Token::kLPAREN);
3247 if (CurrentToken() != Token::kSTRING) { 3249 if (CurrentToken() != Token::kSTRING) {
3248 ErrorMsg("library url expected"); 3250 ErrorMsg("library url expected");
3249 } 3251 }
3250 const String& url = *CurrentLiteral(); 3252 const String& url = *ParseImportStringLiteral();
3251 ConsumeToken();
3252 String& prefix = String::Handle(); 3253 String& prefix = String::Handle();
3253 if (CurrentToken() == Token::kCOMMA) { 3254 if (CurrentToken() == Token::kCOMMA) {
3254 ConsumeToken(); 3255 ConsumeToken();
3255 if (!IsLiteral("prefix")) { 3256 if (!IsLiteral("prefix")) {
3256 ErrorMsg("prefix: expected"); 3257 ErrorMsg("prefix: expected");
3257 } 3258 }
3258 ConsumeToken(); 3259 ConsumeToken();
3259 ExpectToken(Token::kCOLON); 3260 ExpectToken(Token::kCOLON);
3260 if (CurrentToken() != Token::kSTRING) { 3261 if (CurrentToken() != Token::kSTRING) {
3261 ErrorMsg("prefix expected"); 3262 ErrorMsg("prefix expected");
3262 } 3263 }
3263 prefix = CurrentLiteral()->raw(); 3264 prefix = CurrentLiteral()->raw();
3264 // TODO(asiva): Need to also check that prefix is not a reserved keyword. 3265 // TODO(asiva): Need to also check that prefix is not a reserved keyword.
3265 if (!Scanner::IsIdent(prefix)) { 3266 if (!Scanner::IsIdent(prefix)) {
3266 ErrorMsg("prefix should be an identifier"); 3267 ErrorMsg("prefix should be an identifier");
3267 } 3268 }
3268 ConsumeToken(); 3269 ConsumeToken();
3269 } 3270 }
3270 ExpectToken(Token::kRPAREN); 3271 ExpectToken(Token::kRPAREN);
3271 ExpectToken(Token::kSEMICOLON); 3272 ExpectToken(Token::kSEMICOLON);
3273 const Array& import_map = Array::Handle(library_.import_map());
3272 Dart_Handle handle = CallLibraryTagHandler(kCanonicalizeUrl, 3274 Dart_Handle handle = CallLibraryTagHandler(kCanonicalizeUrl,
3273 import_pos, 3275 import_pos,
3274 url); 3276 url,
3277 import_map);
3275 const String& canon_url = String::CheckedHandle(Api::UnwrapHandle(handle)); 3278 const String& canon_url = String::CheckedHandle(Api::UnwrapHandle(handle));
3276 // Lookup the library URL. 3279 // Lookup the library URL.
3277 Library& library = Library::Handle(Library::LookupLibrary(canon_url)); 3280 Library& library = Library::Handle(Library::LookupLibrary(canon_url));
3278 if (library.IsNull()) { 3281 if (library.IsNull()) {
3279 // Call the library tag handler to load the library. 3282 // Call the library tag handler to load the library.
3280 CallLibraryTagHandler(kImportTag, import_pos, canon_url); 3283 CallLibraryTagHandler(kImportTag, import_pos, canon_url, import_map);
3281 // If the library tag handler succeded without registering the 3284 // If the library tag handler succeded without registering the
3282 // library we create an empty library to import. 3285 // library we create an empty library to import.
3283 library = Library::LookupLibrary(canon_url); 3286 library = Library::LookupLibrary(canon_url);
3284 if (library.IsNull()) { 3287 if (library.IsNull()) {
3285 library = Library::New(canon_url); 3288 library = Library::New(canon_url);
3286 library.Register(); 3289 library.Register();
3287 } 3290 }
3288 } 3291 }
3289 // Add the import to the library. 3292 // Add the import to the library.
3290 if (prefix.IsNull() || (prefix.Length() == 0)) { 3293 if (prefix.IsNull() || (prefix.Length() == 0)) {
3291 library_.AddImport(library); 3294 library_.AddImport(library);
3292 } else { 3295 } else {
3293 if (library_.LookupLocalObject(prefix) != Object::null()) { 3296 if (library_.LookupLocalObject(prefix) != Object::null()) {
3294 ErrorMsg(token_index_, "'%s' is already defined", prefix.ToCString()); 3297 ErrorMsg(token_index_, "'%s' is already defined", prefix.ToCString());
3295 } 3298 }
3296 const LibraryPrefix& library_prefix = 3299 const LibraryPrefix& library_prefix =
3297 LibraryPrefix::Handle(LibraryPrefix::New(prefix, library)); 3300 LibraryPrefix::Handle(LibraryPrefix::New(prefix, library));
3298 library_.AddObject(library_prefix, prefix); 3301 library_.AddObject(library_prefix, prefix);
3299 } 3302 }
3300 } 3303 }
3301 } 3304 }
3302 3305
3303 3306
3304 void Parser::ParseLibraryInclude() { 3307 void Parser::ParseLibraryInclude() {
3308 const Array& import_map = Array::Handle(library_.import_map());
3305 while (CurrentToken() == Token::kSOURCE) { 3309 while (CurrentToken() == Token::kSOURCE) {
3306 const intptr_t source_pos = token_index_; 3310 const intptr_t source_pos = token_index_;
3307 ConsumeToken(); 3311 ConsumeToken();
3308 ExpectToken(Token::kLPAREN); 3312 ExpectToken(Token::kLPAREN);
3309 if (CurrentToken() != Token::kSTRING) { 3313 if (CurrentToken() != Token::kSTRING) {
3310 ErrorMsg("source url expected"); 3314 ErrorMsg("source url expected");
3311 } 3315 }
3312 const String& url = *CurrentLiteral(); 3316 const String& url = *ParseImportStringLiteral();
3313 ConsumeToken();
3314 ExpectToken(Token::kRPAREN); 3317 ExpectToken(Token::kRPAREN);
3315 ExpectToken(Token::kSEMICOLON); 3318 ExpectToken(Token::kSEMICOLON);
3316 Dart_Handle handle = CallLibraryTagHandler(kCanonicalizeUrl, 3319 Dart_Handle handle = CallLibraryTagHandler(kCanonicalizeUrl,
3317 source_pos, 3320 source_pos,
3318 url); 3321 url,
3322 import_map);
3319 const String& canon_url = String::CheckedHandle(Api::UnwrapHandle(handle)); 3323 const String& canon_url = String::CheckedHandle(Api::UnwrapHandle(handle));
3320 CallLibraryTagHandler(kSourceTag, source_pos, canon_url); 3324 CallLibraryTagHandler(kSourceTag, source_pos, canon_url, import_map);
3321 } 3325 }
3322 } 3326 }
3323 3327
3324 3328
3325 void Parser::ParseLibraryDefinition() { 3329 void Parser::ParseLibraryDefinition() {
3326 // Handle the script tag. 3330 // Handle the script tag.
3327 if (CurrentToken() == Token::kSCRIPTTAG) { 3331 if (CurrentToken() == Token::kSCRIPTTAG) {
3328 // Nothing to do for script tags except to skip them. 3332 // Nothing to do for script tags except to skip them.
3329 ConsumeToken(); 3333 ConsumeToken();
3330 } 3334 }
(...skipping 3308 matching lines...) Expand 10 before | Expand all | Expand 10 after
6639 } else { 6643 } else {
6640 ASSERT(primary->primary().IsClass()); 6644 ASSERT(primary->primary().IsClass());
6641 ErrorMsg(ident_pos, "illegal reference to class or interface '%s'", 6645 ErrorMsg(ident_pos, "illegal reference to class or interface '%s'",
6642 ident.ToCString()); 6646 ident.ToCString());
6643 } 6647 }
6644 } 6648 }
6645 return var_or_field; 6649 return var_or_field;
6646 } 6650 }
6647 6651
6648 6652
6653 // Resolve variables used in an import string literal.
6654 // If the variable name cannot be resolved issue an error message.
6655 // Currently we only resolve against the global map which is passed in
6656 // when the script is loaded.
6657 RawString* Parser::ResolveImportVar(intptr_t ident_pos, const String& ident) {
6658 TRACE_PARSER("ResolveImportVar");
6659 String& map_name = String::Handle(library_.LookupImportMap(ident));
6660 if (!map_name.IsNull()) {
6661 return map_name.raw();
6662 }
6663 ErrorMsg(ident_pos, "import variable '%s' has not been defined",
6664 ident.ToCString());
6665 return String::null();
6666 }
6667
6668
6649 // Parses type = [ident "."] ident ["<" type { "," type } ">"]. 6669 // Parses type = [ident "."] ident ["<" type { "," type } ">"].
6650 // Returns the class object if the type can be resolved. Otherwise, either give 6670 // Returns the class object if the type can be resolved. Otherwise, either give
6651 // an error if type resolution was required, or return the unresolved name as a 6671 // an error if type resolution was required, or return the unresolved name as a
6652 // string object. 6672 // string object.
6653 RawAbstractType* Parser::ParseType(TypeResolution type_resolution) { 6673 RawAbstractType* Parser::ParseType(TypeResolution type_resolution) {
6654 if (CurrentToken() != Token::kIDENT) { 6674 if (CurrentToken() != Token::kIDENT) {
6655 ErrorMsg("type name expected"); 6675 ErrorMsg("type name expected");
6656 } 6676 }
6657 QualIdent type_name; 6677 QualIdent type_name;
6658 if (type_resolution == kIgnore) { 6678 if (type_resolution == kIgnore) {
(...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after
7316 if ((CurrentToken() == Token::kSTRING) && 7336 if ((CurrentToken() == Token::kSTRING) &&
7317 (LookaheadToken(1) != Token::kINTERPOL_VAR) && 7337 (LookaheadToken(1) != Token::kINTERPOL_VAR) &&
7318 (LookaheadToken(1) != Token::kINTERPOL_START)) { 7338 (LookaheadToken(1) != Token::kINTERPOL_START)) {
7319 // Common case: no interpolation. 7339 // Common case: no interpolation.
7320 primary = new LiteralNode(literal_start, *CurrentLiteral()); 7340 primary = new LiteralNode(literal_start, *CurrentLiteral());
7321 ConsumeToken(); 7341 ConsumeToken();
7322 return primary; 7342 return primary;
7323 } 7343 }
7324 // String interpolation needed. 7344 // String interpolation needed.
7325 ArrayNode* values = new ArrayNode(token_index_, TypeArguments::ZoneHandle()); 7345 ArrayNode* values = new ArrayNode(token_index_, TypeArguments::ZoneHandle());
7326 GrowableArray<const Object*> arg_values;
7327 while (CurrentToken() == Token::kSTRING) { 7346 while (CurrentToken() == Token::kSTRING) {
7328 values->AddElement(new LiteralNode(token_index_, *CurrentLiteral())); 7347 values->AddElement(new LiteralNode(token_index_, *CurrentLiteral()));
7329 ConsumeToken(); 7348 ConsumeToken();
7330 if ((CurrentToken() != Token::kINTERPOL_VAR) && 7349 if ((CurrentToken() != Token::kINTERPOL_VAR) &&
7331 (CurrentToken() != Token::kINTERPOL_START)) { 7350 (CurrentToken() != Token::kINTERPOL_START)) {
7332 break; 7351 break;
7333 } 7352 }
7334 while ((CurrentToken() == Token::kINTERPOL_VAR) || 7353 while ((CurrentToken() == Token::kINTERPOL_VAR) ||
7335 (CurrentToken() == Token::kINTERPOL_START)) { 7354 (CurrentToken() == Token::kINTERPOL_START)) {
7336 AstNode* expr = NULL; 7355 AstNode* expr = NULL;
(...skipping 15 matching lines...) Expand all
7352 ArgumentListNode* interpolate_arg = 7371 ArgumentListNode* interpolate_arg =
7353 new ArgumentListNode(values->token_index()); 7372 new ArgumentListNode(values->token_index());
7354 interpolate_arg->Add(values); 7373 interpolate_arg->Add(values);
7355 primary = MakeStaticCall(kStringClassName, 7374 primary = MakeStaticCall(kStringClassName,
7356 kInterpolateName, 7375 kInterpolateName,
7357 interpolate_arg); 7376 interpolate_arg);
7358 return primary; 7377 return primary;
7359 } 7378 }
7360 7379
7361 7380
7381 // An import string literal consists of the concatenation of the next n tokens
7382 // that satisfy the EBNF grammar:
7383 // literal = kSTRING {{ interpol }+ kSTRING }
7384 // interpol = kINTERPOL_VAR
7385 // In other words, the scanner breaks down interpolated strings so that
7386 // a string literal always begins and ends with a kSTRING token, and
7387 // there are never two kSTRING tokens next to each other.
7388 String* Parser::ParseImportStringLiteral() {
7389 if ((CurrentToken() == Token::kSTRING) &&
7390 (LookaheadToken(1) != Token::kINTERPOL_VAR) &&
7391 (LookaheadToken(1) != Token::kINTERPOL_START)) {
7392 // Common case: no interpolation.
7393 String* result = CurrentLiteral();
7394 ConsumeToken();
7395 return result;
7396 }
7397 // String interpolation needed.
7398 String& result = String::ZoneHandle(String::New(""));
7399 String& resolved_name = String::Handle();
7400 while (CurrentToken() == Token::kSTRING) {
7401 result = String::Concat(result, *CurrentLiteral());
7402 ConsumeToken();
7403 if ((CurrentToken() != Token::kINTERPOL_VAR) &&
7404 (CurrentToken() != Token::kINTERPOL_START)) {
7405 break;
7406 }
7407 while ((CurrentToken() == Token::kINTERPOL_VAR) ||
7408 (CurrentToken() == Token::kINTERPOL_START)) {
7409 if (CurrentToken() == Token::kINTERPOL_START) {
7410 ConsumeToken();
7411 if (IsIdentifier()) {
7412 resolved_name = ResolveImportVar(token_index_, *CurrentLiteral());
7413 result = String::Concat(result, resolved_name);
7414 ConsumeToken();
7415 if (CurrentToken() != Token::kINTERPOL_END) {
7416 ErrorMsg("'}' expected");
7417 }
7418 ConsumeToken();
7419 } else {
7420 ErrorMsg("identifier expected");
7421 }
7422 } else {
7423 ASSERT(CurrentToken() == Token::kINTERPOL_VAR);
7424 resolved_name = ResolveImportVar(token_index_, *CurrentLiteral());
7425 result = String::Concat(result, resolved_name);
7426 ConsumeToken();
7427 }
7428 }
7429 // A string literal always ends with a kSTRING token.
7430 ASSERT(CurrentToken() == Token::kSTRING);
7431 }
7432 return &result;
7433 }
7434
7435
7362 AstNode* Parser::ParsePrimary() { 7436 AstNode* Parser::ParsePrimary() {
7363 TRACE_PARSER("ParsePrimary"); 7437 TRACE_PARSER("ParsePrimary");
7364 ASSERT(!is_top_level_); 7438 ASSERT(!is_top_level_);
7365 AstNode* primary = NULL; 7439 AstNode* primary = NULL;
7366 if (IsFunctionLiteral()) { 7440 if (IsFunctionLiteral()) {
7367 // The name of a literal function is visible from inside the function, but 7441 // The name of a literal function is visible from inside the function, but
7368 // must not collide with names in the scope declaring the literal. 7442 // must not collide with names in the scope declaring the literal.
7369 OpenBlock(); 7443 OpenBlock();
7370 primary = ParseFunctionStatement(true); 7444 primary = ParseFunctionStatement(true);
7371 CloseBlock(); 7445 CloseBlock();
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after
7760 void Parser::SkipQualIdent() { 7834 void Parser::SkipQualIdent() {
7761 ASSERT(IsIdentifier()); 7835 ASSERT(IsIdentifier());
7762 ConsumeToken(); 7836 ConsumeToken();
7763 if (CurrentToken() == Token::kPERIOD) { 7837 if (CurrentToken() == Token::kPERIOD) {
7764 ConsumeToken(); // Consume the kPERIOD token. 7838 ConsumeToken(); // Consume the kPERIOD token.
7765 ExpectIdentifier("identifier expected after '.'"); 7839 ExpectIdentifier("identifier expected after '.'");
7766 } 7840 }
7767 } 7841 }
7768 7842
7769 } // namespace dart 7843 } // namespace dart
OLDNEW
« no previous file with comments | « vm/parser.h ('k') | vm/raw_object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698