Index: runtime/vm/parser.cc |
=================================================================== |
--- runtime/vm/parser.cc (revision 10615) |
+++ runtime/vm/parser.cc (working copy) |
@@ -257,7 +257,7 @@ |
allow_function_literals_(true), |
current_function_(function), |
innermost_function_(Function::Handle(function.raw())), |
- current_class_(Class::Handle(current_function_.owner())), |
+ current_class_(Class::Handle(current_function_.Owner())), |
library_(Library::Handle(current_class_.library())), |
try_blocks_list_(NULL), |
expression_temp_(NULL) { |
@@ -656,8 +656,7 @@ |
ASSERT(isolate->long_jump_base()->IsSafeToJump()); |
ASSERT(parsed_function != NULL); |
const Function& func = parsed_function->function(); |
- const Class& cls = Class::Handle(isolate, func.owner()); |
- const Script& script = Script::Handle(isolate, cls.script()); |
+ const Script& script = Script::Handle(isolate, func.script()); |
Parser parser(script, func, func.token_pos()); |
SequenceNode* node_sequence = NULL; |
Array& default_parameter_values = Array::Handle(isolate, Array::null()); |
@@ -737,7 +736,7 @@ |
AddFormalParamsToScope(¶ms, current_block_->scope); |
const String& field_name = *ExpectIdentifier("field name expected"); |
- const Class& field_class = Class::Handle(func.owner()); |
+ const Class& field_class = Class::Handle(func.Owner()); |
const Field& field = |
Field::ZoneHandle(field_class.LookupStaticField(field_name)); |
@@ -842,7 +841,7 @@ |
SequenceNode* Parser::ParseInstanceGetter(const Function& func) { |
TRACE_PARSER("ParseInstanceGetter"); |
ParamList params; |
- ASSERT(current_class().raw() == func.owner()); |
+ ASSERT(current_class().raw() == func.Owner()); |
params.AddReceiver(ReceiverType(TokenPos())); |
ASSERT(func.num_fixed_parameters() == 1); // receiver. |
ASSERT(func.num_optional_parameters() == 0); |
@@ -859,7 +858,7 @@ |
// name of the field; |
ASSERT(IsIdentifier()); |
const String& field_name = *CurrentLiteral(); |
- const Class& field_class = Class::Handle(func.owner()); |
+ const Class& field_class = Class::Handle(func.Owner()); |
const Field& field = |
Field::ZoneHandle(field_class.LookupInstanceField(field_name)); |
@@ -882,13 +881,13 @@ |
// TokenPos() returns the function's token position which points to |
// the name of the field; we can use it to form the field_name. |
const String& field_name = *CurrentLiteral(); |
- const Class& field_class = Class::ZoneHandle(func.owner()); |
+ const Class& field_class = Class::ZoneHandle(func.Owner()); |
const Field& field = |
Field::ZoneHandle(field_class.LookupInstanceField(field_name)); |
const AbstractType& field_type = AbstractType::ZoneHandle(field.type()); |
ParamList params; |
- ASSERT(current_class().raw() == func.owner()); |
+ ASSERT(current_class().raw() == func.Owner()); |
params.AddReceiver(ReceiverType(TokenPos())); |
params.AddFinalParameter(TokenPos(), |
&String::ZoneHandle(Symbols::Value()), |
@@ -1188,7 +1187,7 @@ |
void Parser::CheckFunctionIsCallable(intptr_t token_pos, |
const Function& function) { |
- if (Class::Handle(function.owner()).is_interface()) { |
+ if (Class::Handle(function.Owner()).is_interface()) { |
ErrorMsg(token_pos, "cannot call function of interface '%s'", |
function.ToFullyQualifiedCString()); |
} |
@@ -1779,7 +1778,7 @@ |
// initializers. |
GrowableArray<FieldInitExpression> initializers; |
GrowableArray<Field*> initialized_fields; |
- Class& cls = Class::Handle(func.owner()); |
+ Class& cls = Class::Handle(func.Owner()); |
ParseInitializedInstanceFields(cls, &initializers, &initialized_fields); |
LocalVariable* receiver = new LocalVariable( |
@@ -1825,7 +1824,7 @@ |
ASSERT(!func.IsFactory()); |
ASSERT(!func.is_static()); |
ASSERT(!func.IsLocalFunction()); |
- const Class& cls = Class::Handle(func.owner()); |
+ const Class& cls = Class::Handle(func.Owner()); |
ASSERT(!cls.IsNull()); |
if (CurrentToken() == Token::kCLASS) { |
@@ -1847,7 +1846,7 @@ |
// Add implicit receiver parameter which is passed the allocated |
// but uninitialized instance to construct. |
- ASSERT(current_class().raw() == func.owner()); |
+ ASSERT(current_class().raw() == func.Owner()); |
params.AddReceiver(ReceiverType(TokenPos())); |
// Add implicit parameter for construction phase. |
@@ -2096,7 +2095,7 @@ |
// The first parameter of a factory is the AbstractTypeArguments vector of |
// the type of the instance to be allocated. |
if (!func.is_static() && !func.IsClosureFunction()) { |
- ASSERT(current_class().raw() == func.owner()); |
+ ASSERT(current_class().raw() == func.Owner()); |
params.AddReceiver(ReceiverType(TokenPos())); |
} else if (func.IsFactory()) { |
params.AddFinalParameter( |
@@ -2626,7 +2625,7 @@ |
current_class(), |
field->name_pos); |
ParamList params; |
- ASSERT(current_class().raw() == getter.owner()); |
+ ASSERT(current_class().raw() == getter.Owner()); |
params.AddReceiver(ReceiverType(TokenPos())); |
getter.set_result_type(*field->type); |
AddFormalParamsToFunction(¶ms, getter); |
@@ -2642,7 +2641,7 @@ |
current_class(), |
field->name_pos); |
ParamList params; |
- ASSERT(current_class().raw() == setter.owner()); |
+ ASSERT(current_class().raw() == setter.Owner()); |
params.AddReceiver(ReceiverType(TokenPos())); |
params.AddFinalParameter(TokenPos(), |
&String::ZoneHandle(Symbols::Value()), |
@@ -2925,6 +2924,13 @@ |
void Parser::ParseClassDefinition(const GrowableObjectArray& pending_classes) { |
TRACE_PARSER("ParseClassDefinition"); |
const intptr_t class_pos = TokenPos(); |
+ bool is_patch = false; |
+ if (is_patch_source() && |
+ (CurrentToken() == Token::kIDENT) && |
+ CurrentLiteral()->Equals("patch")) { |
+ ConsumeToken(); |
+ is_patch = true; |
+ } |
ExpectToken(Token::kCLASS); |
const intptr_t classname_pos = TokenPos(); |
String& class_name = *ExpectTypeIdentifier("class name expected"); |
@@ -2934,6 +2940,10 @@ |
Class& cls = Class::Handle(); |
Object& obj = Object::Handle(library_.LookupObject(class_name)); |
if (obj.IsNull()) { |
+ if (is_patch) { |
+ ErrorMsg(classname_pos, "missing class '%s' cannot be patched", |
+ class_name.ToCString()); |
+ } |
cls = Class::New(class_name, script_, classname_pos); |
library_.AddClass(cls); |
} else { |
@@ -2943,14 +2953,29 @@ |
} |
cls ^= obj.raw(); |
if (cls.is_interface()) { |
- ErrorMsg(classname_pos, "'%s' is already defined as interface", |
- class_name.ToCString()); |
- } else if (cls.functions() != Object::empty_array()) { |
+ ErrorMsg(classname_pos, "'%s' %s", |
+ class_name.ToCString(), |
+ is_patch ? |
+ "is already defined as interface" : |
+ "interface cannot be patched"); |
+ } else if (!is_patch && (cls.functions() != Object::empty_array())) { |
ErrorMsg(classname_pos, "class '%s' is already defined", |
class_name.ToCString()); |
siva
2012/08/15 00:16:04
I suppose it is an error to have multiple patch cl
Ivan Posva
2012/08/15 06:50:39
Currently this error cannot be identified as I am
|
+ } else if (is_patch) { |
+ String& patch = String::Handle(Symbols::New("patch ")); |
+ patch = String::Concat(patch, class_name); |
+ patch = Symbols::New(patch); |
+ cls = Class::New(patch, script_, classname_pos); |
+ } else { |
+ // Not patching a class, but it has been found. This must be one of the |
+ // pre-registered classes from object.cc or a duplicate definition. |
+ if (cls.functions() != Object::empty_array()) { |
+ ErrorMsg(classname_pos, "class '%s' is already defined", |
+ class_name.ToCString()); |
+ } |
siva
2012/08/15 00:16:04
There seems to be a duplication of this is already
Ivan Posva
2012/08/15 06:50:40
Merge-conflict resolution error. Thanks for notici
|
+ // Pre-registered classes need their scripts connected at this time. |
+ cls.set_script(script_); |
} |
- // Pre-registered classes need their scripts connected at this time. |
- cls.set_script(script_); |
} |
ASSERT(!cls.IsNull()); |
ASSERT(cls.functions() == Object::empty_array()); |
@@ -2996,7 +3021,10 @@ |
} |
ExpectToken(Token::kRBRACE); |
- CheckConstructors(&members); |
+ if (!is_patch) { |
+ // Do not install implicit constructors. |
hausner
2012/08/14 18:25:06
Why?
Ivan Posva
2012/08/15 06:50:40
If a patch class does not patch a constructor, it
|
+ CheckConstructors(&members); |
+ } |
Array& array = Array::Handle(); |
array = Array::MakeArray(members.fields()); |
@@ -3006,7 +3034,13 @@ |
array = Array::MakeArray(members.functions()); |
cls.SetFunctions(array); |
- pending_classes.Add(cls, Heap::kOld); |
+ if (!is_patch) { |
+ pending_classes.Add(cls, Heap::kOld); |
+ } else { |
+ // Lookup the patched class and apply the changes. |
+ obj = library_.LookupObject(class_name); |
+ Class::Cast(obj).ApplyPatch(cls); |
+ } |
} |
@@ -3034,7 +3068,7 @@ |
class_desc->token_pos())); |
ParamList params; |
// Add implicit 'this' parameter. |
- ASSERT(current_class().raw() == ctor.owner()); |
+ ASSERT(current_class().raw() == ctor.Owner()); |
params.AddReceiver(ReceiverType(TokenPos())); |
// Add implicit parameter for construction phase. |
params.AddFinalParameter( |
@@ -3714,7 +3748,7 @@ |
AbstractType& result_type = AbstractType::Handle(); |
if (is_patch_source() && |
(CurrentToken() == Token::kIDENT) && |
- (CurrentLiteral()->Equals("patch"))) { |
+ CurrentLiteral()->Equals("patch")) { |
ConsumeToken(); |
is_patch = true; |
} else if (CurrentToken() == Token::kEXTERNAL) { |
@@ -4006,6 +4040,11 @@ |
(LookaheadToken(1) == Token::kCLASS)) { |
ConsumeToken(); // Consume and ignore 'abstract'. |
ParseClassDefinition(pending_classes); |
+ } else if (is_patch_source() && |
+ (CurrentToken() == Token::kIDENT) && |
+ CurrentLiteral()->Equals("patch") && |
+ (LookaheadToken(1) == Token::kCLASS)) { |
+ ParseClassDefinition(pending_classes); |
} else { |
set_current_class(toplevel_class); |
if (IsVariableDeclaration()) { |
@@ -4168,7 +4207,7 @@ |
const Function& func) { |
func.set_is_native(true); |
TRACE_PARSER("ParseNativeFunctionBlock"); |
- const Class& cls = Class::Handle(func.owner()); |
+ const Class& cls = Class::Handle(func.Owner()); |
const int num_parameters = params->parameters->length(); |
const bool is_instance_closure = func.IsImplicitInstanceClosureFunction(); |
int num_params_for_resolution = num_parameters; |
@@ -7092,7 +7131,7 @@ |
String& func_name = String::ZoneHandle(func.name()); |
if (func.is_static()) { |
// Parse static function call. |
- Class& cls = Class::Handle(func.owner()); |
+ Class& cls = Class::Handle(func.Owner()); |
selector = ParseStaticCall(cls, func_name, primary_pos); |
} else { |
// Dynamic function call on implicit "this" parameter. |
@@ -7648,7 +7687,7 @@ |
return new StaticGetterNode(qual_ident.ident_pos, |
NULL, |
false, |
- Class::ZoneHandle(func.owner()), |
+ Class::ZoneHandle(func.Owner()), |
*qual_ident.ident); |
} |
if (qual_ident.lib_prefix != NULL) { |
@@ -7844,7 +7883,7 @@ |
intptr_t pos, Function& constructor, |
const AbstractTypeArguments& type_arguments) { |
if (!type_arguments.IsNull()) { |
- const Class& constructor_class = Class::Handle(constructor.owner()); |
+ const Class& constructor_class = Class::Handle(constructor.Owner()); |
ASSERT(!constructor_class.IsNull()); |
ASSERT(constructor_class.is_finalized()); |
// Do not report the expected vs. actual number of type arguments, because |