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

Unified Diff: runtime/vm/parser.cc

Issue 12210127: First stab at mixins in VM compiler (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/parser.cc
===================================================================
--- runtime/vm/parser.cc (revision 18475)
+++ runtime/vm/parser.cc (working copy)
@@ -291,7 +291,8 @@
parsed_function_(parsed_function),
innermost_function_(Function::Handle(parsed_function->function().raw())),
current_class_(Class::Handle(parsed_function->function().Owner())),
- library_(Library::Handle(current_class_.library())),
+ library_(Library::Handle(Class::Handle(
+ parsed_function->function().origin()).library())),
try_blocks_list_(NULL) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!current_function().IsNull());
@@ -1841,6 +1842,13 @@
initialized_fields->Add(&field);
}
intptr_t field_pos = field.token_pos();
+ if (current_class().raw() != field.origin()) {
+ const Class& origin_class = Class::Handle(field.origin());
+ if (origin_class.library() != library_.raw()) {
+ ErrorMsg("Cannot handle initialized mixin field '%s'"
+ "from imported library\n", field.ToCString());
+ }
+ }
SetPosition(field_pos);
ASSERT(IsIdentifier());
ConsumeToken();
@@ -2033,13 +2041,11 @@
const Class& cls = Class::Handle(func.Owner());
ASSERT(!cls.IsNull());
- if (CurrentToken() == Token::kCLASS) {
+ if (func.IsImplicitConstructor()) {
// Special case: implicit constructor.
// The parser adds an implicit default constructor when a class
// does not have any explicit constructor or factory (see
- // Parser::AddImplicitConstructor). The token position of this implicit
- // constructor points to the 'class' keyword, which is followed
- // by the name of the class (which is also the constructor name).
+ // Parser::AddImplicitConstructor).
// There is no source text to parse. We just build the
// sequence node by hand.
return MakeImplicitConstructor(func);
@@ -3244,8 +3250,11 @@
String::Handle(type.UserVisibleName()).ToCString());
}
super_type ^= type.raw();
+ if (CurrentToken() == Token::kWITH) {
+ super_type = ParseMixins(super_type);
+ }
} else {
- // No extends clause: Implicitly extend Object.
+ // No extends clause: implicitly extend Object.
super_type = Type::ObjectType();
}
ASSERT(!super_type.IsNull());
@@ -3270,13 +3279,13 @@
cls.set_is_abstract();
}
- // Add an implicit constructor if no explicit constructor is present. No
- // implicit constructors are needed for patch classes.
- if (!members.has_constructor() && !is_patch) {
- AddImplicitConstructor(&members);
- }
CheckConstructors(&members);
+ // Need to compute this here since MakeArray() will clear the
+ // functions array in members.
+ const bool need_implicit_constructor =
+ !members.has_constructor() && !is_patch;
+
Array& array = Array::Handle();
array = Array::MakeArray(members.fields());
cls.SetFields(array);
@@ -3285,6 +3294,12 @@
array = Array::MakeArray(members.functions());
cls.SetFunctions(array);
+ // Add an implicit constructor if no explicit constructor is present.
+ // No implicit constructors are needed for patch classes.
+ if (need_implicit_constructor) {
+ AddImplicitConstructor(cls);
+ }
+
if (!is_patch) {
pending_classes.Add(cls, Heap::kOld);
} else {
@@ -3300,15 +3315,14 @@
}
-// Add an implicit constructor if no explicit constructor is present.
-void Parser::AddImplicitConstructor(ClassDesc* class_desc) {
- // The implicit constructor is unnamed, has no explicit parameter,
- // and contains a supercall in the initializer list.
- String& ctor_name = String::ZoneHandle(
- String::Concat(class_desc->class_name(), Symbols::Dot()));
+// Add an implicit constructor to the given class.
+void Parser::AddImplicitConstructor(const Class& cls) {
+ // The implicit constructor is unnamed, has no explicit parameter.
+ String& ctor_name = String::ZoneHandle(cls.Name());
+ ctor_name = String::Concat(ctor_name, Symbols::Dot());
ctor_name = Symbols::New(ctor_name);
- // The token position for the implicit constructor is the 'class'
- // keyword of the constructor's class.
+ // To indicate that this is an implicit constructor, we set the
+ // token position is the same as the token position of the class.
Function& ctor = Function::Handle(
Function::New(ctor_name,
RawFunction::kConstructor,
@@ -3316,22 +3330,23 @@
/* is_const = */ false,
/* is_abstract = */ false,
/* is_external = */ false,
- current_class(),
- class_desc->token_pos()));
+ cls,
+ cls.token_pos()));
ParamList params;
- // Add implicit 'this' parameter.
- ASSERT(current_class().raw() == ctor.Owner());
- params.AddReceiver(ReceiverType(TokenPos()));
+ // Add implicit 'this' parameter. We don't care about the specific type
+ // and just specify dynamic.
+ const Type& receiver_type = Type::Handle(Type::DynamicType());
+ params.AddReceiver(&receiver_type);
// Add implicit parameter for construction phase.
- params.AddFinalParameter(TokenPos(),
+ params.AddFinalParameter(cls.token_pos(),
&Symbols::PhaseParameter(),
&Type::ZoneHandle(Type::SmiType()));
AddFormalParamsToFunction(&params, ctor);
// The body of the constructor cannot modify the type of the constructed
// instance, which is passed in as the receiver.
- ctor.set_result_type(*((*params.parameters)[0].type));
- class_desc->AddFunction(ctor);
+ ctor.set_result_type(receiver_type);
+ cls.AddFunction(ctor);
}
@@ -3376,6 +3391,75 @@
}
+void Parser::ParseMixinTypedef(const GrowableObjectArray& pending_classes) {
+ TRACE_PARSER("ParseMixinTypedef");
+ const intptr_t classname_pos = TokenPos();
+ String& class_name = *ExpectUserDefinedTypeIdentifier("class name expected");
+ if (FLAG_trace_parser) {
+ OS::Print("toplevel parsing typedef class '%s'\n", class_name.ToCString());
+ }
+ const Object& obj = Object::Handle(library_.LookupLocalObject(class_name));
+ if (!obj.IsNull()) {
+ ErrorMsg(classname_pos, "'%s' is already defined",
+ class_name.ToCString());
+ }
+ const Class& mixin_application =
+ Class::Handle(Class::New(class_name, script_, classname_pos));
+ library_.AddClass(mixin_application);
+ set_current_class(mixin_application);
+ ParseTypeParameters(mixin_application);
+ ExpectToken(Token::kASSIGN);
+
+ if (CurrentToken() == Token::kABSTRACT) {
+ mixin_application.set_is_abstract();
+ ConsumeToken();
+ }
+
+ const intptr_t supertype_pos = TokenPos();
+ const AbstractType& type =
+ AbstractType::Handle(ParseType(ClassFinalizer::kTryResolve));
+ if (type.IsTypeParameter()) {
+ ErrorMsg(supertype_pos,
+ "class '%s' may not extend type parameter '%s'",
+ class_name.ToCString(),
+ String::Handle(type.UserVisibleName()).ToCString());
+ }
+ Type& mixin_super_type = Type::Handle();
+ mixin_super_type ^= type.raw();
+
+ if (CurrentToken() != Token::kWITH) {
+ ErrorMsg("mixin application 'with Type' expected");
+ }
+
+ Type& mixin_application_type = Type::Handle(ParseMixins(mixin_super_type));
+ // The result of ParseMixins() is a chain of super classes that is the
+ // result of the mixin composition 'S with M1, M2, ...'. The mixin
+ // application classes are anonymous (i.e. not registered in the current
+ // library). We steal the super type and mixin type from the bottom of
+ // the chain and add it to the named mixin application class. The bottom
+ // anonymous class in the chain is thrown away.
+ const Class& anon_mixin_app_class =
+ Class::Handle(mixin_application_type.type_class());
+ mixin_application.set_super_type(
+ Type::Handle(anon_mixin_app_class.super_type()));
+ mixin_application.set_mixin(Type::Handle(anon_mixin_app_class.mixin()));
+ const Array& interfaces = Array::Handle(anon_mixin_app_class.interfaces());
+ mixin_application.set_interfaces(interfaces);
+ AddImplicitConstructor(mixin_application);
+
+ if (CurrentToken() == Token::kIMPLEMENTS) {
+ Array& interfaces = Array::Handle();
+ const intptr_t interfaces_pos = TokenPos();
+ const Type& super_type = Type::Handle(mixin_application.super_type());
+ interfaces = ParseInterfaceList(super_type);
+ AddInterfaces(interfaces_pos, mixin_application, interfaces);
+ }
+
+ pending_classes.Add(mixin_application, Heap::kOld);
+ ExpectSemicolon();
+}
+
+
// Look ahead to detect if we are seeing ident [ TypeParameters ] "(".
// We need this lookahead to distinguish between the optional return type
// and the alias name of a function type alias.
@@ -3397,11 +3481,34 @@
}
-void Parser::ParseFunctionTypeAlias(
- const GrowableObjectArray& pending_classes) {
- TRACE_PARSER("ParseFunctionTypeAlias");
+// Look ahead to detect if we are seeing ident [ TypeParameters ] "=".
+// Token position remains unchanged.
+bool Parser::IsMixinTypedef() {
+ if (IsIdentifier() && (LookaheadToken(1) == Token::kASSIGN)) {
+ return true;
+ }
+ const intptr_t saved_pos = TokenPos();
+ bool is_mixin_def = false;
+ if (IsIdentifier() && (LookaheadToken(1) == Token::kLT)) {
+ ConsumeToken();
+ if (TryParseTypeParameter() && (CurrentToken() == Token::kASSIGN)) {
+ is_mixin_def = true;
+ }
+ }
+ SetPosition(saved_pos);
+ return is_mixin_def;
+}
+
+
+void Parser::ParseTypedef(const GrowableObjectArray& pending_classes) {
+ TRACE_PARSER("ParseTypedef");
ExpectToken(Token::kTYPEDEF);
+ if (IsMixinTypedef()) {
+ ParseMixinTypedef(pending_classes);
+ return;
+ }
+
// Parse the result type of the function type.
AbstractType& result_type = Type::Handle(Type::DynamicType());
if (CurrentToken() == Token::kVOID) {
@@ -3683,8 +3790,7 @@
// Parse and return an array of interface types.
RawArray* Parser::ParseInterfaceList(const Type& super_type) {
TRACE_PARSER("ParseInterfaceList");
- ASSERT((CurrentToken() == Token::kIMPLEMENTS) ||
- (CurrentToken() == Token::kEXTENDS));
+ ASSERT(CurrentToken() == Token::kIMPLEMENTS);
const GrowableObjectArray& interfaces =
GrowableObjectArray::Handle(GrowableObjectArray::New());
String& interface_name = String::Handle();
@@ -3698,6 +3804,9 @@
interface = ParseType(ClassFinalizer::kTryResolve);
interface_name = interface.UserVisibleName();
if (interface_name.Equals(super_type_name)) {
+ // TODO(hausner): I think this check is not necessary. There is
+ // no such restriction. If the check is removed, the 'super_type'
+ // parameter to this function can be eliminated.
ErrorMsg(interface_pos, "class may not extend and implement '%s'",
interface_name.ToCString());
}
@@ -3715,6 +3824,72 @@
}
+RawType* Parser::ParseMixins(const Type& super_type) {
+ TRACE_PARSER("ParseMixins");
+ ASSERT(CurrentToken() == Token::kWITH);
+
+ // TODO(hausner): Remove this restriction.
+ if (super_type.arguments() != AbstractTypeArguments::null()) {
+ ErrorMsg(super_type.token_pos(),
+ "super class of mixin may not have type arguments");
+ }
+
+ AbstractType& mixin_type = AbstractType::Handle();
+ AbstractTypeArguments& mixin_type_arguments =
+ AbstractTypeArguments::Handle();
+ Class& mixin_application = Class::Handle();
+ Type& mixin_application_type = Type::Handle();
+ Type& mixin_super_type = Type::Handle(super_type.raw());
+ Array& mixin_application_interfaces = Array::Handle();
+ const TypeArguments& no_type_arguments = TypeArguments::Handle();
+ do {
+ ConsumeToken();
+ const intptr_t mixin_pos = TokenPos();
+ mixin_type = ParseType(ClassFinalizer::kTryResolve);
+ if (mixin_type.IsTypeParameter()) {
+ ErrorMsg(mixin_pos,
+ "mixin type '%s' may not be a type parameter",
+ String::Handle(mixin_type.UserVisibleName()).ToCString());
+ }
+ // TODO(hausner): Remove this check once we handle mixins with type
+ // arguments.
+ mixin_type_arguments = mixin_type.arguments();
+ if (!mixin_type_arguments.IsNull()) {
+ ErrorMsg(mixin_pos,
+ "mixin type '%s' may not have type arguments",
+ String::Handle(mixin_type.UserVisibleName()).ToCString());
+ }
+
+ // The name of the mixin application class is a combination of
+ // the superclass and mixin class.
+ String& mixin_app_name = String::Handle();
+ mixin_app_name = mixin_super_type.Name();
+ mixin_app_name = String::Concat(mixin_app_name, Symbols::Ampersand());
+ mixin_app_name = String::Concat(mixin_app_name,
+ String::Handle(mixin_type.Name()));
+ mixin_app_name = Symbols::New(mixin_app_name);
+
+ mixin_application = Class::New(mixin_app_name, script_, mixin_pos);
+ mixin_application.set_super_type(mixin_super_type);
+ mixin_application.set_mixin(Type::Cast(mixin_type));
+ mixin_application.set_library(library_);
+ AddImplicitConstructor(mixin_application);
+ // Add the mixin type to the interfaces that the mixin application
+ // class implements. This is necessary so that type tests work.
+ mixin_application_interfaces = Array::New(1);
+ mixin_application_interfaces.SetAt(0, mixin_type);
+ mixin_application.set_interfaces(mixin_application_interfaces);
+
+ // TODO(hausner): Need to support type arguments.
+ mixin_application_type = Type::New(mixin_application,
+ no_type_arguments,
+ Scanner::kDummyTokenIndex);
+ mixin_super_type = mixin_application_type.raw();
+ } while (CurrentToken() == Token::kCOMMA);
+ return mixin_application_type.raw();
+}
+
+
// Add 'interface' to 'interface_list' if it is not already in the list.
// An error is reported if the interface conflicts with an interface already in
// the list with the same class and same type arguments.
@@ -4449,7 +4624,7 @@
} else if ((CurrentToken() == Token::kTYPEDEF) &&
(LookaheadToken(1) != Token::kLPAREN)) {
set_current_class(toplevel_class);
- ParseFunctionTypeAlias(pending_classes);
+ ParseTypedef(pending_classes);
} else if ((CurrentToken() == Token::kABSTRACT) &&
(LookaheadToken(1) == Token::kCLASS)) {
ParseClassDefinition(pending_classes);
@@ -9475,6 +9650,14 @@
ErrorMsg("class '%s' does not have a superclass",
String::Handle(current_class().Name()).ToCString());
}
+ if (current_class().mixin() != Type::null()) {
+ const Type& mixin_type = Type::Handle(current_class().mixin());
+ if (mixin_type.type_class() == current_function().origin()) {
+ ErrorMsg("class '%s' may not use super "
+ "because it is used as mixin class",
+ String::Handle(current_class().Name()).ToCString());
+ }
+ }
ConsumeToken();
if (CurrentToken() == Token::kPERIOD) {
ConsumeToken();
« no previous file with comments | « runtime/vm/parser.h ('k') | runtime/vm/raw_object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698