Add Dart_Invoke, which will replace Dart_InvokeDynamic and Dart_InvokeStatic.

Fixed Dart_SetField to allow us to set a field to null.
Review URL: https://chromiumcodereview.appspot.com//9608024

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@5433 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
turnidge@google.com 2012-03-13 19:49:48 +00:00
parent cd8cdc5fe8
commit 3d363b570f
3 changed files with 336 additions and 10 deletions

View file

@ -1655,6 +1655,34 @@ DART_EXPORT void Dart_ClosureSetSmrck(Dart_Handle object, int64_t value);
// --- Methods and Fields ---
/**
* Invokes a method or function.
*
* The 'target' parameter may be an object, class, or library. If
* 'target' is an object, then this function will invoke an instance
* method. If 'target' is a class, then this function will invoke a
* static method. If 'target' is a library, then this function will
* invoke a top-level function from that library.
*
* This function ignores visibility (leading underscores in names).
*
* May generate an unhandled exception error.
*
* \param target An object, class, or library.
* \param name The name of the function or method to invoke.
* \param number_of_arguments Size of the arguments array.
* \param arguments An array of arguments to the function.
*
* \return If the function or method is called and completes
* successfully, then the return value is returned. If an error
* occurs during execution, then an error handle is returned.
*/
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target,
Dart_Handle name,
int number_of_arguments,
Dart_Handle* arguments);
/**
* DEPRECATED: Use Dart_Invoke instead.
*
* Invokes a static method with the given arguments.
*
* May generate an unhandled exception error.
@ -1670,6 +1698,8 @@ DART_EXPORT Dart_Handle Dart_InvokeStatic(Dart_Handle library,
Dart_Handle* arguments);
/**
* DEPRECATED: Use Dart_Invoke instead.
*
* Invokes an instance method with the given arguments.
*
* May generate an unhandled exception error.
@ -1686,18 +1716,18 @@ DART_EXPORT Dart_Handle Dart_InvokeDynamic(Dart_Handle receiver,
/**
* Gets the value of a field.
*
* The 'container' parameter may actually be an object, class, or
* library. If 'container' is an object, then this function will
* access an instance field. If 'container' is a class, then this
* function will access a static field. If 'container' is a library,
* then this function will access a top-level variable.
* The 'container' parameter may be an object, class, or library. If
* 'container' is an object, then this function will access an
* instance field. If 'container' is a class, then this function will
* access a static field. If 'container' is a library, then this
* function will access a top-level variable.
*
* This function ignores field visibility (leading underscores in names).
*
* May generate an unhandled exception error.
*
* \param container An object, class, or library.
* \param name A field name
* \param name A field name.
*
* \return If no error occurs, then the value of the field is
* returned. Otherwise an error handle is returned.
@ -1719,8 +1749,8 @@ DART_EXPORT Dart_Handle Dart_GetField(Dart_Handle container,
* May generate an unhandled exception error.
*
* \param container An object, class, or library.
* \param name A field name
* \param value The new field value
* \param name A field name.
* \param value The new field value.
*
* \return A valid handle if no error occurs.
*/

View file

@ -2068,6 +2068,118 @@ DART_EXPORT void Dart_ClosureSetSmrck(Dart_Handle object, int64_t value) {
// --- Methods and Fields ---
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target,
Dart_Handle name,
int number_of_arguments,
Dart_Handle* arguments) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
const String& function_name = Api::UnwrapStringHandle(name);
if (function_name.IsNull()) {
RETURN_TYPE_ERROR(name, String);
}
if (number_of_arguments < 0) {
return Api::NewError(
"%s expects argument 'number_of_arguments' to be non-negative.",
CURRENT_FUNC);
}
// Check for malformed arguments in the arguments list.
GrowableArray<const Object*> dart_args(number_of_arguments);
for (int i = 0; i < number_of_arguments; i++) {
const Object& arg = Object::Handle(Api::UnwrapHandle(arguments[i]));
if (!arg.IsNull() && !arg.IsInstance()) {
if (arg.IsError()) {
return Api::NewLocalHandle(arg);
} else {
return Api::NewError(
"%s expects argument %d to be an instance of Object.",
CURRENT_FUNC, i);
}
}
dart_args.Add(&arg);
}
const Array& kNoArgNames = Array::Handle();
const Object& obj = Object::Handle(Api::UnwrapHandle(target));
if (obj.IsNull()) {
return Api::NewError("%s expects argument 'target' to be non-null.",
CURRENT_FUNC);
} else if (obj.IsInstance()) {
Instance& instance = Instance::Handle();
instance ^= obj.raw();
const Function& function = Function::Handle(
Resolver::ResolveDynamic(instance,
function_name,
(number_of_arguments + 1),
Resolver::kIsQualified));
if (function.IsNull()) {
const Type& type = Type::Handle(instance.GetType());
const String& cls_name = String::Handle(type.ClassName());
return Api::NewError("%s: did not find instance method '%s.%s'.",
CURRENT_FUNC,
cls_name.ToCString(),
function_name.ToCString());
}
const Object& result = Object::Handle(
DartEntry::InvokeDynamic(instance, function, dart_args, kNoArgNames));
return Api::NewLocalHandle(result);
} else if (obj.IsClass()) {
// Finalize all classes.
const char* msg = CheckIsolateState(isolate);
if (msg != NULL) {
return Api::NewError(msg);
}
Class& cls = Class::Handle();
cls ^= obj.raw();
const Function& function = Function::Handle(
Resolver::ResolveStatic(cls,
function_name,
number_of_arguments,
Array::Handle(),
Resolver::kIsQualified));
if (function.IsNull()) {
const String& cls_name = String::Handle(cls.Name());
return Api::NewError("%s: did not find static method '%s.%s'.",
CURRENT_FUNC,
cls_name.ToCString(),
function_name.ToCString());
}
const Object& result = Object::Handle(
DartEntry::InvokeStatic(function, dart_args, kNoArgNames));
return Api::NewLocalHandle(result);
} else if (obj.IsLibrary()) {
// Finalize all classes.
const char* msg = CheckIsolateState(isolate);
if (msg != NULL) {
return Api::NewError(msg);
}
Library& lib = Library::Handle();
lib ^= obj.raw();
const Function& function = Function::Handle(
lib.LookupLocalFunction(function_name));
if (function.IsNull()) {
return Api::NewError("%s: did not find top-level function '%s'.",
CURRENT_FUNC,
function_name.ToCString());
}
const Object& result = Object::Handle(
DartEntry::InvokeStatic(function, dart_args, kNoArgNames));
return Api::NewLocalHandle(result);
} else {
return Api::NewError(
"%s expects argument 'target' to be an object, class, or library.",
CURRENT_FUNC);
}
}
DART_EXPORT Dart_Handle Dart_InvokeStatic(Dart_Handle library_in,
Dart_Handle class_name_in,
Dart_Handle function_name_in,
@ -2390,10 +2502,14 @@ DART_EXPORT Dart_Handle Dart_SetField(Dart_Handle container,
if (field_name.IsNull()) {
RETURN_TYPE_ERROR(name, String);
}
const Instance& value_instance = Api::UnwrapInstanceHandle(value);
if (value_instance.IsNull()) {
// Since null is allowed for value, we don't use UnwrapInstanceHandle.
const Object& value_obj = Object::Handle(Api::UnwrapHandle(value));
if (!value_obj.IsNull() && !value_obj.IsInstance()) {
RETURN_TYPE_ERROR(value, Instance);
}
Instance& value_instance = Instance::Handle();
value_instance ^= value_obj.raw();
Field& field = Field::Handle();
Function& setter = Function::Handle();

View file

@ -2303,6 +2303,43 @@ TEST_CASE(FieldAccess) {
}
TEST_CASE(SetField_FunnyValue) {
const char* kScriptChars =
"var top;\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle name = Dart_NewString("top");
Dart_Handle args[1];
bool value;
// Test that you can set the field to a good value.
EXPECT_VALID(Dart_SetField(lib, name, Dart_True()));
Dart_Handle result = Dart_GetField(lib, name);
EXPECT_VALID(result);
EXPECT(Dart_IsBoolean(result));
EXPECT_VALID(Dart_BooleanValue(result, &value));
EXPECT(value);
// Test that you can set the field to null
EXPECT_VALID(Dart_SetField(lib, name, Dart_Null()));
result = Dart_GetField(lib, name);
EXPECT_VALID(result);
EXPECT(Dart_IsNull(result));
// Pass a non-instance handle.
result = Dart_SetField(lib, name, lib);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_SetField expects argument 'value' to be of type Instance.",
Dart_GetError(result));
// Pass an error handle. The error is contagious.
result = Dart_SetField(lib, name, Api::NewError("myerror"));
EXPECT(Dart_IsError(result));
EXPECT_STREQ("myerror", Dart_GetError(result));
}
TEST_CASE(FieldAccessOld) {
const char* kScriptChars =
"class Fields {\n"
@ -2958,6 +2995,149 @@ TEST_CASE(StaticFieldNotFound) {
}
TEST_CASE(Invoke) {
const char* kScriptChars =
"class BaseMethods {\n"
" inheritedMethod(arg) => 'inherited $arg';\n"
" static nonInheritedMethod(arg) => 'noninherited $arg';\n"
"}\n"
"\n"
"class Methods extends BaseMethods {\n"
" instanceMethod(arg) => 'instance $arg';\n"
" _instanceMethod(arg) => 'hidden instance $arg';\n"
" static staticMethod(arg) => 'static $arg';\n"
" static _staticMethod(arg) => 'hidden static $arg';\n"
"}\n"
"\n"
"topMethod(arg) => 'top $arg';\n"
"_topMethod(arg) => 'hidden top $arg';\n"
"\n"
"Methods test() {\n"
" return new Methods();\n"
"}\n";
// Shared setup.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("Methods"));
EXPECT_VALID(cls);
Dart_Handle instance = Dart_Invoke(lib, Dart_NewString("test"), 0, NULL);
EXPECT_VALID(instance);
Dart_Handle args[1];
args[0] = Dart_NewString("!!!");
Dart_Handle result;
Dart_Handle name;
const char* str;
// Instance method.
name = Dart_NewString("instanceMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
result = Dart_Invoke(instance, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("instance !!!", str);
// Hidden instance method.
name = Dart_NewString("_instanceMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
result = Dart_Invoke(instance, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hidden instance !!!", str);
// Inherited method.
name = Dart_NewString("inheritedMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
result = Dart_Invoke(instance, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("inherited !!!", str);
// Static method.
name = Dart_NewString("staticMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(cls, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("static !!!", str);
// Hidden static method.
name = Dart_NewString("_staticMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(cls, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hidden static !!!", str);
// Static non-inherited method. Not found at any level.
name = Dart_NewString("non_inheritedMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
// Top-Level method.
name = Dart_NewString("topMethod");
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(lib, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("top !!!", str);
// Hidden top-level method.
name = Dart_NewString("_topMethod");
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(lib, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hidden top !!!", str);
}
TEST_CASE(Invoke_FunnyArgs) {
const char* kScriptChars =
"test(arg) => 'hello $arg';\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle name = Dart_NewString("test");
Dart_Handle args[1];
const char* str;
// Make sure that valid args yield valid results.
args[0] = Dart_NewString("!!!");
Dart_Handle result = Dart_Invoke(lib, Dart_NewString("test"), 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hello !!!", str);
// Make sure that null is legal.
args[0] = Dart_Null();
result = Dart_Invoke(lib, Dart_NewString("test"), 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hello null", str);
// Pass a non-instance handle.
args[0] = lib;
result = Dart_Invoke(lib, Dart_NewString("test"), 1, args);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_Invoke expects argument 0 to be an instance of Object.",
Dart_GetError(result));
// Pass an error handle. The error is contagious.
args[0] = Api::NewError("myerror");
result = Dart_Invoke(lib, Dart_NewString("test"), 1, args);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("myerror", Dart_GetError(result));
}
TEST_CASE(InvokeDynamic) {
const char* kScriptChars =
"class InvokeDynamic {\n"