| Index: runtime/vm/dart_api_impl.cc
|
| ===================================================================
|
| --- runtime/vm/dart_api_impl.cc (revision 9490)
|
| +++ runtime/vm/dart_api_impl.cc (working copy)
|
| @@ -34,6 +34,7 @@
|
|
|
| ThreadLocalKey Api::api_native_key_ = Thread::kUnsetThreadLocalKey;
|
|
|
| +
|
| const char* CanonicalFunction(const char* func) {
|
| if (strncmp(func, "dart::", 6) == 0) {
|
| return func + 6;
|
| @@ -42,6 +43,7 @@
|
| }
|
| }
|
|
|
| +
|
| #define RETURN_TYPE_ERROR(isolate, dart_handle, type) \
|
| do { \
|
| const Object& tmp = \
|
| @@ -58,6 +60,86 @@
|
| } while (0)
|
|
|
|
|
| +#define RETURN_NULL_ERROR(parameter) \
|
| + return Api::NewError("%s expects argument '%s' to be non-null.", \
|
| + CURRENT_FUNC, #parameter);
|
| +
|
| +
|
| +// Takes a vm internal name and makes it suitable for external user.
|
| +//
|
| +// Examples:
|
| +//
|
| +// Internal getter and setter prefices are removed:
|
| +//
|
| +// get:foo -> foo
|
| +// set:foo -> foo
|
| +//
|
| +// Private name mangling is removed, possibly twice:
|
| +//
|
| +// _ReceivePortImpl@6be832b -> _ReceivePortImpl
|
| +// _ReceivePortImpl@6be832b._internal@6be832b -> +ReceivePortImpl._internal
|
| +//
|
| +// The trailing . on the default constructor name is dropped:
|
| +//
|
| +// List. -> List
|
| +//
|
| +// And so forth:
|
| +//
|
| +// get:foo@6be832b -> foo
|
| +// _MyClass@6b3832b. -> _MyClass
|
| +// _MyClass@6b3832b.named -> _MyClass.named
|
| +//
|
| +static RawString* IdentifierPrettyName(Isolate* isolate, const String& name) {
|
| + intptr_t len = name.Length();
|
| + intptr_t start = 0;
|
| + intptr_t at_pos = len; // Position of '@' in the name.
|
| + intptr_t dot_pos = len; // Position of '.' in the name.
|
| +
|
| + for (int i = 0; i < name.Length(); i++) {
|
| + if (name.CharAt(i) == ':') {
|
| + ASSERT(start == 0);
|
| + start = i + 1;
|
| + } else if (name.CharAt(i) == '@') {
|
| + ASSERT(at_pos == len);
|
| + at_pos = i;
|
| + } else if (name.CharAt(i) == '.') {
|
| + dot_pos = i;
|
| + break;
|
| + }
|
| + }
|
| + intptr_t limit = (at_pos < dot_pos ? at_pos : dot_pos);
|
| + if (start == 0 && limit == len) {
|
| + // This name is fine as it is.
|
| + return name.raw();
|
| + }
|
| +
|
| + String& result = String::Handle(isolate);
|
| + result = String::SubString(name, start, (limit - start));
|
| +
|
| + // Look for a second '@' now to correctly handle names like
|
| + // "_ReceivePortImpl@6be832b._internal@6be832b".
|
| + at_pos = len;
|
| + for (int i = dot_pos; i < name.Length(); i++) {
|
| + if (name.CharAt(i) == '@') {
|
| + ASSERT(at_pos == len);
|
| + at_pos = i;
|
| + }
|
| + }
|
| +
|
| + intptr_t suffix_len = at_pos - dot_pos;
|
| + if (suffix_len <= 1) {
|
| + // The constructor name is of length 0 or 1. That means that
|
| + // either this isn't a constructor or that this is an unnamed
|
| + // constructor. In either case, we're done.
|
| + return result.raw();
|
| + }
|
| +
|
| + const String& suffix =
|
| + String::Handle(isolate, String::SubString(name, dot_pos, suffix_len));
|
| + return String::Concat(result, suffix);
|
| +}
|
| +
|
| +
|
| // Return error if isolate is in an inconsistent state.
|
| // Return NULL when no error condition exists.
|
| //
|
| @@ -108,7 +190,7 @@
|
| }
|
|
|
| RawObject* Api::UnwrapHandle(Dart_Handle object) {
|
| -#ifdef DEBUG
|
| +#if defined(DEBUG)
|
| Isolate* isolate = Isolate::Current();
|
| ASSERT(isolate != NULL);
|
| ApiState* state = isolate->api_state();
|
| @@ -575,8 +657,7 @@
|
| ApiState* state = isolate->api_state();
|
| ASSERT(state != NULL);
|
| if (keys == NULL) {
|
| - return Api::NewError("%s expects argument 'keys' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(keys);
|
| }
|
| if (num_keys <= 0) {
|
| return Api::NewError(
|
| @@ -584,8 +665,7 @@
|
| CURRENT_FUNC);
|
| }
|
| if (values == NULL) {
|
| - return Api::NewError("%s expects argument 'values' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(values);
|
| }
|
| if (num_values <= 0) {
|
| return Api::NewError(
|
| @@ -670,8 +750,7 @@
|
| Isolate* isolate = Isolate::Current();
|
| CHECK_ISOLATE(isolate);
|
| if (callback == NULL) {
|
| - return Api::NewError("%s expects argument 'callback' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(callback);
|
| }
|
| isolate->heap()->Profile(callback, stream);
|
| return Api::Success(isolate);
|
| @@ -814,12 +893,10 @@
|
| DARTSCOPE(isolate);
|
| TIMERSCOPE(time_creating_snapshot);
|
| if (buffer == NULL) {
|
| - return Api::NewError("%s expects argument 'buffer' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(buffer);
|
| }
|
| if (size == NULL) {
|
| - return Api::NewError("%s expects argument 'size' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(size);
|
| }
|
| const char* msg = CheckIsolateState(isolate,
|
| ClassFinalizer::kGeneratingSnapshot);
|
| @@ -841,12 +918,10 @@
|
| DARTSCOPE(isolate);
|
| TIMERSCOPE(time_creating_snapshot);
|
| if (buffer == NULL) {
|
| - return Api::NewError("%s expects argument 'buffer' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(buffer);
|
| }
|
| if (size == NULL) {
|
| - return Api::NewError("%s expects argument 'size' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(size);
|
| }
|
| const char* msg = CheckIsolateState(isolate);
|
| if (msg != NULL) {
|
| @@ -1490,8 +1565,7 @@
|
| Isolate* isolate = Isolate::Current();
|
| DARTSCOPE(isolate);
|
| if (str == NULL) {
|
| - return Api::NewError("%s expects argument 'str' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(str);
|
| }
|
| if (!Utf8::IsValid(str)) {
|
| return Api::NewError("%s expects argument 'str' to be valid UTF-8.",
|
| @@ -1544,8 +1618,7 @@
|
| CURRENT_FUNC);
|
| }
|
| if (peer == NULL) {
|
| - return Api::NewError("%s expects argument 'peer' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(peer);
|
| }
|
| *peer = str.GetPeer();
|
| return Api::Success(isolate);
|
| @@ -1559,8 +1632,7 @@
|
| Isolate* isolate = Isolate::Current();
|
| DARTSCOPE(isolate);
|
| if (codepoints == NULL && length != 0) {
|
| - return Api::NewError("%s expects argument 'codepoints' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(codepoints);
|
| }
|
| if (length < 0) {
|
| return Api::NewError("%s expects argument 'length' to be greater than 0.",
|
| @@ -1578,8 +1650,7 @@
|
| Isolate* isolate = Isolate::Current();
|
| DARTSCOPE(isolate);
|
| if (codepoints == NULL && length != 0) {
|
| - return Api::NewError("%s expects argument 'codepoints' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(codepoints);
|
| }
|
| if (length < 0) {
|
| return Api::NewError("%s expects argument 'length' to be greater than 0.",
|
| @@ -1597,8 +1668,7 @@
|
| Isolate* isolate = Isolate::Current();
|
| DARTSCOPE(isolate);
|
| if (codepoints == NULL && length != 0) {
|
| - return Api::NewError("%s expects argument 'codepoints' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(codepoints);
|
| }
|
| if (length < 0) {
|
| return Api::NewError("%s expects argument 'length' to be greater than 0.",
|
| @@ -1701,12 +1771,10 @@
|
| RETURN_TYPE_ERROR(isolate, object, String);
|
| }
|
| if (bytes == NULL) {
|
| - return Api::NewError("%s expects argument 'bytes' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(bytes);
|
| }
|
| if (length == NULL) {
|
| - return Api::NewError("%s expects argument 'length' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(length);
|
| }
|
| const char* cstring = str.ToCString();
|
| *length = Utf8::Length(str);
|
| @@ -2106,8 +2174,7 @@
|
| Isolate* isolate = Isolate::Current();
|
| DARTSCOPE(isolate);
|
| if (data == NULL && length != 0) {
|
| - return Api::NewError("%s expects argument 'data' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(data);
|
| }
|
| if (length < 0) {
|
| return Api::NewError("%s expects argument 'length' to be greater than 0.",
|
| @@ -2128,8 +2195,7 @@
|
| RETURN_TYPE_ERROR(isolate, object, ExternalUint8Array);
|
| }
|
| if (peer == NULL) {
|
| - return Api::NewError("%s expects argument 'peer' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(peer);
|
| }
|
| *peer = array.GetPeer();
|
| return Api::Success(isolate);
|
| @@ -2407,7 +2473,8 @@
|
| if (cls.IsNull()) {
|
| RETURN_TYPE_ERROR(isolate, clazz, Class);
|
| }
|
| - return Api::NewHandle(isolate, cls.Name());
|
| + const String& cls_name = String::Handle(isolate, cls.Name());
|
| + return Api::NewHandle(isolate, IdentifierPrettyName(isolate, cls_name));
|
| }
|
|
|
|
|
| @@ -2419,6 +2486,14 @@
|
| if (cls.IsNull()) {
|
| RETURN_TYPE_ERROR(isolate, clazz, Class);
|
| }
|
| +
|
| +#if defined(DEBUG)
|
| + const Library& lib = Library::Handle(cls.library());
|
| + if (lib.IsNull()) {
|
| + ASSERT(cls.IsDynamicClass() || cls.IsVoidClass());
|
| + }
|
| +#endif
|
| +
|
| return Api::NewHandle(isolate, cls.library());
|
| }
|
|
|
| @@ -2497,6 +2572,417 @@
|
| }
|
|
|
|
|
| +// --- Function and Variable Reflection ---
|
| +
|
| +
|
| +// Outside of the vm, we expose setter names with a trailing '='.
|
| +static bool HasExternalSetterSuffix(const String& name) {
|
| + return name.CharAt(name.Length() - 1) == '=';
|
| +}
|
| +
|
| +
|
| +static RawString* AddExternalSetterSuffix(const String& name) {
|
| + const String& equals = String::Handle(String::NewSymbol("="));
|
| + return String::Concat(name, equals);
|
| +}
|
| +
|
| +
|
| +static RawString* RemoveExternalSetterSuffix(const String& name) {
|
| + ASSERT(HasExternalSetterSuffix(name));
|
| + return String::SubString(name, 0, name.Length() - 1);
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_GetFunctionNames(Dart_Handle target) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
|
| + if (obj.IsError()) {
|
| + return target;
|
| + }
|
| +
|
| + const GrowableObjectArray& names =
|
| + GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
|
| + Function& func = Function::Handle();
|
| + String& name = String::Handle();
|
| +
|
| + if (obj.IsClass()) {
|
| + const Class& cls = Class::Cast(obj);
|
| + const Array& func_array = Array::Handle(cls.functions());
|
| +
|
| + // Some special types like 'Dynamic' have a null functions list.
|
| + if (!func_array.IsNull()) {
|
| + for (intptr_t i = 0; i < func_array.Length(); ++i) {
|
| + func ^= func_array.At(i);
|
| +
|
| + // Skip implicit getters and setters.
|
| + if (func.kind() == RawFunction::kImplicitGetter ||
|
| + func.kind() == RawFunction::kImplicitSetter ||
|
| + func.kind() == RawFunction::kConstImplicitGetter) {
|
| + continue;
|
| + }
|
| +
|
| + name = func.name();
|
| + bool is_setter = Field::IsSetterName(name);
|
| + name = IdentifierPrettyName(isolate, name);
|
| +
|
| + if (is_setter) {
|
| + name = AddExternalSetterSuffix(name);
|
| + }
|
| + names.Add(name);
|
| + }
|
| + }
|
| + } else if (obj.IsLibrary()) {
|
| + const Library& lib = Library::Cast(obj);
|
| + DictionaryIterator it(lib);
|
| + Object& obj = Object::Handle();
|
| + while (it.HasNext()) {
|
| + obj = it.GetNext();
|
| + if (obj.IsFunction()) {
|
| + func ^= obj.raw();
|
| + name = func.name();
|
| + bool is_setter = Field::IsSetterName(name);
|
| + name = IdentifierPrettyName(isolate, name);
|
| + if (is_setter) {
|
| + name = AddExternalSetterSuffix(name);
|
| + }
|
| + names.Add(name);
|
| + }
|
| + }
|
| + } else {
|
| + return Api::NewError(
|
| + "%s expects argument 'target' to be a class or library.",
|
| + CURRENT_FUNC);
|
| + }
|
| + return Api::NewHandle(isolate, Array::MakeArray(names));
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_LookupFunction(Dart_Handle target,
|
| + Dart_Handle function_name) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
|
| + if (obj.IsError()) {
|
| + return target;
|
| + }
|
| + const String& func_name = Api::UnwrapStringHandle(isolate, function_name);
|
| + if (func_name.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, function_name, String);
|
| + }
|
| +
|
| + Function& func = Function::Handle(isolate);
|
| + String& tmp_name = String::Handle(isolate);
|
| + if (obj.IsClass()) {
|
| + const Class& cls = Class::Cast(obj);
|
| +
|
| + // Case 1. Lookup the unmodified function name.
|
| + func = cls.LookupFunction(func_name);
|
| +
|
| + // Case 2. Lookup the function without the external setter suffix
|
| + // '='. Make sure to do this check after the regular lookup, so
|
| + // that we don't interfere with operator lookups (like ==).
|
| + if (func.IsNull() && HasExternalSetterSuffix(func_name)) {
|
| + tmp_name = RemoveExternalSetterSuffix(func_name);
|
| + tmp_name = Field::SetterName(tmp_name);
|
| + func = cls.LookupFunction(tmp_name);
|
| + }
|
| +
|
| + // Case 3. Lookup the funciton with the getter prefix prepended.
|
| + if (func.IsNull()) {
|
| + tmp_name = Field::GetterName(func_name);
|
| + func = cls.LookupFunction(tmp_name);
|
| + }
|
| +
|
| + // Case 4. Lookup the function with a . appended to find the
|
| + // unnamed constructor.
|
| + if (func.IsNull()) {
|
| + const String& dot = String::Handle(String::NewSymbol("."));
|
| + tmp_name = String::Concat(func_name, dot);
|
| + func = cls.LookupFunction(tmp_name);
|
| + }
|
| + } else if (obj.IsLibrary()) {
|
| + const Library& lib = Library::Cast(obj);
|
| +
|
| + // Case 1. Lookup the unmodified function name.
|
| + func = lib.LookupFunctionAllowPrivate(func_name);
|
| +
|
| + // Case 2. Lookup the function without the external setter suffix
|
| + // '='. Make sure to do this check after the regular lookup, so
|
| + // that we don't interfere with operator lookups (like ==).
|
| + if (func.IsNull() && HasExternalSetterSuffix(func_name)) {
|
| + tmp_name = RemoveExternalSetterSuffix(func_name);
|
| + tmp_name = Field::SetterName(tmp_name);
|
| + func = lib.LookupFunctionAllowPrivate(tmp_name);
|
| + }
|
| +
|
| + // Case 3. Lookup the funciton with the getter prefix prepended.
|
| + if (func.IsNull()) {
|
| + tmp_name = Field::GetterName(func_name);
|
| + func = lib.LookupFunctionAllowPrivate(tmp_name);
|
| + }
|
| + } else {
|
| + return Api::NewError(
|
| + "%s expects argument 'target' to be a class or library.",
|
| + CURRENT_FUNC);
|
| + }
|
| +
|
| +#if defined(DEBUG)
|
| + if (!func.IsNull()) {
|
| + // We only provide access to a subset of function kinds.
|
| + RawFunction::Kind func_kind = func.kind();
|
| + ASSERT(func_kind == RawFunction::kFunction ||
|
| + func_kind == RawFunction::kGetterFunction ||
|
| + func_kind == RawFunction::kSetterFunction ||
|
| + func_kind == RawFunction::kConstructor ||
|
| + func_kind == RawFunction::kAbstract);
|
| + }
|
| +#endif
|
| + return Api::NewHandle(isolate, func.raw());
|
| +}
|
| +
|
| +
|
| +DART_EXPORT bool Dart_IsFunction(Dart_Handle handle) {
|
| + return Api::ClassId(handle) == kFunction;
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + const Function& func = Api::UnwrapFunctionHandle(isolate, function);
|
| + if (func.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, function, Function);
|
| + }
|
| + String& func_name = String::Handle(isolate);
|
| + func_name = func.name();
|
| + bool is_setter = Field::IsSetterName(func_name);
|
| + func_name = IdentifierPrettyName(isolate, func_name);
|
| + if (is_setter) {
|
| + func_name = AddExternalSetterSuffix(func_name);
|
| + }
|
| + return Api::NewHandle(isolate, func_name.raw());
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_FunctionIsAbstract(Dart_Handle function,
|
| + bool* is_abstract) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + if (is_abstract == NULL) {
|
| + RETURN_NULL_ERROR(is_abstract);
|
| + }
|
| + const Function& func = Api::UnwrapFunctionHandle(isolate, function);
|
| + if (func.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, function, Function);
|
| + }
|
| + *is_abstract = (func.kind() == RawFunction::kAbstract);
|
| + return Api::Success(isolate);
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
|
| + bool* is_static) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + if (is_static == NULL) {
|
| + RETURN_NULL_ERROR(is_static);
|
| + }
|
| + const Function& func = Api::UnwrapFunctionHandle(isolate, function);
|
| + if (func.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, function, Function);
|
| + }
|
| + *is_static = func.is_static();
|
| + return Api::Success(isolate);
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_FunctionIsConstructor(Dart_Handle function,
|
| + bool* is_constructor) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + if (is_constructor == NULL) {
|
| + RETURN_NULL_ERROR(is_constructor);
|
| + }
|
| + const Function& func = Api::UnwrapFunctionHandle(isolate, function);
|
| + if (func.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, function, Function);
|
| + }
|
| + *is_constructor = func.kind() == RawFunction::kConstructor;
|
| + return Api::Success(isolate);
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_FunctionIsGetter(Dart_Handle function,
|
| + bool* is_getter) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + if (is_getter == NULL) {
|
| + RETURN_NULL_ERROR(is_getter);
|
| + }
|
| + const Function& func = Api::UnwrapFunctionHandle(isolate, function);
|
| + if (func.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, function, Function);
|
| + }
|
| + // TODO(turnidge): It would be nice if I could just use func.kind()
|
| + // to check for a getter function here, but unfortunately the only
|
| + // way to distinguish abstract getter functions is to use the name
|
| + // itself. Consider adding a RawFunction::kAbstractGetter type.
|
| + const String& func_name = String::Handle(isolate, func.name());
|
| + *is_getter = Field::IsGetterName(func_name);
|
| +
|
| + return Api::Success(isolate);
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_FunctionIsSetter(Dart_Handle function,
|
| + bool* is_setter) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + if (is_setter == NULL) {
|
| + RETURN_NULL_ERROR(is_setter);
|
| + }
|
| + const Function& func = Api::UnwrapFunctionHandle(isolate, function);
|
| + if (func.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, function, Function);
|
| + }
|
| + // TODO(turnidge): It would be nice if I could just use func.kind()
|
| + // to check for a setter function here, but unfortunately the only
|
| + // way to distinguish abstract setter functions is to use the name
|
| + // itself. Consider adding a RawFunction::kAbstractSetter type.
|
| + const String& func_name = String::Handle(isolate, func.name());
|
| + *is_setter = Field::IsSetterName(func_name);
|
| +
|
| + return Api::Success(isolate);
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_GetVariableNames(Dart_Handle target) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
|
| + if (obj.IsError()) {
|
| + return target;
|
| + }
|
| +
|
| + const GrowableObjectArray& names =
|
| + GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
|
| + Field& field = Field::Handle(isolate);
|
| + String& name = String::Handle(isolate);
|
| +
|
| + if (obj.IsClass()) {
|
| + const Class& cls = Class::Cast(obj);
|
| + const Array& field_array = Array::Handle(cls.fields());
|
| +
|
| + // Some special types like 'Dynamic' have a null fields list.
|
| + //
|
| + // TODO(turnidge): Fix 'Dynamic' so that it does not have a null
|
| + // fields list. This will have to wait until the empty array is
|
| + // allocated in the vm isolate.
|
| + if (!field_array.IsNull()) {
|
| + for (intptr_t i = 0; i < field_array.Length(); ++i) {
|
| + field ^= field_array.At(i);
|
| + name = field.name();
|
| + name = IdentifierPrettyName(isolate, name);
|
| + names.Add(name);
|
| + }
|
| + }
|
| + } else if (obj.IsLibrary()) {
|
| + const Library& lib = Library::Cast(obj);
|
| + DictionaryIterator it(lib);
|
| + Object& obj = Object::Handle(isolate);
|
| + while (it.HasNext()) {
|
| + obj = it.GetNext();
|
| + if (obj.IsField()) {
|
| + field ^= obj.raw();
|
| + name = field.name();
|
| + name = IdentifierPrettyName(isolate, name);
|
| + names.Add(name);
|
| + }
|
| + }
|
| + } else {
|
| + return Api::NewError(
|
| + "%s expects argument 'target' to be a class or library.",
|
| + CURRENT_FUNC);
|
| + }
|
| + return Api::NewHandle(isolate, Array::MakeArray(names));
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_LookupVariable(Dart_Handle target,
|
| + Dart_Handle variable_name) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
|
| + if (obj.IsError()) {
|
| + return target;
|
| + }
|
| + const String& var_name = Api::UnwrapStringHandle(isolate, variable_name);
|
| + if (var_name.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, variable_name, String);
|
| + }
|
| + if (obj.IsClass()) {
|
| + const Class& cls = Class::Cast(obj);
|
| + return Api::NewHandle(isolate, cls.LookupField(var_name));
|
| + }
|
| + if (obj.IsLibrary()) {
|
| + const Library& lib = Library::Cast(obj);
|
| + return Api::NewHandle(isolate, lib.LookupFieldAllowPrivate(var_name));
|
| + }
|
| + return Api::NewError(
|
| + "%s expects argument 'target' to be a class or library.",
|
| + CURRENT_FUNC);
|
| +}
|
| +
|
| +
|
| +DART_EXPORT bool Dart_IsVariable(Dart_Handle handle) {
|
| + return Api::ClassId(handle) == kField;
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_VariableName(Dart_Handle variable) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + const Field& var = Api::UnwrapFieldHandle(isolate, variable);
|
| + if (var.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, variable, Field);
|
| + }
|
| + const String& var_name = String::Handle(var.name());
|
| + return Api::NewHandle(isolate, IdentifierPrettyName(isolate, var_name));
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_VariableIsStatic(Dart_Handle variable,
|
| + bool* is_static) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + if (is_static == NULL) {
|
| + RETURN_NULL_ERROR(is_static);
|
| + }
|
| + const Field& var = Api::UnwrapFieldHandle(isolate, variable);
|
| + if (var.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, variable, Field);
|
| + }
|
| + *is_static = var.is_static();
|
| + return Api::Success(isolate);
|
| +}
|
| +
|
| +
|
| +DART_EXPORT Dart_Handle Dart_VariableIsFinal(Dart_Handle variable,
|
| + bool* is_final) {
|
| + Isolate* isolate = Isolate::Current();
|
| + DARTSCOPE(isolate);
|
| + if (is_final == NULL) {
|
| + RETURN_NULL_ERROR(is_final);
|
| + }
|
| + const Field& var = Api::UnwrapFieldHandle(isolate, variable);
|
| + if (var.IsNull()) {
|
| + RETURN_TYPE_ERROR(isolate, variable, Field);
|
| + }
|
| + *is_final = var.is_final();
|
| + return Api::Success(isolate);
|
| +}
|
| +
|
| // --- Constructors, Methods, and Fields ---
|
|
|
|
|
| @@ -3333,8 +3819,7 @@
|
| DARTSCOPE(isolate);
|
| TIMERSCOPE(time_script_loading);
|
| if (buffer == NULL) {
|
| - return Api::NewError("%s expects argument 'buffer' to be non-null.",
|
| - CURRENT_FUNC);
|
| + RETURN_NULL_ERROR(buffer);
|
| }
|
| const Snapshot* snapshot = Snapshot::SetupFromBuffer(buffer);
|
| if (!snapshot->IsScriptSnapshot()) {
|
| @@ -3464,8 +3949,15 @@
|
| String& name = String::Handle();
|
| while (it.HasNext()) {
|
| cls = it.GetNextClass();
|
| - name = cls.Name();
|
| - names.Add(name);
|
| + // For now we suppress the signature classes of closures.
|
| + //
|
| + // TODO(turnidge): Add this to the unit test.
|
| + const Function& signature_func = Function::Handle(cls.signature_function());
|
| + if (signature_func.IsNull()) {
|
| + name = cls.Name();
|
| + name = IdentifierPrettyName(isolate, name);
|
| + names.Add(name);
|
| + }
|
| }
|
| return Api::NewHandle(isolate, Array::MakeArray(names));
|
| }
|
|
|