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

Unified Diff: runtime/vm/parser.cc

Issue 1234883005: Implement tear-off closure operator # (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Address review comments Created 5 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/resolver.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/parser.cc
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index a8671215f191128cef668fb109dcac792140591c..ce6dec46202873d52a54b104ee486b62f2b08928 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -846,7 +846,6 @@ void Parser::ParseFunction(ParsedFunction* parsed_function) {
switch (func.kind()) {
case RawFunction::kClosureFunction:
if (func.IsImplicitClosureFunction()) {
- parser.SkipFunctionPreamble();
node_sequence =
parser.ParseImplicitClosure(func, &default_parameter_values);
break;
@@ -1287,26 +1286,35 @@ SequenceNode* Parser::ParseInstanceSetter(const Function& func) {
SequenceNode* Parser::ParseImplicitClosure(const Function& func,
Array* default_values) {
TRACE_PARSER("ParseImplicitClosure");
-
intptr_t token_pos = func.token_pos();
OpenFunctionBlock(func);
ParamList params;
-
params.AddFinalParameter(
token_pos,
&Symbols::ClosureParameter(),
&Type::ZoneHandle(Type::DynamicType()));
- const bool allow_explicit_default_values = true;
- ParseFormalParameterList(allow_explicit_default_values, false, &params);
- SetupDefaultsForOptionalParams(&params, default_values);
-
- // Getters can't be closurized. If supported, they need special
- // handling of the parameters as in ParseFunc.
const Function& parent = Function::ZoneHandle(func.parent_function());
- ASSERT(!parent.IsGetterFunction());
+ if (parent.IsImplicitSetterFunction()) {
+ const intptr_t ident_pos = func.token_pos();
+ ASSERT(IsIdentifier());
+ const String& field_name = *CurrentLiteral();
+ const Class& field_class = Class::ZoneHandle(Z, parent.Owner());
+ const Field& field =
+ Field::ZoneHandle(Z, field_class.LookupInstanceField(field_name));
+ const AbstractType& field_type = AbstractType::ZoneHandle(Z, field.type());
+ params.AddFinalParameter(ident_pos,
+ &Symbols::Value(),
+ &field_type);
+ ASSERT(func.num_fixed_parameters() == 2); // closure, value.
+ } else if (!parent.IsGetterFunction() && !parent.IsImplicitGetterFunction()) {
+ const bool allow_explicit_default_values = true;
+ SkipFunctionPreamble();
+ ParseFormalParameterList(allow_explicit_default_values, false, &params);
+ SetupDefaultsForOptionalParams(&params, default_values);
+ }
// Populate function scope with the formal parameters.
LocalScope* scope = current_block_->scope;
@@ -3431,8 +3439,9 @@ void Parser::SkipInitializers() {
RawLibraryPrefix* Parser::ParsePrefix() {
ASSERT(IsIdentifier());
// A library prefix can never stand by itself. It must be followed by
- // a period.
- if (LookaheadToken(1) != Token::kPERIOD) {
+ // a period or a hash mark (for closurization).
+ Token::Kind next_token = LookaheadToken(1);
+ if ((next_token != Token::kPERIOD) && (next_token != Token::kHASH)) {
return LibraryPrefix::null();
}
const String& ident = *CurrentLiteral();
@@ -3459,10 +3468,8 @@ RawLibraryPrefix* Parser::ParsePrefix() {
return LibraryPrefix::null();
}
- // We have a name that is not shadowed, followed by a period.
- // Consume the identifier and the period.
- ConsumeToken();
- ASSERT(CurrentToken() == Token::kPERIOD); // We checked above.
+ // We have a name that is not shadowed, followed by a period or #.
+ // Consume the identifier, let the caller consume the . or #.
ConsumeToken();
return prefix.raw();
}
@@ -11318,13 +11325,156 @@ AstNode* Parser::ParseSelectors(AstNode* primary, bool is_cascade) {
}
+// Closurization e#m of getter, setter, method or operator.
+AstNode* Parser::ParseClosurization(AstNode* primary) {
+ ExpectToken(Token::kHASH);
+ intptr_t property_pos = TokenPos();
+ bool is_setter_name = false;
+
+ String& extractor_name = String::ZoneHandle(Z);
+ if (IsIdentifier()) {
+ extractor_name = CurrentLiteral()->raw();
+ ConsumeToken();
+ if (CurrentToken() == Token::kASSIGN) {
+ ConsumeToken();
+ is_setter_name = true;
+ }
+ } else if (Token::CanBeOverloaded(CurrentToken())) {
+ extractor_name = String::New(Token::Str(CurrentToken()));
+ ConsumeToken();
+ } else {
+ ReportError("identifier or operator expected");
+ }
+
+ if (primary->IsPrimaryNode() && primary->AsPrimaryNode()->IsSuper()) {
+ // TODO(hausner): implement super#m
+ ReportError("closurization of super method not yet supported");
+ }
+
+ // Handle closurization of top-level names from library prefixes, P#m
+ if (primary->IsLiteralNode() &&
+ primary->AsLiteralNode()->literal().IsLibraryPrefix()) {
+ const LibraryPrefix& prefix =
+ LibraryPrefix::Cast(primary->AsLiteralNode()->literal());
+ Object& obj = Object::Handle(Z);
+ const bool is_private_name =
+ (extractor_name.CharAt(0) == Library::kPrivateIdentifierStart);
+ if (!is_private_name) {
+ // Private names are not exported by libraries. The name mangling
+ // of private names with a library-specific suffix usually ensures
+ // that _x in library A is not found when looked up from library B.
+ // In the pathological case where a library imports itself with
+ // a prefix, the name mangling does not help in hiding the private
+ // name, so we explicitly prevent lookup of private names here.
+ obj = prefix.LookupObject(extractor_name);
+ }
+ if (!prefix.is_loaded() && (parsed_function() != NULL)) {
+ // Remember that this function depends on an import prefix of an
+ // unloaded deferred library.
+ parsed_function()->AddDeferredPrefix(prefix);
+ }
+
+ if (obj.IsFunction()) {
+ const Function& func = Function::Cast(obj);
+ if (!func.IsSetterFunction() || is_setter_name) {
+ return CreateImplicitClosureNode(func, property_pos, NULL);
+ }
+ } else if (obj.IsField()) {
+ const Field& field = Field::Cast(obj);
+ if (is_setter_name && !field.is_final()) {
+ Instance& setter_closure = Instance::ZoneHandle(field.SetterClosure());
+ return new(Z) LiteralNode(property_pos, setter_closure);
+ }
+ if (!is_setter_name) {
+ Instance& getter_closure = Instance::ZoneHandle(field.GetterClosure());
+ return new(Z) LiteralNode(property_pos, getter_closure);
+ }
+ }
+ return ThrowNoSuchMethodError(property_pos,
+ current_class(),
+ extractor_name,
+ NULL, // No arguments.
+ InvocationMirror::kTopLevel,
+ is_setter_name
+ ? InvocationMirror::kSetter
+ : InvocationMirror::kMethod,
+ NULL); // No existing function.
+ }
+
+ // Handle closurization of static properties of classes, C#n.
+ if (primary->IsPrimaryNode() &&
+ primary->AsPrimaryNode()->primary().IsClass()) {
+ const Class& cls = Class::Cast(primary->AsPrimaryNode()->primary());
+ const Field& field =
+ Field::Handle(Z, cls.LookupStaticField(extractor_name));
+ if (!field.IsNull()) {
+ if (is_setter_name) {
+ extractor_name = Field::SetterName(extractor_name);
+ if (!field.is_final()) {
+ const Instance& setter_closure =
+ Instance::ZoneHandle(Z, field.SetterClosure());
+ ASSERT(setter_closure.IsClosure());
+ // Note: the created closure is cached after it's created
+ // once. If eager compilation is desired, the compiler can
+ // be invoked here. The same applies for getters below.
+ return new(Z) LiteralNode(property_pos, setter_closure);
+ }
+ } else {
+ const Instance& getter_closure =
+ Instance::ZoneHandle(Z, field.GetterClosure());
+ ASSERT(getter_closure.IsClosure());
+ return new(Z) LiteralNode(property_pos, getter_closure);
+ }
+ } else {
+ Function& func = Function::Handle(Z);
+ if (is_setter_name) {
+ extractor_name = Field::SetterName(extractor_name);
+ func = cls.LookupStaticFunction(extractor_name);
+ } else {
+ func = cls.LookupStaticFunction(extractor_name);
+ if (func.IsNull()) {
+ const String& getter_name =
+ String::Handle(Z, Field::GetterName(extractor_name));
+ func = cls.LookupStaticFunction(getter_name);
+ }
+ }
+ if (!func.IsNull()) {
+ return CreateImplicitClosureNode(func, property_pos, NULL);
+ }
+ }
+ return ThrowNoSuchMethodError(property_pos,
+ cls,
+ extractor_name,
+ NULL, // No arguments.
+ InvocationMirror::kStatic,
+ is_setter_name
+ ? InvocationMirror::kSetter
+ : InvocationMirror::kMethod,
+ NULL); // No existing function.
+ }
+
+ // Closurization of instance getter, setter, method or operator.
+ if (is_setter_name) {
+ extractor_name = String::Concat(Symbols::SetterPrefix(), extractor_name);
+ }
+ extractor_name = String::Concat(Symbols::HashMark(), extractor_name);
+ extractor_name = Symbols::New(extractor_name);
+ return new(Z) InstanceGetterNode(property_pos, primary, extractor_name);
+}
+
+
AstNode* Parser::ParsePostfixExpr() {
TRACE_PARSER("ParsePostfixExpr");
String* expr_ident =
Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL;
const intptr_t expr_pos = TokenPos();
AstNode* expr = ParsePrimary();
- expr = ParseSelectors(expr, false);
+ if (CurrentToken() == Token::kHASH) {
+ expr = LoadFieldIfUnresolved(expr);
+ expr = ParseClosurization(expr);
+ } else {
+ expr = ParseSelectors(expr, false);
+ }
if (IsIncrementOperator(CurrentToken())) {
TRACE_PARSER("IncrementOperator");
if (!IsLegalAssignableSyntax(expr, TokenPos())) {
@@ -12006,6 +12156,9 @@ RawAbstractType* Parser::ParseType(
SkipQualIdent();
} else {
*prefix = ParsePrefix();
+ if (!prefix->IsNull()) {
+ ExpectToken(Token::kPERIOD);
+ }
type_name = CurrentLiteral()->raw();
ConsumeToken();
@@ -12631,14 +12784,19 @@ AstNode* Parser::ParseNewOperator(Token::Kind op_kind) {
intptr_t type_pos = TokenPos();
// Can't allocate const objects of a deferred type.
const bool allow_deferred_type = !is_const;
- const bool consume_unresolved_prefix = (LookaheadToken(3) == Token::kLT) ||
- (LookaheadToken(3) == Token::kPERIOD);
+ const Token::Kind la3 = LookaheadToken(3);
+ const bool consume_unresolved_prefix =
+ (la3 == Token::kLT) || (la3 == Token::kPERIOD) || (la3 == Token::kHASH);
+
LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(Z);
AbstractType& type = AbstractType::Handle(Z,
ParseType(ClassFinalizer::kCanonicalizeWellFormed,
allow_deferred_type,
consume_unresolved_prefix,
&prefix));
+ if (CurrentToken() == Token::kHASH) {
+ ReportError("constructor closurization not yet supported");
+ }
if (FLAG_load_deferred_eagerly &&
!prefix.IsNull() && prefix.is_deferred_load() && !prefix.is_loaded()) {
// Add runtime check.
@@ -13073,6 +13231,14 @@ AstNode* Parser::ParsePrimary() {
} else if (IsIdentifier()) {
intptr_t qual_ident_pos = TokenPos();
const LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(Z, ParsePrefix());
+ if (!prefix.IsNull()) {
+ if (CurrentToken() == Token::kHASH) {
+ // Closurization of top-level entity in prefix scope.
+ return new(Z) LiteralNode(qual_ident_pos, prefix);
+ } else {
+ ExpectToken(Token::kPERIOD);
+ }
+ }
String& ident = *CurrentLiteral();
ConsumeToken();
if (prefix.IsNull()) {
@@ -13434,6 +13600,11 @@ void Parser::SkipNewOperator() {
ConsumeToken(); // Skip new or const keyword.
if (IsIdentifier()) {
SkipType(false);
+ SkipIf(Token::kHASH);
+ if (CurrentToken() == Token::kPERIOD) {
+ ConsumeToken();
+ ExpectIdentifier("identifier expected");
+ }
if (CurrentToken() == Token::kLPAREN) {
SkipActualParameters();
return;
@@ -13552,6 +13723,16 @@ void Parser::SkipSelectors() {
void Parser::SkipPostfixExpr() {
SkipPrimary();
+ if (CurrentToken() == Token::kHASH) {
+ if (IsIdentifier()) {
+ ConsumeToken();
+ SkipIf(Token::kASSIGN);
+ } else if (Token::CanBeOverloaded(CurrentToken())) {
+ ConsumeToken();
+ } else {
+ ReportError("identifier or operator expected");
+ }
+ }
SkipSelectors();
if (IsIncrementOperator(CurrentToken())) {
ConsumeToken();
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/resolver.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698