diff --git a/plugins/ets/runtime/ets_libbase_runtime.yaml b/plugins/ets/runtime/ets_libbase_runtime.yaml index dd96ec4845dcf3744aa4c74a1cd6e57219c767f6..b6fe4e87b3d36e97c9992f7ca9dc24db1634469e 100644 --- a/plugins/ets/runtime/ets_libbase_runtime.yaml +++ b/plugins/ets/runtime/ets_libbase_runtime.yaml @@ -1906,7 +1906,7 @@ intrinsics: impl: panda::ets::intrinsics::TypeAPIGetMethod clear_flags: [ ] - - name: TypeAPIGetConstructorsNum + - name: StdTypeGetConstructorsNum space: ets class_name: std.core.ETSGLOBAL method_name: TypeAPIGetConstructorsNum @@ -2049,17 +2049,6 @@ intrinsics: impl: panda::ets::intrinsics::TypeAPIGetResultType clear_flags: [ ] - - name: TypeAPIGetReceiverType - space: ets - class_name: std.core.ETSGLOBAL - method_name: TypeAPIGetReceiverType - static: true - signature: - ret: std.core.String - args: [ std.core.String ] - impl: panda::ets::intrinsics::TypeAPIGetReceiverType - clear_flags: [ ] - - name: StdMethodInvoke space: ets class_name: std.core.ETSGLOBAL @@ -2085,6 +2074,16 @@ intrinsics: - std.core.String - std.core.Object[] impl: panda::ets::intrinsics::TypeAPIMethodInvokeConstructor + + - name: TypeAPIGetReceiverType + space: ets + class_name: std.core.ETSGLOBAL + method_name: TypeAPIGetReceiverType + static: true + signature: + ret: std.core.String + args: [ std.core.String ] + impl: panda::ets::intrinsics::TypeAPIGetReceiverType clear_flags: [ ] ################# @@ -2137,6 +2136,7 @@ intrinsics: ################### # std.core.Value # ################### + - name: ValueAPIGetFieldObject space: ets class_name: std.core.ETSGLOBAL @@ -2236,6 +2236,104 @@ intrinsics: impl: panda::ets::intrinsics::ValueAPIGetFieldDouble clear_flags: [ ] + - name: ValueAPIGetFieldByNameObject + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetFieldByNameObject + static: true + signature: + ret: std.core.Object + args: [ std.core.Object, std.core.String ] + impl: panda::ets::intrinsics::ValueAPIGetFieldByNameObject + clear_flags: [ ] + + - name: ValueAPIGetFieldByNameBoolean + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetFieldByNameBoolean + static: true + signature: + ret: u1 + args: [ std.core.Object, std.core.String ] + impl: panda::ets::intrinsics::ValueAPIGetFieldByNameBoolean + clear_flags: [ ] + + - name: ValueAPIGetFieldByNameByte + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetFieldByNameByte + static: true + signature: + ret: i8 + args: [ std.core.Object, std.core.String ] + impl: panda::ets::intrinsics::ValueAPIGetFieldByNameByte + clear_flags: [ ] + + - name: ValueAPIGetFieldByNameChar + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetFieldByNameChar + static: true + signature: + ret: u16 + args: [ std.core.Object, std.core.String ] + impl: panda::ets::intrinsics::ValueAPIGetFieldByNameChar + clear_flags: [ ] + + - name: ValueAPIGetFieldByNameShort + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetFieldByNameShort + static: true + signature: + ret: i16 + args: [ std.core.Object, std.core.String ] + impl: panda::ets::intrinsics::ValueAPIGetFieldByNameShort + clear_flags: [ ] + + - name: ValueAPIGetFieldByNameInt + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetFieldByNameInt + static: true + signature: + ret: i32 + args: [ std.core.Object, std.core.String ] + impl: panda::ets::intrinsics::ValueAPIGetFieldByNameInt + clear_flags: [ ] + + - name: ValueAPIGetFieldByNameLong + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetFieldByNameLong + static: true + signature: + ret: i64 + args: [ std.core.Object, std.core.String ] + impl: panda::ets::intrinsics::ValueAPIGetFieldByNameLong + clear_flags: [ ] + + - name: ValueAPIGetFieldByNameFloat + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetFieldByNameFloat + static: true + signature: + ret: f32 + args: [ std.core.Object, std.core.String ] + impl: panda::ets::intrinsics::ValueAPIGetFieldByNameFloat + clear_flags: [ ] + + - name: ValueAPIGetFieldByNameDouble + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetFieldByNameDouble + static: true + signature: + ret: f64 + args: [ std.core.Object, std.core.String ] + impl: panda::ets::intrinsics::ValueAPIGetFieldByNameDouble + clear_flags: [ ] - name: ValueAPISetFieldObject @@ -2440,6 +2538,17 @@ intrinsics: + - name: ValueAPIGetArrayLength + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetArrayLength + static: true + signature: + ret: i64 + args: [ std.core.Object ] + impl: panda::ets::intrinsics::ValueAPIGetArrayLength + clear_flags: [ ] + - name: ValueAPISetElementObject space: ets class_name: std.core.ETSGLOBAL @@ -2539,6 +2648,106 @@ intrinsics: impl: panda::ets::intrinsics::ValueAPISetElementDouble clear_flags: [ ] + + - name: ValueAPIGetElementObject + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetElementObject + static: true + signature: + ret: std.core.Object + args: [ std.core.Object, i64 ] + impl: panda::ets::intrinsics::ValueAPIGetElementObject + clear_flags: [ ] + + - name: ValueAPIGetElementBoolean + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetElementBoolean + static: true + signature: + ret: u1 + args: [ std.core.Object, i64 ] + impl: panda::ets::intrinsics::ValueAPIGetElementBoolean + clear_flags: [ ] + + - name: ValueAPIGetElementByte + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetElementByte + static: true + signature: + ret: i8 + args: [ std.core.Object, i64 ] + impl: panda::ets::intrinsics::ValueAPIGetElementByte + clear_flags: [ ] + + - name: ValueAPIGetElementChar + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetElementChar + static: true + signature: + ret: u16 + args: [ std.core.Object, i64 ] + impl: panda::ets::intrinsics::ValueAPIGetElementChar + clear_flags: [ ] + + - name: ValueAPIGetElementShort + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetElementShort + static: true + signature: + ret: i16 + args: [ std.core.Object, i64 ] + impl: panda::ets::intrinsics::ValueAPIGetElementShort + clear_flags: [ ] + + - name: ValueAPIGetElementInt + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetElementInt + static: true + signature: + ret: i32 + args: [ std.core.Object, i64 ] + impl: panda::ets::intrinsics::ValueAPIGetElementInt + clear_flags: [ ] + + - name: ValueAPIGetElementLong + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetElementLong + static: true + signature: + ret: i64 + args: [ std.core.Object, i64 ] + impl: panda::ets::intrinsics::ValueAPIGetElementLong + clear_flags: [ ] + + - name: ValueAPIGetElementFloat + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetElementFloat + static: true + signature: + ret: f32 + args: [ std.core.Object, i64 ] + impl: panda::ets::intrinsics::ValueAPIGetElementFloat + clear_flags: [ ] + + - name: ValueAPIGetElementDouble + space: ets + class_name: std.core.ETSGLOBAL + method_name: ValueAPIGetElementDouble + static: true + signature: + ret: f64 + args: [ std.core.Object, i64 ] + impl: panda::ets::intrinsics::ValueAPIGetElementDouble + clear_flags: [ ] + ############################### # std.core.TypeBuilderContext # ############################### diff --git a/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp b/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp index 84b25f4a2dd82a55eac8cde3577d151304d27253..a8a33fa75156cc31847692b32418f1f47a905e3a 100644 --- a/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp +++ b/plugins/ets/runtime/interop_js/ets_proxy/ets_class_wrapper.cpp @@ -274,18 +274,33 @@ std::pair, std::vector> EtsClassWrapper::Calculat INTEROP_FATAL_IF(!it.second); } } - // Collect methods - for (auto &m : klass->GetMethods()) { - if (m.IsPrivate()) { - continue; - } - auto name = m.GetName().data; - if (overloads != nullptr && overloads->find(name) != overloads->end()) { - continue; - } - auto it = props.insert({m.GetName().data, &m}); - if (UNLIKELY(!it.second)) { - fatal_method_overloaded(&m); + + // If class is std.core.Object + auto klass_desc = utf::Mutf8AsCString(klass->GetDescriptor()); + if (klass_desc == panda_file_items::class_descriptors::OBJECT) { + // Ingore all methods of std.core.Object due to names intersection with JS Object + // Keep constructors only + auto obj_ctors = ets_class_->GetConstructors(); + // Assuming that ETS StdLib guarantee that Object has the only one ctor + ASSERT(obj_ctors.size() == 1); + auto ctor = obj_ctors[0]->GetPandaMethod(); + props.insert({ctor->GetName().data, ctor}); + // TODO(shumilov-petr): Think about removing methods from std.core.Object + // that are already presented in JS Object, others should be kept + } else { + // Collect methods + for (auto &m : klass->GetMethods()) { + if (m.IsPrivate()) { + continue; + } + auto name = m.GetName().data; + if (overloads != nullptr && overloads->find(name) != overloads->end()) { + continue; + } + auto it = props.insert({m.GetName().data, &m}); + if (UNLIKELY(!it.second)) { + fatal_method_overloaded(&m); + } } } diff --git a/plugins/ets/runtime/intrinsics/std_core_Type.cpp b/plugins/ets/runtime/intrinsics/std_core_Type.cpp index 5725633c7b4965bc67d449fe5fb158f3b5eaad0e..44ab2ab34831933cac7f311422876e2ddd877a54 100644 --- a/plugins/ets/runtime/intrinsics/std_core_Type.cpp +++ b/plugins/ets/runtime/intrinsics/std_core_Type.cpp @@ -19,6 +19,7 @@ #include #include #include "file.h" +#include "handle_scope.h" #include "include/coretypes/class.h" #include "include/mem/panda_string.h" #include "include/mtmanaged_thread.h" @@ -298,7 +299,7 @@ EtsObject *TypeAPIGetStaticFieldValue(EtsString *owner_td, EtsString *name) using T = EtsTypeEnumToCppType; auto val = owner_type->GetRuntimeClass()->GetFieldPrimitive(*field->GetCoreType()); // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) - return EtsBoxPrimitive::Create(EtsCoroutine::GetCurrent(), val); + return EtsBoxPrimitive::Create(coroutine, val); }); } @@ -309,6 +310,7 @@ EtsVoid *TypeAPISetStaticFieldValue(EtsString *owner_td, EtsString *name, EtsObj { auto coroutine = EtsCoroutine::GetCurrent(); [[maybe_unused]] HandleScope scope(coroutine); + VMHandle fname_ptr(coroutine, name->GetCoreType()); VMHandle value_ptr(coroutine, v->GetCoreType()); @@ -364,8 +366,8 @@ EtsTypeAPIMethod *CreateMethod(EtsMethod *method, EtsClass *type) // Set Type Descriptor typeapi_method.GetPtr()->SetTypeDesc(method->GetDescriptor().c_str()); EtsString *name; - if (method->IsConstructor()) { - name = EtsString::CreateFromMUtf8("constructor"); + if (method->IsInstanceConstructor()) { + name = EtsString::CreateFromMUtf8(CONSTRUCTOR_NAME); } else { name = method->GetNameString(); } @@ -387,7 +389,7 @@ EtsTypeAPIMethod *CreateMethod(EtsMethod *method, EtsClass *type) attr |= (method->IsStatic()) ? static_cast(EtsTypeAPIAttributes::STATIC) : 0U; attr |= (method->IsConstructor()) ? static_cast(EtsTypeAPIAttributes::CONSTRUCTOR) : 0U; attr |= (method->IsAbstract()) ? static_cast(EtsTypeAPIAttributes::ABSTRACT) : 0U; - attr |= (method->IsDeclaredIn(type)) ? static_cast(EtsTypeAPIAttributes::INHERITED) : 0U; + attr |= (!method->IsDeclaredIn(type)) ? static_cast(EtsTypeAPIAttributes::INHERITED) : 0U; attr |= (method->IsGetter()) ? static_cast(EtsTypeAPIAttributes::GETTER) : 0U; attr |= (method->IsSetter()) ? static_cast(EtsTypeAPIAttributes::SETTER) : 0U; @@ -514,10 +516,44 @@ EtsString *TypeAPIGetArrayElementType(EtsString *td) return EtsString::CreateFromMUtf8(arr_class->GetComponentType()->GetDescriptor()); } +EtsObject *MakeClassInstance(EtsString *td) +{ + auto coroutine = EtsCoroutine::GetCurrent(); + [[maybe_unused]] HandleScope scope(coroutine); + + auto class_linker = PandaEtsVM::GetCurrent()->GetClassLinker(); + auto type_class = class_linker->GetClass(td->GetMutf8().c_str()); + + ASSERT(!type_class->IsArrayClass()); + + if (type_class->IsStringClass()) { + return EtsString::CreateNewEmptyString()->AsObject(); + } + + VMHandle obj_handle(coroutine, EtsObject::Create(type_class)->GetCoreType()); + auto has_default_constr = false; + type_class->EnumerateMethods([&](EtsMethod *method) { + if (method->IsConstructor() && method->GetParametersNum() == 0) { + std::array args {Value(obj_handle.GetPtr()->GetCoreType())}; + method->GetPandaMethod()->InvokeVoid(coroutine, args.data()); + has_default_constr = true; + return true; + } + return false; + }); + ASSERT(has_default_constr); + return obj_handle.GetPtr(); +} + EtsObject *TypeAPIMakeArrayInstance(EtsString *td, EtsLong len) { + auto coroutine = EtsCoroutine::GetCurrent(); + [[maybe_unused]] HandleScope scope(coroutine); + + VMHandle td_handle(coroutine, td->GetCoreType()); + auto class_linker = PandaEtsVM::GetCurrent()->GetClassLinker(); - auto type_desc = td->GetMutf8(); + auto type_desc = td_handle->GetMutf8(); auto type_class = class_linker->GetClass(type_desc.c_str()); auto val_type = panda::panda_file::Type::GetTypeIdBySignature(type_desc[0]); @@ -538,8 +574,14 @@ EtsObject *TypeAPIMakeArrayInstance(EtsString *td, EtsLong len) return EtsFloatArray::Create(len)->AsObject(); case panda_file::Type::TypeId::F64: return EtsDoubleArray::Create(len)->AsObject(); - case panda_file::Type::TypeId::REFERENCE: - return EtsObjectArray::Create(type_class, len)->AsObject(); + case panda_file::Type::TypeId::REFERENCE: { + VMHandle array_handle(coroutine, EtsObjectArray::Create(type_class, len)->GetCoreType()); + for (size_t i = 0; i < array_handle->GetLength(); ++i) { + VMHandle element_handle(coroutine, MakeClassInstance(td_handle.GetPtr())->GetCoreType()); + array_handle->Set(i, element_handle.GetPtr()); + } + return array_handle->AsObject(); + } default: return nullptr; } @@ -555,4 +597,5 @@ EtsString *TypeAPIGetBaseType(EtsString *td) } return EtsString::CreateFromMUtf8(base_class->GetDescriptor()); } + } // namespace panda::ets::intrinsics diff --git a/plugins/ets/runtime/intrinsics/std_core_Value.cpp b/plugins/ets/runtime/intrinsics/std_core_Value.cpp index 108cdc496300ab645be42f6539e3cbedba9db3d0..e2de0329c4bb9d6ff21e06aae670146c6dafa105 100644 --- a/plugins/ets/runtime/intrinsics/std_core_Value.cpp +++ b/plugins/ets/runtime/intrinsics/std_core_Value.cpp @@ -23,24 +23,49 @@ #include "plugins/ets/runtime/types/ets_void.h" #include "plugins/ets/runtime/ets_panda_file_items.h" #include "types/ets_array.h" +#include "types/ets_box_primitive.h" #include "types/ets_class.h" #include "types/ets_method.h" #include "types/ets_primitives.h" #include "types/ets_type.h" +#include "types/ets_type_comptime_traits.h" #include "types/ets_typeapi.h" #include "types/ets_typeapi_field.h" namespace panda::ets::intrinsics { +EtsObject *ValueAPIGetFieldByName(EtsObject *obj, EtsString *name) +{ + auto coroutine = EtsCoroutine::GetCurrent(); + [[maybe_unused]] HandleScope scope(coroutine); + VMHandle obj_handle(coroutine, obj->GetCoreType()); + VMHandle name_handle(coroutine, name->GetCoreType()); + + auto type_class = obj_handle.GetPtr()->GetClass(); + auto field = type_class->GetFieldByName(name_handle.GetPtr()); + + if (field->GetType()->IsPrimitive()) { + return EtsPrimitiveTypeEnumToComptimeConstant(ConvertPandaTypeToEtsType(field->GetCoreType()->GetType()), + [&](auto type) -> EtsObject * { + using T = EtsTypeEnumToCppType; + auto val = obj_handle.GetPtr()->GetFieldPrimitive(field); + // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader) + return EtsBoxPrimitive::Create(coroutine, val); + }); + } + return obj_handle.GetPtr()->GetFieldObject(field); +} + EtsVoid *ValueAPISetFieldObject(EtsObject *obj, EtsLong i, EtsObject *val) { auto coroutine = EtsCoroutine::GetCurrent(); [[maybe_unused]] HandleScope scope(coroutine); VMHandle obj_handle(coroutine, obj->GetCoreType()); + VMHandle val_handle(coroutine, val->GetCoreType()); auto type_class = obj_handle.GetPtr()->GetClass(); auto field_object = type_class->GetFieldByIndex(i); - obj_handle.GetPtr()->SetFieldObject(field_object, val); + obj_handle.GetPtr()->SetFieldObject(field_object, val_handle.GetPtr()); return EtsVoid::GetInstance(); } @@ -113,10 +138,13 @@ EtsVoid *ValueAPISetFieldByNameObject(EtsObject *obj, EtsString *name, EtsObject auto coroutine = EtsCoroutine::GetCurrent(); [[maybe_unused]] HandleScope scope(coroutine); VMHandle obj_handle(coroutine, obj->GetCoreType()); + VMHandle name_handle(coroutine, name->GetCoreType()); + VMHandle val_handle(coroutine, val->GetCoreType()); + auto type_class = obj_handle.GetPtr()->GetClass(); - auto field_object = type_class->GetFieldIDByName(name->GetMutf8().c_str()); - obj_handle.GetPtr()->SetFieldObject(field_object, val); + auto field_object = type_class->GetFieldIDByName(name_handle.GetPtr()->GetMutf8().c_str()); + obj_handle.GetPtr()->SetFieldObject(field_object, val_handle.GetPtr()); return EtsVoid::GetInstance(); } @@ -126,9 +154,10 @@ void SetFieldByNameValue(EtsObject *obj, EtsString *name, T val) auto coroutine = EtsCoroutine::GetCurrent(); [[maybe_unused]] HandleScope scope(coroutine); VMHandle obj_handle(coroutine, obj->GetCoreType()); + VMHandle name_handle(coroutine, name->GetCoreType()); auto type_class = obj_handle.GetPtr()->GetClass(); - auto field_object = type_class->GetFieldIDByName(name->GetMutf8().c_str()); + auto field_object = type_class->GetFieldIDByName(name_handle.GetPtr()->GetMutf8().c_str()); if (field_object->GetType()->IsBoxedClass()) { obj_handle.GetPtr()->SetFieldObject(field_object, EtsBoxPrimitive::Create(coroutine, val)); return; @@ -251,13 +280,89 @@ EtsDouble ValueAPIGetFieldDouble(EtsObject *obj, EtsLong i) return GetFieldValue(obj, i); } +EtsObject *ValueAPIGetFieldByNameObject(EtsObject *obj, EtsString *name) +{ + auto coroutine = EtsCoroutine::GetCurrent(); + [[maybe_unused]] HandleScope scope(coroutine); + VMHandle obj_handle(coroutine, obj->GetCoreType()); + + auto type_class = obj_handle.GetPtr()->GetClass(); + auto field_object = type_class->GetFieldIDByName(name->GetMutf8().c_str()); + return obj_handle.GetPtr()->GetFieldObject(field_object); +} + +template +T GetFieldByNameValue(EtsObject *obj, EtsString *name) +{ + auto coroutine = EtsCoroutine::GetCurrent(); + [[maybe_unused]] HandleScope scope(coroutine); + VMHandle obj_handle(coroutine, obj->GetCoreType()); + + auto type_class = obj_handle.GetPtr()->GetClass(); + auto field_object = type_class->GetFieldIDByName(name->GetMutf8().c_str()); + + if (field_object->GetType()->IsBoxedClass()) { + return EtsBoxPrimitive::FromCoreType(obj_handle.GetPtr()->GetFieldObject(field_object))->GetValue(); + } + return obj_handle.GetPtr()->GetFieldPrimitive(field_object); +} + +EtsBoolean ValueAPIGetFieldByNameBoolean(EtsObject *obj, EtsString *name) +{ + return GetFieldByNameValue(obj, name); +} + +EtsByte ValueAPIGetFieldByNameByte(EtsObject *obj, EtsString *name) +{ + return GetFieldByNameValue(obj, name); +} + +EtsShort ValueAPIGetFieldByNameShort(EtsObject *obj, EtsString *name) +{ + return GetFieldByNameValue(obj, name); +} + +EtsChar ValueAPIGetFieldByNameChar(EtsObject *obj, EtsString *name) +{ + return GetFieldByNameValue(obj, name); +} + +EtsInt ValueAPIGetFieldByNameInt(EtsObject *obj, EtsString *name) +{ + return GetFieldByNameValue(obj, name); +} + +EtsLong ValueAPIGetFieldByNameLong(EtsObject *obj, EtsString *name) +{ + return GetFieldByNameValue(obj, name); +} + +EtsFloat ValueAPIGetFieldByNameFloat(EtsObject *obj, EtsString *name) +{ + return GetFieldByNameValue(obj, name); +} + +EtsDouble ValueAPIGetFieldByNameDouble(EtsObject *obj, EtsString *name) +{ + return GetFieldByNameValue(obj, name); +} + +EtsLong ValueAPIGetArrayLength(EtsObject *obj) +{ + auto coroutine = EtsCoroutine::GetCurrent(); + [[maybe_unused]] HandleScope scope(coroutine); + VMHandle arr_handle(coroutine, obj->GetCoreType()); + return arr_handle->GetLength(); +} + EtsVoid *ValueAPISetElementObject(EtsObject *obj, EtsLong i, EtsObject *val) { auto coroutine = EtsCoroutine::GetCurrent(); [[maybe_unused]] HandleScope scope(coroutine); VMHandle arr_handle(coroutine, obj->GetCoreType()); + VMHandle val_handle(coroutine, val->GetCoreType()); - arr_handle.GetPtr()->Set(i, val); + arr_handle.GetPtr()->Set(i, val_handle.GetPtr()); return EtsVoid::GetInstance(); } @@ -324,4 +429,68 @@ EtsVoid *ValueAPISetElementDouble(EtsObject *obj, EtsLong i, EtsDouble val) return EtsVoid::GetInstance(); } +EtsObject *ValueAPIGetElementObject(EtsObject *obj, EtsLong i) +{ + auto coroutine = EtsCoroutine::GetCurrent(); + [[maybe_unused]] HandleScope scope(coroutine); + VMHandle arr_handle(coroutine, obj->GetCoreType()); + + return arr_handle.GetPtr()->Get(i); +} + +template +typename P::ValueType GetElement(EtsObject *obj, EtsLong i) +{ + auto coroutine = EtsCoroutine::GetCurrent(); + [[maybe_unused]] HandleScope scope(coroutine); + auto type_class = obj->GetClass(); + if (!type_class->GetComponentType()->IsBoxedClass()) { + VMHandle

arr_handle(coroutine, obj->GetCoreType()); + return arr_handle.GetPtr()->Get(i); + } + VMHandle arr_handle(coroutine, obj->GetCoreType()); + auto value = EtsBoxPrimitive::FromCoreType(arr_handle.GetPtr()->Get(i)); + return value->GetValue(); +} + +EtsBoolean ValueAPIGetElementBoolean(EtsObject *obj, EtsLong i) +{ + return GetElement(obj, i); +} + +EtsByte ValueAPIGetElementByte(EtsObject *obj, EtsLong i) +{ + return GetElement(obj, i); +} + +EtsShort ValueAPIGetElementShort(EtsObject *obj, EtsLong i) +{ + return GetElement(obj, i); +} + +EtsChar ValueAPIGetElementChar(EtsObject *obj, EtsLong i) +{ + return GetElement(obj, i); +} + +EtsInt ValueAPIGetElementInt(EtsObject *obj, EtsLong i) +{ + return GetElement(obj, i); +} + +EtsLong ValueAPIGetElementLong(EtsObject *obj, EtsLong i) +{ + return GetElement(obj, i); +} + +EtsFloat ValueAPIGetElementFloat(EtsObject *obj, EtsLong i) +{ + return GetElement(obj, i); +} + +EtsDouble ValueAPIGetElementDouble(EtsObject *obj, EtsLong i) +{ + return GetElement(obj, i); +} + } // namespace panda::ets::intrinsics \ No newline at end of file diff --git a/plugins/ets/runtime/types/ets_array.h b/plugins/ets/runtime/types/ets_array.h index 283376878835be49876854d874d5fa3e63cd5306..19e6cda0a21fd3fe846be9b7c4b1d4e7f02a510f 100644 --- a/plugins/ets/runtime/types/ets_array.h +++ b/plugins/ets/runtime/types/ets_array.h @@ -166,6 +166,8 @@ private: template class EtsPrimitiveArray : public EtsArray { public: + using ValueType = ClassType; + static EtsPrimitiveArray *Create(uint32_t length, SpaceType space_type = SpaceType::SPACE_TYPE_OBJECT) { ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS(); diff --git a/plugins/ets/runtime/types/ets_class.cpp b/plugins/ets/runtime/types/ets_class.cpp index 07cc66b1fe160ece59f3f2fe9113f490c6d6eb9d..497dc8d2f2c51f6d34f6851c5eda9ce91603af04 100644 --- a/plugins/ets/runtime/types/ets_class.cpp +++ b/plugins/ets/runtime/types/ets_class.cpp @@ -16,6 +16,7 @@ #include "include/language_context.h" #include "include/mem/panda_containers.h" #include "libpandabase/utils/utf.h" +#include "macros.h" #include "napi/ets_napi.h" #include "runtime/include/runtime.h" #include "plugins/ets/runtime/types/ets_array.h" @@ -80,6 +81,27 @@ EtsField *EtsClass::GetOwnFieldByIndex(uint32_t i) return EtsField::FromRuntimeField(&GetRuntimeClass()->GetFields()[i]); } +EtsField *EtsClass::GetFieldByName(EtsString *name) +{ + auto coroutine = EtsCoroutine::GetCurrent(); + [[maybe_unused]] HandleScope scope(coroutine); + VMHandle expected_name(coroutine, name->GetCoreType()); + + EtsField *res = nullptr; + EnumerateBaseClasses([&](EtsClass *c) { + auto fields = c->GetRuntimeClass()->GetFields(); + for (auto &f : fields) { + auto ets_field = EtsField::FromRuntimeField(&f); + if (ets_field->GetNameString()->StringsAreEqual(expected_name.GetPtr()->AsObject())) { + res = ets_field; + return true; + } + } + return false; + }); + return res; +} + EtsMethod *EtsClass::GetDirectMethod(const char *name, const char *signature) { auto core_name = reinterpret_cast(name); @@ -113,27 +135,15 @@ EtsMethod *EtsClass::GetDirectMethod(const char *name, const Method::Proto &prot uint32_t EtsClass::GetMethodsNum() { - uint32_t fnumber = 0; - EnumerateBaseClasses([&](EtsClass *c) { - fnumber += c->GetRuntimeClass()->GetMethods().Size(); - return false; - }); - return fnumber; + return GetMethods().size(); } -EtsMethod *EtsClass::GetMethodByIndex(uint32_t i) +EtsMethod *EtsClass::GetMethodByIndex(uint32_t ind) { EtsMethod *res = nullptr; - EnumerateBaseClasses([&](EtsClass *c) { - auto methods = c->GetRuntimeClass()->GetMethods(); - auto fnum = methods.Size(); - if (i >= fnum) { - i -= fnum; - return false; - } - res = EtsMethod::FromRuntimeMethod(&methods[i]); - return true; - }); + auto methods = GetMethods(); + ASSERT(ind < methods.size()); + res = methods[ind]; return res; } @@ -171,30 +181,60 @@ EtsMethod *EtsClass::GetMethod(const char *name, const char *signature) return reinterpret_cast(core_method); } +// TODO(kirill-mitkin): Cache in EtsClass field later PandaVector EtsClass::GetMethods() { - auto ets_methods = PandaVector(Runtime::GetCurrent()->GetInternalAllocator()->Adapter()); - EnumerateBaseClasses([&](EtsClass *c) { - auto methods = c->GetRuntimeClass()->GetMethods(); - auto fnum = methods.Size(); - for (uint32_t i = 0; i < fnum; i++) { - // Skip constructors of base classes - if (methods[i].IsConstructor() && c != this) { - continue; + PandaUnorderedMap unique_methods; + + auto add_direct_methods = [&](const EtsClass *c) { + auto direct_methods = c->GetRuntimeClass()->GetMethods(); + for (auto &method : direct_methods) { + auto name = PandaString(utf::Mutf8AsCString((method.GetName().data))); + if (unique_methods.find(name) == unique_methods.end()) { + unique_methods[name] = EtsMethod::FromRuntimeMethod(&method); } - ets_methods.push_back(EtsMethod::FromRuntimeMethod(&methods[i])); } - return false; - }); + }; + + if (IsInterface()) { + add_direct_methods(this); + EnumerateInterfaces([&](const EtsClass *c) { + add_direct_methods(c); + return false; + }); + } else { + EnumerateBaseClasses([&](EtsClass *c) { + auto direct_methods = c->GetRuntimeClass()->GetMethods(); + auto fnum = direct_methods.Size(); + for (uint32_t i = 0; i < fnum; i++) { + // Skip constructors + if (direct_methods[i].IsConstructor()) { + continue; + } + auto name = PandaString(utf::Mutf8AsCString((direct_methods[i].GetName().data))); + unique_methods[name] = EtsMethod::FromRuntimeMethod(&direct_methods[i]); + } + return false; + }); + } + auto ets_methods = PandaVector(); + for (auto &iter : unique_methods) { + ets_methods.push_back(iter.second); + } return ets_methods; } PandaVector EtsClass::GetConstructors() { auto constructors = PandaVector(); - auto methods = GetMethods(); - std::copy_if(methods.begin(), methods.end(), std::back_inserter(constructors), - [this](EtsMethod *method) { return method->IsInstanceConstructor() && method->GetClass() == this; }); + auto methods = GetRuntimeClass()->GetMethods(); + // TODO(kirill-mitkin): cache in ets_class field + for (auto &method : methods) { + // Skip constructors + if (method.IsInstanceConstructor()) { + constructors.emplace_back(EtsMethod::FromRuntimeMethod(&method)); + } + } return constructors; } diff --git a/plugins/ets/runtime/types/ets_class.h b/plugins/ets/runtime/types/ets_class.h index 965688ae0c344b7f993ee38b9e467f1ae09f2ef1..7c72cb9f5ff52dfc7d3ac8f59797a88e93adef25 100644 --- a/plugins/ets/runtime/types/ets_class.h +++ b/plugins/ets/runtime/types/ets_class.h @@ -91,6 +91,8 @@ public: EtsField *GetOwnFieldByIndex(uint32_t i); + EtsField *GetFieldByName(EtsString *name); + EtsField *GetFieldIDByName(const char *name, const char *sig = nullptr) { auto u8name = reinterpret_cast(name); @@ -375,7 +377,7 @@ public: } template - void EnumerateInterfaces(const Callback &callback) + void EnumerateDirectInterfaces(const Callback &callback) { for (Class *runtime_interface : GetRuntimeClass()->GetInterfaces()) { EtsClass *interface = EtsClass::FromRuntimeClass(runtime_interface); @@ -386,6 +388,30 @@ public: } } + void GetInterfaces(PandaUnorderedSet &ifaces, EtsClass *iface) + { + ifaces.insert(iface); + EnumerateDirectInterfaces([&](EtsClass *runtime_interface) { + if (ifaces.find(runtime_interface) == ifaces.end()) { + runtime_interface->GetInterfaces(ifaces, runtime_interface); + } + return false; + }); + } + + template + void EnumerateInterfaces(const Callback &callback) + { + PandaUnorderedSet ifaces; + GetInterfaces(ifaces, this); + for (auto iface : ifaces) { + bool finished = callback(iface); + if (finished) { + break; + } + } + } + template void EnumerateBaseClasses(const Callback &callback) { diff --git a/plugins/ets/runtime/types/ets_type.h b/plugins/ets/runtime/types/ets_type.h index 0b338159e2845b427983f7480bcaa1e1e0120f14..a43bcc03358f8edf3aa28932e11162c0ddc6d11b 100644 --- a/plugins/ets/runtime/types/ets_type.h +++ b/plugins/ets/runtime/types/ets_type.h @@ -29,6 +29,7 @@ static constexpr char METHOD_PREFIX = 'M'; static constexpr const char *NULL_TYPE_DESC = "Null"; static constexpr const char *LAMBDA_PREFIX = "LambdaObject"; static constexpr const char *LAMBDA_METHOD_NAME = "invoke"; +static constexpr const char *CONSTRUCTOR_NAME = "constructor"; static constexpr char TYPE_DESC_DELIMITER = ';'; static constexpr const char *GETTER_BEGIN = ""; static constexpr const char *SETTER_BEGIN = ""; diff --git a/plugins/ets/runtime/types/ets_type_comptime_traits.h b/plugins/ets/runtime/types/ets_type_comptime_traits.h index 865f75d7077723a7dfb8d579bb5a0091478c492c..9adaa34565a5d7250483060115aaf5ff89010bc0 100644 --- a/plugins/ets/runtime/types/ets_type_comptime_traits.h +++ b/plugins/ets/runtime/types/ets_type_comptime_traits.h @@ -17,6 +17,7 @@ #include "ets_type.h" #include "ets_primitives.h" +#include "ets_array.h" namespace panda::ets { @@ -69,11 +70,62 @@ template <> struct EtsTypeEnumToCppTypeT { using Type = EtsObject *; }; + +template +struct EtsTypeEnumToEtsArrayTypeT; + +template <> +struct EtsTypeEnumToEtsArrayTypeT { + using Type = EtsBooleanArray; +}; + +template <> +struct EtsTypeEnumToEtsArrayTypeT { + using Type = EtsByteArray; +}; + +template <> +struct EtsTypeEnumToEtsArrayTypeT { + using Type = EtsCharArray; +}; + +template <> +struct EtsTypeEnumToEtsArrayTypeT { + using Type = EtsShortArray; +}; + +template <> +struct EtsTypeEnumToEtsArrayTypeT { + using Type = EtsIntArray; +}; + +template <> +struct EtsTypeEnumToEtsArrayTypeT { + using Type = EtsLongArray; +}; + +template <> +struct EtsTypeEnumToEtsArrayTypeT { + using Type = EtsFloatArray; +}; + +template <> +struct EtsTypeEnumToEtsArrayTypeT { + using Type = EtsDoubleArray; +}; + +template <> +struct EtsTypeEnumToEtsArrayTypeT { + using Type = EtsObjectArray; +}; } // namespace detail template using EtsTypeEnumToCppType = typename detail::EtsTypeEnumToCppTypeT::Type; +template +using EtsTypeEnumToEtsArrayType = typename detail::EtsTypeEnumToEtsArrayTypeT::Type; + /* make switch on EtsType compile-time * to func is passed argument, such that */ diff --git a/plugins/ets/stdlib/escompat/Reflect.ets b/plugins/ets/stdlib/escompat/Reflect.ets new file mode 100644 index 0000000000000000000000000000000000000000..9cd122de0b8ce12030691421fb6368fc4a59e19f --- /dev/null +++ b/plugins/ets/stdlib/escompat/Reflect.ets @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package escompat + +export class Reflect { + + private constructor () {} + + /** + * Gets the field of target, equivalent to target.key + * + * @param target the target object on which to get the field + * + * @param key the string name of the field to get + * + * @returns the value of the field + */ + // TODO(shumilov-petr): Make result type `Object | undefined` when `undefined` will be available + public static get(target: Object, key: string): Object | null { + if (target instanceof Char || + target instanceof Boolean || + target instanceof Byte || + target instanceof Short || + target instanceof Int || + target instanceof Long || + target instanceof Float || + target instanceof Double || + target instanceof String) { + throw new Error("`target` argument of Reflect.get must have fields") + } + if (!Reflect.has(target, key)) { + // TODO(shumilov-petr): Replace `null` into `undefined` + // return undefined + return null + } + let t = Type.of(target) + if (t instanceof ClassType) { + return (Value.of(target) as ClassValue).getFieldByName(key).getData() + } else if (t instanceof ArrayType) { + if (key == "length") { + return new Number((Value.of(target) as ArrayValue).getLength()) + } + } else if (t instanceof LambdaType) { + if (key == "length") { + return new Number((t as FunctionType).getParametersNum()) + } else if (key == "name") { + return "" + } + } else if (t instanceof EnumType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof UnionType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof TupleType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } + // TODO(shumilov-petr): Replace `null` into `undefined` + // return undefined + return null + } + + /** + * Gets the element of target, equivalent to target[index] + * + * @param target the target object on which to get the element + * + * @param key the number index of the element to get + * + * @returns the value of the element + */ + // TODO(shumilov-petr): Make result type `Object | undefined` when `undefined` will be available + public static get(target: Object, index: number): Object | null { + if (target instanceof Char || + target instanceof Boolean || + target instanceof Byte || + target instanceof Short || + target instanceof Int || + target instanceof Long || + target instanceof Float || + target instanceof Double || + target instanceof String) { + throw new Error("`target` argument of Reflect.get must be indexed") + } + if (!Reflect.has(target, index)) { + // TODO(shumilov-petr): Replace `null` into `undefined` + // return undefined + return null + } + let t = Type.of(target) + if (t instanceof ArrayType) { + let av = Value.of(target) as ArrayValue + return av.getElement(index as long).getData() + } else if (t instanceof EnumType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof UnionType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof TupleType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } + // TODO(shumilov-petr): Replace `null` into `undefined` + // return undefined + return null + } + + /** + * Sets the field of target, equivalent to target.key = value + * + * @param target the target object on which to set the field + * + * @param key the name of the field to set + * + * @param value the value to set. + * + * @returns a Boolean indicating whether or not setting the field was successful + */ + public static set(target: Object, key: string, value: Object): Boolean { + let v = Value.of(target) + let vt = v.getType() + if (vt instanceof ClassType) { + let ct = vt as ClassType + if (!ct.hasField(key)) { + return false + } + let cv = v as ClassValue + try { + cv.setFieldByName(key, Value.of(value)) + } catch (e: Error) { + return false + } + return true + } + return false + } + + /** + * Sets the element of target, equivalent to target[index] = value + * + * @param target the target object on which to set the element + * + * @param index the index of the element to set + * + * @param value the value to set. + * + * @returns a boolean indicating whether or not setting the element was successful + */ + public static set(target: Object, index: number, value: Object): Boolean { + let v = Value.of(target) + let vt = v.getType() + if (vt instanceof ArrayType) { + if (!Reflect.has(target, index)) { + return false + } + let av = v as ArrayValue + try { + av.setElement(index as long, Value.of(value)) + } catch (e: Error) { + return false + } + return true + } + return false + } + + /** + * Returns the names of the own fields of an object + * + * @param o object that contains the own fields + * + * @returns array representation of names + */ + public static ownKeys(target: Object): string[] { + return Object.getOwnPropertyNames(target) + } + + /** + * Determines whether an object has a field with the specified name + * + * @param target an object + * + * @param key a field name + * + * @returns a boolean indicating whether or not the target has the field + */ + public static has(target: Object, key: string): boolean { + return Object.hasOwn(target, key) + } + + /** + * Determines whether an object has a field with the specified name + * + * @param target an object + * + * @param index an element index + * + * @returns a boolean indicating whether or not the target has the element + */ + public static has(target: Object, index: number): boolean { + return Object.hasOwn(target, index) + } +} + diff --git a/plugins/ets/stdlib/escompat/json.ets b/plugins/ets/stdlib/escompat/json.ets index 153de97b50585023a518bd9525ee4d716c822b9a..a9c18f2779e5cf5d54fac40837e6f65e60ba0eae 100644 --- a/plugins/ets/stdlib/escompat/json.ets +++ b/plugins/ets/stdlib/escompat/json.ets @@ -368,7 +368,7 @@ export class JSON { return JSON.checkType(typ, new Array()) } - public static parse(str: String, typ: Type): T | null { + public static parse(str: String, typ: Type): NullishType { if (!JSON.checkType(typ, new Array())) { throw new Error("Incorrect type: " + typ.toString()) } @@ -381,7 +381,7 @@ export class JSON { let cVal = Value.of(object) as ClassValue let unboxString : (v: JSONString) => String = (v: JSONString): String => { return v.value } - let fieldArray = jVal.keys.map(unboxString) + let fieldArray = jVal.keys_.map(unboxString) for (let field_num = 0; field_num < cType.getFieldsNum(); field_num++) { let field : Field = cType.getField(field_num) let indexInJSON = fieldArray.indexOf(field.getName()) @@ -401,7 +401,7 @@ export class JSON { let arrVal = Value.of(arr) as ArrayValue for (let i = 0; i < len; i++) { let elem = JSON.parse(jVal.values.at(i) as JSONValue, aType.getElementType()) - arrVal.setElementByIndex(i, Value.of(elem)) + arrVal.setElement(i, Value.of(elem)) } return arr } @@ -551,7 +551,7 @@ export class JSONParser { } private parseKeyValue(res: JSONObject): JSONObject { - res.keys.push(this.parse(new JSONValue()) as JSONString) + res.keys_.push(this.parse(new JSONValue()) as JSONString) this.getNextChar() if (this.curChar != c':') { throw new SyntaxError("Expected : \",\" at " + this.getCurPosDescr() + " got \"" + this.curChar + "\"") @@ -692,7 +692,7 @@ export class JSONParser { export class JSONValue extends Object {} export class JSONObject extends JSONValue { - keys: Array = new Array() + keys_: Array = new Array() values: Array = new Array() readonly static START_CHAR = c'{' readonly static END_CHAR = c'}' @@ -701,11 +701,11 @@ export class JSONObject extends JSONValue { public override toString(): String { let res = new StringBuilder([JSONObject.START_CHAR]) - for (let i = 0; i < this.keys.length() - 1; ++i) { - res.append("" + this.keys.at(i) + JSONObject.SEPARATOR + this.values.at(i) + JSONObject.DELIMETER) + for (let i = 0; i < this.keys_.length() - 1; ++i) { + res.append("" + this.keys_.at(i) + JSONObject.SEPARATOR + this.values.at(i) + JSONObject.DELIMETER) } - if (this.keys.length() > 0) { - res.append("" + this.keys.at(this.keys.length() - 1) + JSONObject.SEPARATOR + this.values.at(this.keys.length() - 1)) + if (this.keys_.length() > 0) { + res.append("" + this.keys_.at(this.keys_.length() - 1) + JSONObject.SEPARATOR + this.values.at(this.keys_.length() - 1)) } res.append(JSONObject.END_CHAR) return res.toString() diff --git a/plugins/ets/stdlib/std/core/Field.ets b/plugins/ets/stdlib/std/core/Field.ets index b9c11d1f578f6c99f3ad2535ee27752cac595bf7..99c7b4d22f4b26ed2be06b1ef38be380f9da5c24 100644 --- a/plugins/ets/stdlib/std/core/Field.ets +++ b/plugins/ets/stdlib/std/core/Field.ets @@ -77,4 +77,12 @@ export final class Field extends Object { public override toString(): string { return this.getName() + ": " + this.getType().toString() } + + public override equals(oth: NullishType): boolean { + return oth instanceof Field && + this.td == (oth as Field).td && + this.name == (oth as Field).name && + this.accessMod == (oth as Field).accessMod && + this.attributes == (oth as Field).attributes + } } \ No newline at end of file diff --git a/plugins/ets/stdlib/std/core/Method.ets b/plugins/ets/stdlib/std/core/Method.ets index d5ad4835b83165dbf7d93a1fdb25240f33792c11..7dd4bb43706a157859c0e758af52ef465426bd37 100644 --- a/plugins/ets/stdlib/std/core/Method.ets +++ b/plugins/ets/stdlib/std/core/Method.ets @@ -94,4 +94,20 @@ export final class Method extends Object { return TypeAPIMethodInvoke(this.td, recv, convertedArgs) } } + + public getAttributes(): int { + return this.attributes + } + + public getAccessModifier(): int { + return this.accessMod + } + + public override equals(oth: NullishType): boolean { + return oth instanceof Method && + this.td == (oth as Method).td && + this.name == (oth as Method).name && + this.accessMod == (oth as Method).accessMod && + this.attributes == (oth as Method).attributes + } } diff --git a/plugins/ets/stdlib/std/core/Object.ets b/plugins/ets/stdlib/std/core/Object.ets index 4c5d6a02ae58104870b3e80ea29e046c6a610fb9..f016300bb33e27b636c80203aed60003c0df865a 100644 --- a/plugins/ets/stdlib/std/core/Object.ets +++ b/plugins/ets/stdlib/std/core/Object.ets @@ -15,6 +15,9 @@ package std.core; +// TODO(shumilov-petr): Temporary solution +type Tuple = Object[] + /** * Common ancestor amongst all other classes */ @@ -31,7 +34,7 @@ export class Object { * @returns result of the conversion */ public toString(): String { - return Type.of(this).toString(); + return Value.of(this).toString() } /** @@ -50,9 +53,332 @@ export class Object { * * @returns true if provided object and this instance have same references, false otherwise */ - public equals(to: Object|null): boolean { + public equals(to: NullishType): boolean { return runtime.equals(this, to); } + + /** + * Returns the names of the fields of an object + * + * @param o an object + * + * @returns an array of strings representing the given object's own string-keyed field keys. + */ + public static keys(o: Object): string[] { + // Char, Boolean and Numeric types doesn't have keys + if (o instanceof Char || + o instanceof Boolean || + o instanceof Byte || + o instanceof Short || + o instanceof Int || + o instanceof Long || + o instanceof Float || + o instanceof Double) { + return new string[0] + } + // "Keys" for the string type is enumeration from 0 to str.length - 1 + if (o instanceof String) { + let sv = o as string + let len = sv.length() + let res = new string[len as int] + for (let i = 0; i < len; i++) { + // TODO(shumilov-petr): need to apply more effective way for int to String conversion + res[i] = new Int(i).toString() + } + return res + } + let t = Type.of(o) + if (t instanceof ClassType) { + let ct = t as ClassType + let fnum = ct.getFieldsNum() + let n: int = 0 + for (let i = 0; i < fnum; i++) { + if (!ct.getField(i).isStatic()) { + n++ + } + } + let res = new string[n] + let j: int = 0 + for (let i = 0; i < fnum; i++) { + let f = ct.getField(i) + if (!f.isStatic()) { + res[j] = f.getName() + j++ + } + } + return res + } else if (t instanceof ArrayType) { + let av = Value.of(o) as ArrayValue + let len = av.getLength() + let res = new string[len as int] + for (let i = 0; i < len; i++) { + res[i] = new Int(i).toString() + } + return res + } else if (t instanceof LambdaType) { + return new string[0] + } else if (t instanceof EnumType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof UnionType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof TupleType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } + assert(false) + } + + /** + * Returns the values of the fields of an object + * + * @param o an object + * + * @returns an array containing the given object's own string-keyed field values + */ + // TODO(shumilov-petr): Need to rename into `values`. Blocked by Object's childs + public static values__(o: Object): Object[] { + if (o instanceof Char || + o instanceof Boolean || + o instanceof Byte || + o instanceof Short || + o instanceof Int || + o instanceof Long || + o instanceof Float || + o instanceof Double) { + return new Object[0] + } + if (o instanceof String) { + let sv = o as string + let len = sv.length() + let res = new Object[len] + for (let i = 0; i < len; i++) { + res[i] = new StringBuilder().append(sv.charAt(i)).toString() + } + return res + } + let t = Type.of(o) + if (t instanceof ClassType) { + let cv = Value.of(o) as ClassValue + let keys = Object.keys(o) + let len = keys.length + let res = new Object[len] + for (let i = 0; i < len; i++) { + res[i] = cv.getFieldByName(keys[i]).getData() + } + return res + } else if (t instanceof ArrayType) { + let av = Value.of(o) as ArrayValue + let len = av.getLength() + let res = new Object[len as int] + for (let i = 0; i < len; i++) { + res[i] = av.getElement(i).getData() + } + return res + } else if (t instanceof LambdaType) { + return new Object[0] + } else if (t instanceof EnumType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof UnionType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof TupleType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } + assert(false) + } + + /** + * Returns an array of key/values of properties of an object + * + * @param o object that contains the fields + * + * @returns array representation of key/values + */ + public static entries(o: Object): Tuple[] { + if (o instanceof Char || + o instanceof Boolean || + o instanceof Byte || + o instanceof Short || + o instanceof Int || + o instanceof Long || + o instanceof Float || + o instanceof Double) { + return new Tuple[0] + } + if (o instanceof String) { + let sv = o as string + let len = sv.length() + let res = new Tuple[len] + for (let i = 0; i < len; i++) { + res[i] = new Object[2] + res[i][0] = new Int(i).toString() + res[i][1] = new StringBuilder().append(sv.charAt(i)).toString() + } + return res + } + let t = Type.of(o) + if (t instanceof ClassType) { + let cv = Value.of(o) as ClassValue + let keys = Object.keys(o) + let len = keys.length + let res = new Tuple[len] + for (let i = 0; i < len; i++) { + res[i] = new Object[2] + res[i][0] = keys[i] + res[i][1] = cv.getFieldByName(keys[i]).getData() + } + return res + } else if (t instanceof ArrayType) { + let av = Value.of(o) as ArrayValue + let len = av.getLength() + let res = new Tuple[len as int] + for (let i = 0; i < len; i++) { + res[i] = new Object[2] + res[i][0] = new Int(i).toString() + res[i][1] = av.getElement(i).getData() + } + return res + } else if (t instanceof LambdaType) { + return new Tuple[0] + } else if (t instanceof EnumType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof UnionType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof TupleType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } + assert(false) + } + + /** + * Returns the names of the own fields of an object + * + * @param o object that contains the own fields + * + * @returns array representation of names + */ + public static getOwnPropertyNames(o: Object): string[] { + if (o instanceof Char || + o instanceof Boolean || + o instanceof Byte || + o instanceof Short || + o instanceof Int || + o instanceof Long || + o instanceof Float || + o instanceof Double) { + return new string[0] + } + let t = Type.of(o) + if (t instanceof StringType || t instanceof ArrayType) { + let keys = Object.keys(o) + let len = keys.length + let res = new string[len + 1] + for (let i = 0; i < len; i++) { + res[i] = keys[i] + } + res[len] = "length" + return res + } + if (t instanceof ClassType) { + return Object.keys(o) + } else if (t instanceof LambdaType) { + return ["length", "name"] + } else if (t instanceof EnumType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof UnionType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof TupleType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } + assert(false) + } + + /** + * Determines whether an object has a field with the specified name + * + * @param key the string name of the field to test + * + * @returns true if the object has the specified field; false otherwise + */ + public hasOwnProperty(key: string): boolean { + let keys = Object.getOwnPropertyNames(this) + let len = keys.length + for(let i = 0; i < len; i++) { + if (keys[i] == key) { + return true + } + } + return false + } + + /** + * Determines whether an object has a element with the specified index + * + * @param index the number index of the element to test + * + * @returns true if the object has the specified element; false otherwise + */ + public hasOwnProperty(index: number): boolean { + if ((this) instanceof String) { + let sv = this as String + let len = sv.length() + let idx = index as long + return (0 <= idx && idx < len) + } + let t = Type.of(this) + if (t instanceof ArrayType) { + let av = Value.of(this) as ArrayValue + let len = av.getLength() + let idx = index as long + return (0 <= idx && idx < len) + } else if (t instanceof EnumType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof UnionType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } else if (t instanceof TupleType) { + // TODO(shumilov-petr): Not implemented + throw new Error("Not implemented") + } + return false + } + + /** + * Determines whether an object has a field with the specified name + * + * @param target an object + * + * @param key the string name of the field to test + * + * @returns true if the object has the specified field; false otherwise + */ + public static hasOwn(target: Object, key: string): boolean { + return target.hasOwnProperty(key) + } + + /** + * Determines whether an object has a element with the specified index + * + * @param target an object + * + * @param index the number index of the element to test + * + * @returns true if the object has the specified element; false otherwise + */ + public static hasOwn(target: Object, index: number): boolean { + return target.hasOwnProperty(index) + } } export type NullishType = Object | null diff --git a/plugins/ets/stdlib/std/core/Parameter.ets b/plugins/ets/stdlib/std/core/Parameter.ets index e58145eea59abeda53fdaaaa77d818d7f2927bbf..b365a029a1528d97f0358f3d9d6677bf2100fe8a 100644 --- a/plugins/ets/stdlib/std/core/Parameter.ets +++ b/plugins/ets/stdlib/std/core/Parameter.ets @@ -45,4 +45,11 @@ export final class Parameter extends Object { public override toString(): string { return this.getName() + ": " + this.getType().toString() } + + public override equals(oth: Object|null): boolean { + return oth instanceof Parameter && + this.td == (oth as Parameter).td && + this.name == (oth as Parameter).name && + this.attributes == (oth as Parameter).attributes + } } diff --git a/plugins/ets/stdlib/std/core/Type.ets b/plugins/ets/stdlib/std/core/Type.ets index a2339d2a107fbd6f592ec4d464f394333efc0159..9dc18f8abc117fa9bc9baed9c90c9e58d1981482 100644 --- a/plugins/ets/stdlib/std/core/Type.ets +++ b/plugins/ets/stdlib/std/core/Type.ets @@ -346,8 +346,8 @@ export abstract class Type extends Object { if (this.equals(other)) { return true } else if (other.equals(ObjectType)) { - let isNullable = (this) instanceof UndefinedType || (this) instanceof NullType - return this.isReference() && !isNullable && !((this) instanceof VoidType) + let isNullish = (this) instanceof UndefinedType || (this) instanceof NullType + return this.isReference() && !isNullish && !((this) instanceof VoidType) } return false } @@ -1036,6 +1036,16 @@ export final class ClassType extends Type { return false } + public hasMethod(name: string): boolean { + let mnum = this.getMethodsNum() + for (let i = 0; i < mnum; ++i) { + if (this.getMethod(i).getName() == name) { + return true + } + } + return false + } + public getTypeParametersNum(): long { // TODO(shumilov-petr): not implemented throw new Error("Not implemented") @@ -1143,7 +1153,6 @@ export final class ClassType extends Type { } return obj } - } @@ -1197,13 +1206,11 @@ export final class InterfaceType extends Type { } public getMethodsNum(): long { - // TODO(shumilov-petr): not implemented - return 0 + return TypeAPIGetMethodsNum(this.td) } public getMethod(i: long): Method { - // TODO(shumilov-petr): not implemented - throw new Error("Not implemented") + return TypeAPIGetMethod(this.td, i) } public getTypeParametersNum(): long { @@ -1253,6 +1260,16 @@ export final class InterfaceType extends Type { return false } + public hasMethod(name: string): boolean { + let mnum = this.getMethodsNum() + for (let i = 0; i < mnum; ++i) { + if (this.getMethod(i).getName() == name) { + return true + } + } + return false + } + internal override convertObject(obj: NullishType): NullishType { const objType = Type.of(obj) if (!this.assignableFrom(objType)) { @@ -1378,7 +1395,6 @@ export final class ArrayType extends Type { } } - export final class TupleType extends Type { public constructor(td: TypeDesc) { this.td = td @@ -1763,4 +1779,3 @@ export final class UnionType extends Type { return obj } } - diff --git a/plugins/ets/stdlib/std/core/Value.ets b/plugins/ets/stdlib/std/core/Value.ets index 834d03b610a478c54b6a44ad8b84e6ea21125bb8..e428087930a2800a89621420d0f60202aa864fe4 100644 --- a/plugins/ets/stdlib/std/core/Value.ets +++ b/plugins/ets/stdlib/std/core/Value.ets @@ -16,6 +16,7 @@ package std.core; // Class Value + native function ValueAPIGetFieldBoolean(obj: Object, i: long): boolean native function ValueAPIGetFieldByte(obj: Object, i: long): byte @@ -35,6 +36,25 @@ native function ValueAPIGetFieldLong(obj: Object, i: long): long native function ValueAPIGetFieldObject(obj: Object, i: long): Object +native function ValueAPIGetFieldByNameBoolean(obj: Object, name: String): boolean + +native function ValueAPIGetFieldByNameByte(obj: Object, name: String): byte + +native function ValueAPIGetFieldByNameShort(obj: Object, name: String): short + +native function ValueAPIGetFieldByNameChar(obj: Object, name: String): char + +native function ValueAPIGetFieldByNameInt(obj: Object, name: String): int + +native function ValueAPIGetFieldByNameFloat(obj: Object, name: String): float + +native function ValueAPIGetFieldByNameDouble(obj: Object, name: String): double + +native function ValueAPIGetFieldByNameLong(obj: Object, name: String): long + +native function ValueAPIGetFieldByNameObject(obj: Object, name: String): Object + + native function ValueAPISetFieldBoolean(obj: Object, i: long, val: boolean): void native function ValueAPISetFieldByte(obj: Object, i: long, val: byte): void @@ -73,6 +93,8 @@ native function ValueAPISetFieldByNameLong(obj: Object, name: String, val: long) native function ValueAPISetFieldByNameObject(obj: Object, name: String, val: Object): void // Array Value +native function ValueAPIGetArrayLength(obj: Object): long + native function ValueAPISetElementBoolean(obj: Object, i: long, val: boolean): void native function ValueAPISetElementByte(obj: Object, i: long, val: byte): void @@ -91,39 +113,180 @@ native function ValueAPISetElementLong(obj: Object, i: long, val: long): void native function ValueAPISetElementObject(obj: Object, i: long, val: Object): void + +native function ValueAPIGetElementBoolean(obj: Object, i: long): boolean + +native function ValueAPIGetElementByte(obj: Object, i: long): byte + +native function ValueAPIGetElementShort(obj: Object, i: long): short + +native function ValueAPIGetElementChar(obj: Object, i: long): char + +native function ValueAPIGetElementInt(obj: Object, i: long): int + +native function ValueAPIGetElementFloat(obj: Object, i: long): float + +native function ValueAPIGetElementDouble(obj: Object, i: long): double + +native function ValueAPIGetElementLong(obj: Object, i: long): long + +native function ValueAPIGetElementObject(obj: Object, i: long): Object + export abstract class Value extends Object { + public static of(v: boolean): Value { + return new BooleanValue(BooleanType.VAL, v) + } + + public static of(v: char): Value { + return new CharValue(CharType.VAL, v) + } + + public static of(v: byte): Value { + return new ByteValue(ByteType.VAL, v) + } + + public static of(v: short): Value { + return new ShortValue(ShortType.VAL, v) + } + + public static of(v: int): Value { + return new IntValue(IntType.VAL, v) + } + + public static of(v: long): Value { + return new LongValue(LongType.VAL, v) + } + + public static of(v: float): Value { + return new FloatValue(FloatType.VAL, v) + } + + public static of(v: double): Value { + return new DoubleValue(DoubleType.VAL, v) + } + + // ----- + + public static of(v: Boolean): Value { + return new BooleanValue(BooleanType.REF, v) + } + + public static of(v: Char): Value { + return new CharValue(CharType.REF, v) + } + + public static of(v: Byte): Value { + return new ByteValue(ByteType.REF, v) + } + + public static of(v: Short): Value { + return new ShortValue(ShortType.REF, v) + } + + public static of(v: Int): Value { + return new IntValue(IntType.REF, v) + } + + public static of(v: Long): Value { + return new LongValue(LongType.REF, v) + } + + public static of(v: Float): Value { + return new FloatValue(FloatType.REF, v) + } + + public static of(v: Double): Value { + return new DoubleValue(DoubleType.REF, v) + } + + // ----- + public static of(o: NullishType): Value { + if (o instanceof Value) { + return o as Value + } else if (o instanceof Boolean) { + return new BooleanValue(BooleanType.REF, o as Boolean) + } else if (o instanceof Char) { + return new CharValue(CharType.REF, o as Char) + } else if (o instanceof Byte) { + return new ByteValue(ByteType.REF, o as Byte) + } else if (o instanceof Short) { + return new ShortValue(ShortType.REF, o as Short) + } else if (o instanceof Int) { + return new IntValue(IntType.REF, o as Int) + } else if (o instanceof Long) { + return new LongValue(LongType.REF, o as Long) + } else if (o instanceof Float) { + return new FloatValue(FloatType.REF, o as Float) + } else if (o instanceof Double) { + return new DoubleValue(DoubleType.REF, o as Double) + } + let t = Type.of(o) if (t instanceof NullType) { return NullValue.INSTANCE + } else if (t instanceof VoidType) { + return new VoidValue() + } else if (t instanceof UndefinedType) { + return new UndefinedValue() } else if (t instanceof ClassType) { return new ClassValue(t as ClassType, o!) } else if (t instanceof ArrayType) { return new ArrayValue(t as ArrayType, o!) } else if (t instanceof StringType) { - return new StringValue(t as StringType, o! as String) - } else if (t instanceof BooleanType) { - return new BooleanValue(t as BooleanType, o! as Boolean) - } else if (t instanceof ByteType) { - return new ByteValue(t as ByteType, o! as Byte) - } else if (t instanceof ShortType) { - return new ShortValue(t as ShortType, o! as Short) - } else if (t instanceof CharType) { - return new CharValue(t as CharType, o! as Char) - } else if (t instanceof IntType) { - return new IntValue(t as IntType, o! as Int) - } else if (t instanceof FloatType) { - return new FloatValue(t as FloatType, o! as Float) - } else if (t instanceof DoubleType) { - return new DoubleValue(t as DoubleType, o! as Double) - } else if (t instanceof LongType) { - return new LongValue(t as LongType, o! as Long) - } else { + return new StringValue(t as StringType, o! as string) + } else if (t instanceof LambdaType) { + return new LambdaValue(t as LambdaType, o!) + } else if (t instanceof MethodType) { + throw new Error("The MethodType cannot be instantiated") + } else if (t instanceof EnumType) { + throw new Error("Not implemented") + } else if (t instanceof UnionType) { + throw new Error("Not implemented") + } else if (t instanceof TupleType) { throw new Error("Not implemented") } + // TODO(shumilov-petr): throw `unknown type` exception + assert(false) + } + + // ----- + + public static of(v: boolean[]): Value { + return new ArrayValue(ArrayType.BOOLEAN_VAL, v) + } + + public static of(v: char[]): Value { + return new ArrayValue(ArrayType.CHAR_VAL, v) + } + + public static of(v: byte[]): Value { + return new ArrayValue(ArrayType.BYTE_VAL, v) + } + + public static of(v: short[]): Value { + return new ArrayValue(ArrayType.SHORT_VAL, v) + } + + public static of(v: int[]): Value { + return new ArrayValue(ArrayType.INT_VAL, v) + } + + public static of(v: long[]): Value { + return new ArrayValue(ArrayType.LONG_VAL, v) + } + + public static of(v: float[]): Value { + return new ArrayValue(ArrayType.FLOAT_VAL, v) + } + + public static of(v: double[]): Value { + return new ArrayValue(ArrayType.DOUBLE_VAL, v) } public abstract getType(): Type + + public abstract getData(): Object } export final class ClassValue extends Value { @@ -134,7 +297,7 @@ export final class ClassValue extends Value { return this.typ as Type } - public getData(): Object { + public override getData(): Object { return this.data } @@ -148,7 +311,11 @@ export final class ClassValue extends Value { } public getField(i: long): Value { - let ft = this.typ.getField(i).getType() + let f = this.typ.getField(i) + if (f.isStatic()) { + throw new Error("Field must be not static") + } + let ft = f.getType() if (!ft.isReference()) { if (ft instanceof BooleanType) { return new BooleanValue(ft as BooleanType, ValueAPIGetFieldBoolean(this.data, i)) @@ -171,30 +338,63 @@ export final class ClassValue extends Value { return Value.of(ValueAPIGetFieldObject(this.data, i)) } + public getFieldByName(name: string): Value { + let f = this.typ.getFieldByName(name) + if (f.isStatic()) { + throw new Error("Field must be not static") + } + const ft = f.getType() + if (!ft.isReference()) { + if (ft instanceof BooleanType) { + return new BooleanValue(ft as BooleanType, ValueAPIGetFieldByNameBoolean(this.data, name)) + } else if (ft instanceof ByteType) { + return new ByteValue(ft as ByteType, ValueAPIGetFieldByNameByte(this.data, name)) + } else if (ft instanceof ShortType) { + return new ShortValue(ft as ShortType, ValueAPIGetFieldByNameShort(this.data, name)) + } else if (ft instanceof CharType) { + return new CharValue(ft as CharType, ValueAPIGetFieldByNameChar(this.data, name)) + } else if (ft instanceof IntType) { + return new IntValue(ft as IntType, ValueAPIGetFieldByNameInt(this.data, name)) + } else if (ft instanceof FloatType) { + return new FloatValue(ft as FloatType, ValueAPIGetFieldByNameFloat(this.data, name)) + } else if (ft instanceof DoubleType) { + return new DoubleValue(ft as DoubleType, ValueAPIGetFieldByNameDouble(this.data, name)) + } else if (ft instanceof LongType) { + return new LongValue(ft as LongType, ValueAPIGetFieldByNameLong(this.data, name)) + } + assert(false) + } + return Value.of(ValueAPIGetFieldByNameObject(this.data, name)) + } + public setFieldByName(name: string, val: Value) { - let ft = this.typ.getFieldByName(name).getType() + let f = this.typ.getFieldByName(name) + if (f.isStatic()) { + throw new Error("Field must be not static") + } + let ft = f.getType() let vt = val.getType() if (!ft.assignableFrom(vt)) { throw new Error("Cannot assign field of type " + ft + " with value of type " + vt) } if (ft instanceof BooleanType && val instanceof BooleanValue) { - ValueAPISetFieldByNameBoolean(this.data, name, (val as BooleanValue).getData()) + ValueAPISetFieldByNameBoolean(this.data, name, (val as BooleanValue).getValueData()) } else if (ft instanceof ByteType && val instanceof ByteValue) { - ValueAPISetFieldByNameByte(this.data, name, (val as ByteValue).getData()) + ValueAPISetFieldByNameByte(this.data, name, (val as ByteValue).getValueData()) } else if (ft instanceof ShortType && val instanceof ShortValue) { - ValueAPISetFieldByNameShort(this.data, name, (val as ShortValue).getData()) + ValueAPISetFieldByNameShort(this.data, name, (val as ShortValue).getValueData()) } else if (ft instanceof CharType && val instanceof CharValue) { - ValueAPISetFieldByNameChar(this.data, name, (val as CharValue).getData()) + ValueAPISetFieldByNameChar(this.data, name, (val as CharValue).getValueData()) } else if (ft instanceof IntType && val instanceof IntValue) { - ValueAPISetFieldByNameInt(this.data, name, (val as IntValue).getData()) + ValueAPISetFieldByNameInt(this.data, name, (val as IntValue).getValueData()) } else if (ft instanceof FloatType && val instanceof FloatValue) { - ValueAPISetFieldByNameFloat(this.data, name, (val as FloatValue).getData()) + ValueAPISetFieldByNameFloat(this.data, name, (val as FloatValue).getValueData()) } else if (ft instanceof DoubleType && val instanceof DoubleValue) { - ValueAPISetFieldByNameDouble(this.data, name, (val as DoubleValue).getData()) + ValueAPISetFieldByNameDouble(this.data, name, (val as DoubleValue).getValueData()) } else if (ft instanceof LongType && val instanceof LongValue) { - ValueAPISetFieldByNameLong(this.data, name, (val as LongValue).getData()) + ValueAPISetFieldByNameLong(this.data, name, (val as LongValue).getValueData()) } else if (ft instanceof StringType && val instanceof StringValue) { - ValueAPISetFieldByNameObject(this.data, name, (val as StringValue).getData()) + ValueAPISetFieldByNameObject(this.data, name, (val as StringValue).getData() as string) } else if (ft instanceof ArrayType && val instanceof ArrayValue) { ValueAPISetFieldByNameObject(this.data, name, (val as ArrayValue).getData()) } else if (ft instanceof ClassType && val instanceof ClassValue) { @@ -205,29 +405,33 @@ export final class ClassValue extends Value { } public setField(i: long, val: Value) { - let ft = this.typ.getField(i).getType() + let f = this.typ.getField(i) + if (f.isStatic()) { + throw new Error("Field must be not static") + } + let ft = f.getType() let vt = val.getType() if (!ft.assignableFrom(vt)) { throw new Error("Cannot assign field of type " + ft + " with value of type " + vt) } if (ft instanceof BooleanType && val instanceof BooleanValue) { - ValueAPISetFieldBoolean(this.data, i, (val as BooleanValue).getData()) + ValueAPISetFieldBoolean(this.data, i, (val as BooleanValue).getValueData()) } else if (ft instanceof ByteType && val instanceof ByteValue) { - ValueAPISetFieldByte(this.data, i, (val as ByteValue).getData()) + ValueAPISetFieldByte(this.data, i, (val as ByteValue).getValueData()) } else if (ft instanceof ShortType && val instanceof ShortValue) { - ValueAPISetFieldShort(this.data, i, (val as ShortValue).getData()) + ValueAPISetFieldShort(this.data, i, (val as ShortValue).getValueData()) } else if (ft instanceof CharType && val instanceof CharValue) { - ValueAPISetFieldChar(this.data, i, (val as CharValue).getData()) + ValueAPISetFieldChar(this.data, i, (val as CharValue).getValueData()) } else if (ft instanceof IntType && val instanceof IntValue) { - ValueAPISetFieldInt(this.data, i, (val as IntValue).getData()) + ValueAPISetFieldInt(this.data, i, (val as IntValue).getValueData()) } else if (ft instanceof FloatType && val instanceof FloatValue) { - ValueAPISetFieldFloat(this.data, i, (val as FloatValue).getData()) + ValueAPISetFieldFloat(this.data, i, (val as FloatValue).getValueData()) } else if (ft instanceof DoubleType && val instanceof DoubleValue) { - ValueAPISetFieldDouble(this.data, i, (val as DoubleValue).getData()) + ValueAPISetFieldDouble(this.data, i, (val as DoubleValue).getValueData()) } else if (ft instanceof LongType && val instanceof LongValue) { - ValueAPISetFieldLong(this.data, i, (val as LongValue).getData()) + ValueAPISetFieldLong(this.data, i, (val as LongValue).getValueData()) } else if (ft instanceof StringType && val instanceof StringValue) { - ValueAPISetFieldObject(this.data, i, (val as StringValue).getData()) + ValueAPISetFieldObject(this.data, i, (val as StringValue).getData() as string) } else if (ft instanceof ArrayType && val instanceof ArrayValue) { ValueAPISetFieldObject(this.data, i, (val as ArrayValue).getData()) } else if (ft instanceof ClassType && val instanceof ClassValue) { @@ -237,6 +441,22 @@ export final class ClassValue extends Value { } } + public override toString(): string { + const fnum = this.getFieldsNum() + let res = new StringBuilder("{") + for (let i = 0; i < fnum; i++) { + const f = this.typ.getField(i) + const fv = this.getField(i) + res.append(f.getName()) + res.append(": ") + res.append(fv.toString()) + if (i != fnum - 1) { + res.append(", ") + } + } + res.append("}") + return res.toString() + } } export final class ArrayValue extends Value { @@ -247,7 +467,7 @@ export final class ArrayValue extends Value { return this.typ as Type } - public getData(): Object { + public override getData(): Object { return this.data } @@ -256,30 +476,59 @@ export final class ArrayValue extends Value { this.data = data } - public setElementByIndex(i: long, val: Value) { + public getLength(): long { + return ValueAPIGetArrayLength(this.data) + } + + public getElement(i: long): Value { + const et = this.typ.getElementType() + if (!et.isReference()) { + if (et instanceof BooleanType) { + return new BooleanValue(et as BooleanType, ValueAPIGetElementBoolean(this.data, i)) + } else if (et instanceof ByteType) { + return new ByteValue(et as ByteType, ValueAPIGetElementByte(this.data, i)) + } else if (et instanceof ShortType) { + return new ShortValue(et as ShortType, ValueAPIGetElementShort(this.data, i)) + } else if (et instanceof CharType) { + return new CharValue(et as CharType, ValueAPIGetElementChar(this.data, i)) + } else if (et instanceof IntType) { + return new IntValue(et as IntType, ValueAPIGetElementInt(this.data, i)) + } else if (et instanceof FloatType) { + return new FloatValue(et as FloatType, ValueAPIGetElementFloat(this.data, i)) + } else if (et instanceof DoubleType) { + return new DoubleValue(et as DoubleType, ValueAPIGetElementDouble(this.data, i)) + } else if (et instanceof LongType) { + return new LongValue(et as LongType, ValueAPIGetElementLong(this.data, i)) + } + assert(false) + } + return Value.of(ValueAPIGetElementObject(this.data, i)) + } + + public setElement(i: long, val: Value) { let et = this.typ.getElementType() let vt = val.getType() if (!et.assignableFrom(vt)) { throw new Error("Cannot assign array of type " + et + " with value of type " + vt) } if (et instanceof BooleanType && val instanceof BooleanValue) { - ValueAPISetElementBoolean(this.data, i, (val as BooleanValue).getData()) + ValueAPISetElementBoolean(this.data, i, (val as BooleanValue).getValueData()) } else if (et instanceof ByteType && val instanceof ByteValue) { - ValueAPISetElementByte(this.data, i, (val as ByteValue).getData()) + ValueAPISetElementByte(this.data, i, (val as ByteValue).getValueData()) } else if (et instanceof ShortType && val instanceof ShortValue) { - ValueAPISetElementShort(this.data, i, (val as ShortValue).getData()) + ValueAPISetElementShort(this.data, i, (val as ShortValue).getValueData()) } else if (et instanceof CharType && val instanceof CharValue) { - ValueAPISetElementChar(this.data, i, (val as CharValue).getData()) + ValueAPISetElementChar(this.data, i, (val as CharValue).getValueData()) } else if (et instanceof IntType && val instanceof IntValue) { - ValueAPISetElementInt(this.data, i, (val as IntValue).getData()) + ValueAPISetElementInt(this.data, i, (val as IntValue).getValueData()) } else if (et instanceof FloatType && val instanceof FloatValue) { - ValueAPISetElementFloat(this.data, i, (val as FloatValue).getData()) + ValueAPISetElementFloat(this.data, i, (val as FloatValue).getValueData()) } else if (et instanceof DoubleType && val instanceof DoubleValue) { - ValueAPISetElementDouble(this.data, i, (val as DoubleValue).getData()) + ValueAPISetElementDouble(this.data, i, (val as DoubleValue).getValueData()) } else if (et instanceof LongType && val instanceof LongValue) { - ValueAPISetElementLong(this.data, i, (val as LongValue).getData()) + ValueAPISetElementLong(this.data, i, (val as LongValue).getValueData()) } else if (et instanceof StringType && val instanceof StringValue) { - ValueAPISetElementObject(this.data, i, (val as StringValue).getData()) + ValueAPISetElementObject(this.data, i, (val as StringValue).getData() as string) } else if (et instanceof ArrayType && val instanceof ArrayValue) { ValueAPISetElementObject(this.data, i, (val as ArrayValue).getData()) } else if (et instanceof ClassType && val instanceof ClassValue) { @@ -288,6 +537,46 @@ export final class ArrayValue extends Value { throw new Error("Cannot assign array of type " + et + " with value of type " + vt) } } + + public override toString(): string { + const len = this.getLength() + let res = new StringBuilder("[") + for (let i = 0; i < len; i++) { + res.append(this.getElement(i).toString()) + if (i != len - 1) { + res.append(", ") + } + } + res.append("]") + return res.toString() + } +} + +export final class LambdaValue extends Value { + private typ: LambdaType + private data: Object + + public override getType(): Type { + return this.typ as Type + } + + public override getData(): Object { + return this.data + } + + internal constructor(typ: LambdaType, data: Object) { + this.typ = typ + this.data = data + } + + public invoke(...args: Object[]): Object { + // TODO(shumilov-petr): not implemented + throw new Error("Not implemented") + } + + public override toString(): string { + return this.typ.toString() + } } export final class BooleanValue extends Value { @@ -298,7 +587,11 @@ export final class BooleanValue extends Value { return this.typ as Type } - public getData(): Boolean { + public override getData(): Object { + return new Boolean(this.data) + } + + public getValueData(): boolean { return this.data } @@ -310,6 +603,10 @@ export final class BooleanValue extends Value { internal constructor(typ: BooleanType, data: Boolean) { this(typ, data.unboxed()) } + + public override toString(): string { + return new StringBuilder().append(this.data).toString() + } } export final class ByteValue extends Value { @@ -320,7 +617,11 @@ export final class ByteValue extends Value { return this.typ as Type } - public getData(): Byte { + public override getData(): Object { + return new Byte(this.data) + } + + public getValueData(): byte { return this.data } @@ -332,6 +633,10 @@ export final class ByteValue extends Value { internal constructor(typ: ByteType, data: Byte) { this(typ, data.unboxed()) } + + public override toString(): string { + return new StringBuilder().append(this.data).toString() + } } export final class ShortValue extends Value { @@ -342,7 +647,11 @@ export final class ShortValue extends Value { return this.typ as Type } - public getData(): Short { + public override getData(): Object { + return new Short(this.data) + } + + public getValueData(): short { return this.data } @@ -354,6 +663,10 @@ export final class ShortValue extends Value { internal constructor(typ: ShortType, data: Short) { this(typ, data.unboxed()) } + + public override toString(): string { + return new StringBuilder().append(this.data).toString() + } } export final class CharValue extends Value { @@ -364,7 +677,11 @@ export final class CharValue extends Value { return this.typ as Type } - public getData(): Char { + public override getData(): Object { + return new Char(this.data) + } + + public getValueData(): char { return this.data } @@ -376,6 +693,10 @@ export final class CharValue extends Value { internal constructor(typ: CharType, data: Char) { this(typ, data.unboxed()) } + + public override toString(): string { + return new StringBuilder("\"").append(this.data).append("\"").toString() + } } export final class IntValue extends Value { @@ -386,7 +707,11 @@ export final class IntValue extends Value { return this.typ as Type } - public getData(): Int { + public override getData(): Object { + return new Int(this.data) + } + + public getValueData(): int { return this.data } @@ -398,6 +723,10 @@ export final class IntValue extends Value { internal constructor(typ: IntType, data: Int) { this(typ, data.unboxed()) } + + public override toString(): string { + return new StringBuilder().append(this.data).toString() + } } export final class FloatValue extends Value { @@ -408,7 +737,11 @@ export final class FloatValue extends Value { return this.typ as Type } - public getData(): Float { + public override getData(): Object { + return new Float(this.data) + } + + public getValueData(): float { return this.data } @@ -420,6 +753,10 @@ export final class FloatValue extends Value { internal constructor(typ: FloatType, data: Float) { this(typ, data.unboxed()) } + + public override toString(): string { + return new StringBuilder().append(this.data).toString() + } } export final class DoubleValue extends Value { @@ -430,7 +767,11 @@ export final class DoubleValue extends Value { return this.typ as Type } - public getData(): Double { + public override getData(): Object { + return this.data + } + + public getValueData(): double { return this.data } @@ -442,6 +783,10 @@ export final class DoubleValue extends Value { internal constructor(typ: DoubleType, data: Double) { this(typ, data.unboxed()) } + + public override toString(): string { + return new StringBuilder().append(this.data).toString() + } } export final class LongValue extends Value { @@ -452,7 +797,11 @@ export final class LongValue extends Value { return this.typ as Type } - public getData(): Long { + public override getData(): Object { + return new Long(this.data) + } + + public getValueData(): long { return this.data } @@ -464,17 +813,21 @@ export final class LongValue extends Value { internal constructor(typ: LongType, data: Long) { this(typ, data.unboxed()) } + + public override toString(): string { + return new StringBuilder().append(this.data).toString() + } } export final class StringValue extends Value { private typ: StringType - private data: String + private data: string public override getType(): Type { return this.typ as Type } - public getData(): String { + public override getData(): Object { return this.data } @@ -482,6 +835,10 @@ export final class StringValue extends Value { this.typ = typ this.data = data } + + public override toString(): string { + return new StringBuilder("\"").append(this.data).append("\"").toString() + } } export final class NullValue extends Value { @@ -491,15 +848,50 @@ export final class NullValue extends Value { return NullType.REF as Type } + public override getData(): Object { + return NullValue.INSTANCE + } + internal constructor() {} + + public override toString(): string { + return NullValue.INSTANCE.toString() + } } export final class UndefinedValue extends Value { + // TODO(shumilov-petr): replace `new UndefinedValue() into `undefined` when one will be available public static readonly INSTANCE = new UndefinedValue() public override getType(): Type { return UndefinedType.REF as Type } + public override getData(): Object { + return UndefinedValue.INSTANCE + } + + internal constructor() {} + + public override toString(): string { + return UndefinedValue.INSTANCE.toString() + } +} + +export final class VoidValue extends Value { + public static readonly INSTANCE = Void + + public override getType(): Type { + return VoidType.REF as Type + } + + public override getData(): Object { + return VoidValue.INSTANCE + } + internal constructor() {} + + public override toString(): string { + return VoidValue.INSTANCE.toString() + } } diff --git a/plugins/ets/tests/ets-templates/03.types/08.reference_types/01.objects/string_concatenation_0.ets b/plugins/ets/tests/ets-templates/03.types/08.reference_types/01.objects/string_concatenation_0.ets index 5b2bcd27ee1906be28d1d745bf6c20ed48f5d5f9..6f711414baaef0b32e27e677000c02e6831e578b 100644 --- a/plugins/ets/tests/ets-templates/03.types/08.reference_types/01.objects/string_concatenation_0.ets +++ b/plugins/ets/tests/ets-templates/03.types/08.reference_types/01.objects/string_concatenation_0.ets @@ -23,5 +23,5 @@ function main(): void { let a: Object = new A(); let b: String = "as"; let c: String = a + b; - assert c == "Aas"; + assert c == "{}as"; } diff --git a/plugins/ets/tests/ets_func_tests/escompat/Reflect.ets b/plugins/ets/tests/ets_func_tests/escompat/Reflect.ets new file mode 100644 index 0000000000000000000000000000000000000000..35216f24fe8064989b4c21bc4663cf93cc5ab677 --- /dev/null +++ b/plugins/ets/tests/ets_func_tests/escompat/Reflect.ets @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function main(): int { + let failures: int = 0; + + // get + failures += test(reflectGetBadCases(), "Reflect.get on types without fields and elements"); + failures += test(reflectGetClass(), "Reflect.get on class type"); + failures += test(reflectGetArray(), "Reflect.get on array type"); + failures += test(reflectGetLambda(), "Reflect.get on function type"); + + // set + failures += test(reflectSetClass(), "Reflect.set on class type"); + failures += test(reflectSetArray(), "Reflect.set on array type"); + + // ownKeys + failures += test(reflectOwnKeys(), "Reflect.ownKeys"); + + // has + failures += test(reflectHas(), "Reflect.has"); + + return test(failures, "All tests run"); +} + +function reflectGetBadCases(): int { + let c: char = c'c' + let bo: boolean = true + let bt: byte = 10 + let sh: short = 20 + let i: int = 30 + let lo: long = 40 + let fl: float = 50.0 + let dou: double = 60.0 + let s: string = "abc" + + let result: int = 0 + try { + Reflect.get(c, "a") + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must have fields", 0) ? 0 : 1 + } + + try { + Reflect.get(bo, "a") + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must have fields", 0) ? 0 : 1 + } + + try { + Reflect.get(bt, "a") + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must have fields", 0) ? 0 : 1 + } + + try { + Reflect.get(sh, "a") + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must have fields", 0) ? 0 : 1 + } + + try { + Reflect.get(i, "a") + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must have fields", 0) ? 0 : 1 + } + + try { + Reflect.get(lo, "a") + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must have fields", 0) ? 0 : 1 + } + + try { + Reflect.get(fl, "a") + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must have fields", 0) ? 0 : 1 + } + + try { + Reflect.get(dou, "a") + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must have fields", 0) ? 0 : 1 + } + + try { + Reflect.get(s, "a") + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must have fields", 0) ? 0 : 1 + } + + // ---------- + + try { + Reflect.get(c, 1) + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must be indexed", 0) ? 0 : 1 + } + + try { + Reflect.get(bo, 1) + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must be indexed", 0) ? 0 : 1 + } + + try { + Reflect.get(bt, 1) + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must be indexed", 0) ? 0 : 1 + } + + try { + Reflect.get(sh, 1) + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must be indexed", 0) ? 0 : 1 + } + + try { + Reflect.get(i, 1) + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must be indexed", 0) ? 0 : 1 + } + + try { + Reflect.get(lo, 1) + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must be indexed", 0) ? 0 : 1 + } + + try { + Reflect.get(fl, 1) + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must be indexed", 0) ? 0 : 1 + } + + try { + Reflect.get(dou, 1) + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must be indexed", 0) ? 0 : 1 + } + + try { + Reflect.get(s, 1) + } catch (e: Error) { + result += e.toString().contains("`target` argument of Reflect.get must be indexed", 0) ? 0 : 1 + } + + return result +} + +class Point2D { + static axisnum: number = 2 + x: number + y: number + constructor (x_: number, y_: number) { + this.x = x_ + this.y = y_ + } +} + +class Point3D extends Point2D { + static axisnum: number = 3 + z: number + constructor (x_: number, y_: number, z_: number) { + super(x_, y_) + this.z = z_ + } +} + +function reflectGetClass(): int { + let result: int = 0 + + let p: Point2D = new Point3D(10, 20, 30) + + result += (Reflect.get(p, "x") as Number == 10) ? 0 : 1 + result += (Reflect.get(p, "y") as Number == 20) ? 0 : 1 + result += (Reflect.get(p, "z") as Number == 30) ? 0 : 1 + + // TODO(shumilov-petr): Replace `null` into `undefined` + result += (Reflect.get(p, "axisnum") == null) ? 0 : 1 + result += (Reflect.get(p, "qwerty") == null) ? 0 : 1 + result += (Reflect.get(p, 1) == null) ? 0 : 1 + + return result +} + +function reflectGetArray(): int { + let result: int = 0 + + let arr: number[] = [10, 20, 30] + let brr: string[] = ["p", "q", "t", "w"] + + result += (Reflect.get(arr, 0) as Number == 10) ? 0 : 1 + result += (Reflect.get(arr, 1) as Number == 20) ? 0 : 1 + result += (Reflect.get(arr, 2) as Number == 30) ? 0 : 1 + + result += (Reflect.get(brr, 0) == "p") ? 0 : 1 + result += (Reflect.get(brr, 1) == "q") ? 0 : 1 + result += (Reflect.get(brr, 2) == "t") ? 0 : 1 + + result += (Reflect.get(arr, "length") as Number == 3) ? 0 : 1 + result += (Reflect.get(brr, "length") as Number == 4) ? 0 : 1 + + // TODO(shumilov-petr): Replace `null` into `undefined` + result += (Reflect.get(arr, "qwerty") == null) ? 0 : 1 + result += (Reflect.get(arr, 10) == null) ? 0 : 1 + result += (Reflect.get(brr, 4) == null) ? 0 : 1 + + return result +} + +function reflectGetLambda(): int { + let result: int = 0 + + let lambda: (a: number) => number = (a: number): number => { + return a + 1 + } + + result += (Reflect.get(lambda, 0) == null) ? 0 : 1 + result += (Reflect.get(lambda, "length") as Number == 1) ? 0 : 1 + result += (Reflect.get(lambda, "name") == "") ? 0 : 1 + + // TODO(shumilov-petr): Replace `null` into `undefined` + result += (Reflect.get(lambda, "qwerty") == null) ? 0 : 1 + + return result +} + +function reflectSetClass(): int { + let result: int = 0 + + let p: Point2D = new Point3D(10, 20, 30) + + result += (Reflect.set(p, "x", 40 as number) == true) ? 0 : 1 + result += (Reflect.set(p, "y", 50 as number) == true) ? 0 : 1 + result += (Reflect.set(p, "z", 60 as number) == true) ? 0 : 1 + + result += (Reflect.get(p, "x") as Number == 40) ? 0 : 1 + result += (Reflect.get(p, "y") as Number == 50) ? 0 : 1 + result += (Reflect.get(p, "z") as Number == 60) ? 0 : 1 + + // TODO(shumilov-petr): Replace `null` into `undefined` + result += (Reflect.set(p, "axisnum", 10 as number) == false) ? 0 : 1 + result += (Reflect.set(p, "x", "string") == false) ? 0 : 1 + + return result +} + +function reflectSetArray(): int { + let result: int = 0 + + let arr: number[] = [10, 20, 30] + let brr: string[] = ["p", "q", "t", "w"] + + result += (Reflect.set(arr, 0, 40 as number) == true) ? 0 : 1 + result += (Reflect.set(arr, 1, 50 as number) == true) ? 0 : 1 + result += (Reflect.set(arr, 2, 60 as number) == true) ? 0 : 1 + + result += (Reflect.get(arr, 0) as Number == 40) ? 0 : 1 + result += (Reflect.get(arr, 1) as Number == 50) ? 0 : 1 + result += (Reflect.get(arr, 2) as Number == 60) ? 0 : 1 + + // TODO(shumilov-petr): Replace `null` into `undefined` + result += (Reflect.set(arr, 100, 10 as number) == false) ? 0 : 1 + result += (Reflect.set(arr, 0, "string") == false) ? 0 : 1 + + return result +} + +function arraysAreEqual(a: string[], b: string[]): boolean { + let alen = a.length + if (alen != b.length) { + return false + } + for (let i = 0; i < alen; i++) { + if (a[i] != b[i]) { + return false + } + } + return true +} + +function reflectOwnKeys(): int { + let result: int = 0 + + let c: char = c'c' + let bo: boolean = true + let bt: byte = 10 + let sh: short = 20 + let i: int = 30 + let lo: long = 40 + let fl: float = 50.0 + let dou: double = 60.0 + + let arr: number[] = [10, 20, 30] + let str: string = "abc" + + let cl: Point2D = new Point3D(10, 20, 30) + + let lambda: (a: number) => number = (a: number): number => { + return a + 1 + } + + let emptyArr: string[] = [] + + result += arraysAreEqual(Reflect.ownKeys(c), emptyArr) ? 0 : 1 + result += arraysAreEqual(Reflect.ownKeys(bo), emptyArr) ? 0 : 1 + result += arraysAreEqual(Reflect.ownKeys(bt), emptyArr) ? 0 : 1 + result += arraysAreEqual(Reflect.ownKeys(sh), emptyArr) ? 0 : 1 + result += arraysAreEqual(Reflect.ownKeys(i), emptyArr) ? 0 : 1 + result += arraysAreEqual(Reflect.ownKeys(lo), emptyArr) ? 0 : 1 + result += arraysAreEqual(Reflect.ownKeys(fl), emptyArr) ? 0 : 1 + result += arraysAreEqual(Reflect.ownKeys(dou), emptyArr) ? 0 : 1 + + result += arraysAreEqual(Reflect.ownKeys(arr), ["0", "1", "2", "length"]) ? 0 : 1 + result += arraysAreEqual(Reflect.ownKeys(str), ["0", "1", "2", "length"]) ? 0 : 1 + + result += arraysAreEqual(Reflect.ownKeys(cl), ["x", "y", "z"]) ? 0 : 1 + + result += arraysAreEqual(Reflect.ownKeys(lambda), ["length", "name"]) ? 0 : 1 + + return result +} + +function reflectHas(): int { + let result: int = 0 + + let arr: number[] = [10, 20, 30] + let str: string = "abc" + + let cl: Point2D = new Point3D(10, 20, 30) + + let lambda: (a: number) => number = (a: number): number => { + return a + 1 + } + + result += (Reflect.hasOwn(arr, 0) == true) ? 0 : 1 + result += (Reflect.hasOwn(arr, 3) == false) ? 0 : 1 + result += (Reflect.hasOwn(arr, "length") == true) ? 0 : 1 + result += (Reflect.hasOwn(arr, "qwerty") == false) ? 0 : 1 + + result += (Reflect.hasOwn(str, 0) == true) ? 0 : 1 + result += (Reflect.hasOwn(str, 3) == false) ? 0 : 1 + result += (Reflect.hasOwn(str, "length") == true) ? 0 : 1 + result += (Reflect.hasOwn(str, "qwerty") == false) ? 0 : 1 + + result += (Reflect.hasOwn(cl, "x") == true) ? 0 : 1 + result += (Reflect.hasOwn(cl, "y") == true) ? 0 : 1 + result += (Reflect.hasOwn(cl, "z") == true) ? 0 : 1 + result += (Reflect.hasOwn(cl, "axisnum") == false) ? 0 : 1 + result += (Reflect.hasOwn(cl, "asdasd") == false) ? 0 : 1 + result += (Reflect.hasOwn(cl, 0) == false) ? 0 : 1 + + result += (Reflect.hasOwn(lambda, "length") == true) ? 0 : 1 + result += (Reflect.hasOwn(lambda, "name") == true) ? 0 : 1 + result += (Reflect.hasOwn(lambda, 0) == false) ? 0 : 1 + + return result +} + +function test(result: int, message: String ): int { + if (result == 0) { + console.log('PASSED: ' + message); + return 0; + } + console.log('FAILED: ' + message); + return 1; +} diff --git a/plugins/ets/tests/ets_func_tests/std/core/Object.ets b/plugins/ets/tests/ets_func_tests/std/core/Object.ets new file mode 100644 index 0000000000000000000000000000000000000000..919521c9c82c3517ac1d0db912e456b88ea71a54 --- /dev/null +++ b/plugins/ets/tests/ets_func_tests/std/core/Object.ets @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function main(): int { + let failures: int = 0; + + failures += test(objectKeys(), "Object.keys"); + + failures += test(objectValues(), "Object.values"); + + failures += test(objectEntries(), "Object.entries"); + + failures += test(objectGetOwnPropertyNames(), "Object.getOwnPropertyNames"); + + failures += test(objectHasOwnProperty(), "Object.hasOwnProperty"); + + return test(failures, "All tests run"); +} + +type Tuple = Object[] + +class Point2D { + static axisnum: number = 2 + x: number + y: number + constructor (x_: number, y_: number) { + this.x = x_ + this.y = y_ + } +} + +class Point3D extends Point2D { + static axisnum: number = 3 + z: number + constructor (x_: number, y_: number, z_: number) { + super(x_, y_) + this.z = z_ + } +} + +function strArraysAreEqual(a: string[], b: string[]): boolean { + let alen = a.length + if (alen != b.length) { + return false + } + for (let i = 0; i < alen; i++) { + if (a[i] != b[i]) { + return false + } + } + return true +} + +function objArraysAreEqual(a: Object[], b: Object[]): boolean { + let alen = a.length + if (alen != b.length) { + return false + } + for (let i = 0; i < alen; i++) { + if (!(a[i].equals(b[i]))) { + return false + } + } + return true +} + +function tupleArraysAreEqual(a: Tuple[], b: Tuple[]): boolean { + let alen = a.length + if (alen != b.length) { + return false + } + for (let i = 0; i < alen; i++) { + if (a[i].length != b[i].length) { + return false + } + let aalen = a[i].length + for (let j = 0; j < aalen; j++) { + if (!(a[i][j].equals(b[i][j]))) { + return false + } + } + } + return true +} + +function objectKeys(): int { + let result: int = 0 + + let c: char = c'c' + let bo: boolean = true + let bt: byte = 10 + let sh: short = 20 + let i: int = 30 + let lo: long = 40 + let fl: float = 50.0 + let dou: double = 60.0 + + let arr: number[] = [10, 20, 30] + let str: string = "abc" + + let cl: Point2D = new Point3D(10, 20, 30) + + let lambda: (a: number) => number = (a: number): number => { + return a + 1 + } + + let emptyArr: string[] = [] + + result += strArraysAreEqual(Object.keys(c), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Object.keys(bo), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Object.keys(bt), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Object.keys(sh), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Object.keys(i), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Object.keys(lo), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Object.keys(fl), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Object.keys(dou), emptyArr) ? 0 : 1 + + result += strArraysAreEqual(Object.keys(arr), ["0", "1", "2"]) ? 0 : 1 + result += strArraysAreEqual(Object.keys(str), ["0", "1", "2"]) ? 0 : 1 + + result += strArraysAreEqual(Object.keys(cl), ["x", "y", "z"]) ? 0 : 1 + + result += strArraysAreEqual(Object.keys(lambda), emptyArr) ? 0 : 1 + + return result +} + +function objectValues(): int { + let result: int = 0 + + let c: char = c'c' + let bo: boolean = true + let bt: byte = 10 + let sh: short = 20 + let i: int = 30 + let lo: long = 40 + let fl: float = 50.0 + let dou: double = 60.0 + + let arr: number[] = [10, 20, 30] + let str: string = "abc" + + let cl: Point2D = new Point3D(10, 20, 30) + + let lambda: (a: number) => number = (a: number): number => { + return a + 1 + } + + let emptyArr: Object[] = [] + + result += objArraysAreEqual(Object.values__(c), emptyArr) ? 0 : 1 + result += objArraysAreEqual(Object.values__(bo), emptyArr) ? 0 : 1 + result += objArraysAreEqual(Object.values__(bt), emptyArr) ? 0 : 1 + result += objArraysAreEqual(Object.values__(sh), emptyArr) ? 0 : 1 + result += objArraysAreEqual(Object.values__(i), emptyArr) ? 0 : 1 + result += objArraysAreEqual(Object.values__(lo), emptyArr) ? 0 : 1 + result += objArraysAreEqual(Object.values__(fl), emptyArr) ? 0 : 1 + result += objArraysAreEqual(Object.values__(dou), emptyArr) ? 0 : 1 + + let arrVal: Object[] = [new Number(10), new Number(20), new Number(30)] + result += objArraysAreEqual(Object.values__(arr), arrVal) ? 0 : 1 + + let strVal: Object[] = ["a" as string, "b" as string, "c" as string] + result += objArraysAreEqual(Object.values__(str), strVal) ? 0 : 1 + + let clVal: Object[] = [new Number(10), new Number(20), new Number(30)] + result += objArraysAreEqual(Object.values__(cl), clVal) ? 0 : 1 + + result += objArraysAreEqual(Object.values__(lambda), emptyArr) ? 0 : 1 + + return result +} + +function objectEntries(): int { + let result: int = 0 + + let c: char = c'c' + let bo: boolean = true + let bt: byte = 10 + let sh: short = 20 + let i: int = 30 + let lo: long = 40 + let fl: float = 50.0 + let dou: double = 60.0 + + let arr: number[] = [10, 20, 30] + let str: string = "abc" + + let cl: Point2D = new Point3D(10, 20, 30) + + let lambda: (a: number) => number = (a: number): number => { + return a + 1 + } + + let emptyTuple: Tuple[] = new Tuple[0] + + result += tupleArraysAreEqual(Object.entries(c), emptyTuple) ? 0 : 1 + result += tupleArraysAreEqual(Object.entries(bo), emptyTuple) ? 0 : 1 + result += tupleArraysAreEqual(Object.entries(bt), emptyTuple) ? 0 : 1 + result += tupleArraysAreEqual(Object.entries(sh), emptyTuple) ? 0 : 1 + result += tupleArraysAreEqual(Object.entries(i), emptyTuple) ? 0 : 1 + result += tupleArraysAreEqual(Object.entries(lo), emptyTuple) ? 0 : 1 + result += tupleArraysAreEqual(Object.entries(fl), emptyTuple) ? 0 : 1 + result += tupleArraysAreEqual(Object.entries(dou), emptyTuple) ? 0 : 1 + + let arrVal: Tuple[] = new Tuple[3] + arrVal[0] = new Object[2] + arrVal[0] = ["0", new Number(10)] + arrVal[1] = new Object[2] + arrVal[1] = ["1", new Number(20)] + arrVal[2] = new Object[2] + arrVal[2] = ["2", new Number(30)] + result += tupleArraysAreEqual(Object.entries(arr), arrVal) ? 0 : 1 + + let strVal: Tuple[] = new Tuple[3] + strVal[0] = new Object[2] + strVal[0] = ["0", "a"] + strVal[1] = new Object[2] + strVal[1] = ["1", "b"] + strVal[2] = new Object[2] + strVal[2] = ["2", "c"] + result += tupleArraysAreEqual(Object.entries(str), strVal) ? 0 : 1 + + let clVal: Tuple[] = new Tuple[3] + clVal[0] = new Object[2] + clVal[0] = ["x", new Number(10)] + clVal[1] = new Object[2] + clVal[1] = ["y", new Number(20)] + clVal[2] = new Object[2] + clVal[2] = ["z", new Number(30)] + result += tupleArraysAreEqual(Object.entries(cl), clVal) ? 0 : 1 + + result += tupleArraysAreEqual(Object.entries(lambda), emptyTuple) ? 0 : 1 + + return result +} + +function objectGetOwnPropertyNames(): int { + let result: int = 0 + + let c: char = c'c' + let bo: boolean = true + let bt: byte = 10 + let sh: short = 20 + let i: int = 30 + let lo: long = 40 + let fl: float = 50.0 + let dou: double = 60.0 + + let arr: number[] = [10, 20, 30] + let str: string = "abc" + + let cl: Point2D = new Point3D(10, 20, 30) + + let lambda: (a: number) => number = (a: number): number => { + return a + 1 + } + + let emptyArr: string[] = [] + + result += strArraysAreEqual(Reflect.ownKeys(c), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Reflect.ownKeys(bo), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Reflect.ownKeys(bt), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Reflect.ownKeys(sh), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Reflect.ownKeys(i), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Reflect.ownKeys(lo), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Reflect.ownKeys(fl), emptyArr) ? 0 : 1 + result += strArraysAreEqual(Reflect.ownKeys(dou), emptyArr) ? 0 : 1 + + result += strArraysAreEqual(Reflect.ownKeys(arr), ["0", "1", "2", "length"]) ? 0 : 1 + result += strArraysAreEqual(Reflect.ownKeys(str), ["0", "1", "2", "length"]) ? 0 : 1 + + result += strArraysAreEqual(Reflect.ownKeys(cl), ["x", "y", "z"]) ? 0 : 1 + + result += strArraysAreEqual(Reflect.ownKeys(lambda), ["length", "name"]) ? 0 : 1 + + return result +} + +function objectHasOwnProperty(): int { + let result: int = 0 + + let arr: number[] = [10, 20, 30] + let str: string = "abc" + + let cl: Point2D = new Point3D(10, 20, 30) + + let lambda: (a: number) => number = (a: number): number => { + return a + 1 + } + + result += ((arr as Object).hasOwnProperty(0) == true) ? 0 : 1 + result += ((arr as Object).hasOwnProperty(3) == false) ? 0 : 1 + result += ((arr as Object).hasOwnProperty("length") == true) ? 0 : 1 + result += ((arr as Object).hasOwnProperty("qwerty") == false) ? 0 : 1 + + result += (str.hasOwnProperty(0) == true) ? 0 : 1 + result += (str.hasOwnProperty(3) == false) ? 0 : 1 + result += (str.hasOwnProperty("length") == true) ? 0 : 1 + result += (str.hasOwnProperty("qwerty") == false) ? 0 : 1 + + result += (cl.hasOwnProperty("x") == true) ? 0 : 1 + result += (cl.hasOwnProperty("y") == true) ? 0 : 1 + result += (cl.hasOwnProperty("z") == true) ? 0 : 1 + result += (cl.hasOwnProperty("axisnum") == false) ? 0 : 1 + result += (cl.hasOwnProperty("asdasd") == false) ? 0 : 1 + result += (cl.hasOwnProperty(0) == false) ? 0 : 1 + + result += ((lambda as Object).hasOwnProperty("length") == true) ? 0 : 1 + result += ((lambda as Object).hasOwnProperty("name") == true) ? 0 : 1 + result += ((lambda as Object).hasOwnProperty(0) == false) ? 0 : 1 + + return result +} + +function test(result: int, message: String ): int { + if (result == 0) { + console.log('PASSED: ' + message); + return 0; + } + console.log('FAILED: ' + message); + return 1; +} diff --git a/plugins/ets/tests/ets_func_tests/std/core/TypeClassTypeTest.ets b/plugins/ets/tests/ets_func_tests/std/core/TypeClassTypeTest.ets new file mode 100644 index 0000000000000000000000000000000000000000..9123a095aff91d1f7db037991f327e5760424568 --- /dev/null +++ b/plugins/ets/tests/ets_func_tests/std/core/TypeClassTypeTest.ets @@ -0,0 +1,204 @@ +function test(result: boolean, name: String): int { + if (result) { + console.println("PASSED: " + name) + return 0 + } + console.println("FAILED: " + name) + return 1 +} + +interface Serializable { + serialize(): String; +} + +class Point implements Serializable { + protected x: double + y: double + + constructor(x: double, y: double) { + this.x = x + this.y = y + } + + constructor() { + this(0.0, 0.0) + } + + override serialize(): String { + return "{" + this.x + "," + this.y + "}" + } + + add(oth: Point): Point { + let res = new Point() + res.x = this.x + oth.x + res.y = this.y + oth.y + return res + } +} + +class Point3D extends Point { + z: double + private state: int + static ZERO: double = 0.0 + constructor(x: double, y: double, z: double) { + super(x, y) + this.z = z + this.state = 0.0 + } + constructor(state: int) { + this(0, 0, 0) + this.state = 1.0 + } +} + +abstract class Writer { + abstract write(): int +} + +final class HTMLWriter extends Writer { + private state: int + constructor(state: int) { + this.state = state + } + + public getState(): int { + return this.state + } + + override write(): int { + return 0 + } +} + +function testFields(ct: ClassType): int { + console.log(" Fields:") + let failures = 0 + for (let i = 0; i < ct.getFieldsNum(); ++i) { + let field = ct.getField(i); + failures += test(ct.getFieldByName(field.getName()) == field, " " + field.getName() + " field") + } + return failures +} + +function testAllFieldsAreOwn(ct: ClassType): int { + console.log(" Own Fields:") + let failures = test(ct.getOwnFieldsNum() == ct.getFieldsNum(), " OwnFieldsNum == FieldsNum") + for (let i = 0; i < ct.getOwnFieldsNum(); ++i) { + let field = ct.getOwnField(i); + failures += test(ct.getFieldByName(field.getName()) == field, " " + field.getName()) + } + return failures +} + +function testClassExtendsObject(ct: ClassType): int { + let failures = 0 + let objectMethods = ObjectType.getMethodsNum() + for (let i = 0; i < objectMethods; ++i) { + let objectMethodName = ObjectType.getMethod(i).getName() + failures += test(ct.hasMethod(objectMethodName), " " + objectMethodName + " method") + } + return failures +} + +function testPoint(): int { + let pt = Type.of(new Point()) as ClassType + + return test(pt.getName() == "Point", "ClassName: Point") + + test(pt.hasEmptyConstructor(), " doesn't have empty constuctor") + + test(pt.getBaseType() == ObjectType, " base type is ObjectType") + + test(pt.getInterfacesNum() == 1, " 1 Interface:") + + test(pt.getInterface(0).getName() == "Serializable", " Serializable interface") + + test(pt.getFieldsNum() == 2, " 2 Fields:") + + test(pt.hasField("x"), " x field") + + test(pt.hasField("y"), " y field") + + testAllFieldsAreOwn(pt) + + test(pt.getMethodsNum() == 2 + ObjectType.getMethodsNum(), " 2 Methods: ") + + testClassExtendsObject(pt) + + test(pt.hasMethod("add"), " Point.add method") + + test(pt.hasMethod("serialize"), " Serializable.serialize method") + + test(pt.getConstructorsNum() == 2, " 2 Constructor:") + + test(pt.getConstructor(0).getName() == "constructor", " default") + + test(pt.getConstructor(1).getName() == "constructor", " default") + + test(!pt.isFinal(), " not final") + + testFields(pt) +} + +function testPoint3D(): int { + let pt = Type.of(new Point3D(1.0, 2.0, 3.0)) as ClassType + + return test(pt.getName() == "Point3D", "ClassName: Point3D") + + test(!pt.hasEmptyConstructor(), " doesn't have empty constructor") + + test(pt.getBaseType().getName() == "Point", " base type is Point") + + test(pt.getInterfacesNum() == 0, " 0 Interfaces") + + test(pt.getFieldsNum() == 5, " 5 Fields:") + + test(pt.hasField("x"), " x field") + + test(pt.hasField("y"), " y field") + + test(pt.hasField("z"), " z field") + + test(pt.hasField("state"), " state field") + + test(pt.hasField("ZERO"), " ZERO field") + + test(pt.getOwnFieldsNum() == 3, " 3 Own Fields:") + + test(pt.getOwnField(0) == pt.getFieldByName("ZERO"), " ZERO field") + + test(pt.getOwnField(1) == pt.getFieldByName("z"), " z field") + + test(pt.getOwnField(2) == pt.getFieldByName("state"), " state field") + + test(pt.getMethodsNum() == 2 + ObjectType.getMethodsNum(), " 2 Methods:") + + testClassExtendsObject(pt) + + test(pt.hasMethod("add"), " Point.add method") + + test(pt.hasMethod("serialize"), " Serializable.serialize method") + + test(pt.getConstructorsNum() == 2, " 2 Constructors") + + testFields(pt) +} + +function testHTMLWriter(): int { + let wt = Type.of(new HTMLWriter(1)) as ClassType + + return test(wt.getName() == "HTMLWriter", "ClassName: HTMLWriter") + + test(!wt.hasEmptyConstructor(), " doesn't have empty constructor") + + test(wt.getBaseType().getName() == "Writer", " base type is Writer") + + test(wt.getInterfacesNum() == 0, " 0 Interfaces") + + test(wt.getFieldsNum() == 1, " 1 Field:") + + test(wt.hasField("state"), " state field") + + testAllFieldsAreOwn(wt) + + test(wt.getMethodsNum() == 2 + ObjectType.getMethodsNum(), " 5 methods:") + + testClassExtendsObject(wt) + + test(wt.hasMethod("write"), " HTMLWriter.add method") + + test(wt.hasMethod("getState"), " HTMLWriter.getState method") + + test(wt.getConstructorsNum() == 1, " 1 Constructor:") + + test(wt.getConstructor(0).getName() == "constructor", " default") + + test(wt.isFinal(), " final") + + testFields(wt) +} + +function testMake(): int { + console.log(" Make:") + let failures = 0 + let pt = Type.of(new Point()) as ClassType + let wt = Type.of(new HTMLWriter(0)) as ClassType + let p3t = Type.of(new Point3D(10)) as ClassType + let point = pt.make([new Double(1.0), new Double(2.0)] as NullishType[]) as Point + let point3D = p3t.make([new Double(1.0), new Double(2.0), new Double(3.0)] as NullishType[]) as Point3D + let writer = wt.make([new Int(10)] as NullishType[]) as HTMLWriter + failures += test(point.serialize() == "{1,2}", "Point") + failures += test(point3D.serialize() == "{1,2}" && point3D.z == 3, "Point3D") + failures += test(writer.getState() == 10, "HTMLWriter" ) + return failures +} + +function testClassType(): int { + let failures = 0 + failures += testPoint() + failures += testPoint3D() + failures += testHTMLWriter() + failures += testMake() + return failures +} + +function main(): int { + let failures = 0 + failures += testClassType() + if (failures == 0) { + console.println("PASSED: All tests run") + } else { + console.println("FAILED: All tests run") + } + return failures +} \ No newline at end of file diff --git a/plugins/ets/tests/ets_func_tests/std/core/TypeFieldTest.ets b/plugins/ets/tests/ets_func_tests/std/core/TypeFieldTest.ets new file mode 100644 index 0000000000000000000000000000000000000000..26b7f733d41a12fadc39836f8b6ad05a73fa063e --- /dev/null +++ b/plugins/ets/tests/ets_func_tests/std/core/TypeFieldTest.ets @@ -0,0 +1,76 @@ +function test(result: boolean, name: String): int { + if (result) { + console.println("PASSED: " + name) + return 0 + } + console.println("FAILED: " + name) + return 1 +} + +interface Serializable { + serialize(): String; +} + +class Point implements Serializable { + protected x: double + y: double + + override serialize(): String { + return "{" + this.x + "," + this.y + "}" + } + + add(oth: Point): Point { + let res = new Point() + res.x = this.x + oth.x + res.y = this.y + oth.y + return res + } +} + +class Point3D extends Point { + z: double + private state: int + static ZERO: double = 0.0 +} + +function testField(): int { + let pt = Type.of(new Point3D()) as ClassType + + let xf = pt.getFieldByName("x") + let sf = pt.getFieldByName("state") + let zf = pt.getFieldByName("ZERO") + + return test(xf.getName() == "x", "FieldName: x") + + test(xf.getOwnerType() == Type.of(new Point()), " OwnerType: Point") + + test(xf.getType() == DoubleType.VAL, " Type: double") + + test(xf.getAttributes() == Attributes.INHERITED, " no attributes") + + test(xf.getAccessModifier() == AccessModifier.PROTECTED, " protected access modififer") + + test(xf.isInherited(), " inherited") + + test(!xf.isStatic(), " not static") + + test(sf.getName() == "state", "FieldName: state") + + test(sf.getOwnerType() == pt, " OwnerType: Point3D") + + test(sf.getType() == IntType.VAL, " Type: int") + + test(sf.getAttributes() == 0, " no attributes") + + test(sf.getAccessModifier() == AccessModifier.PRIVATE, " private access modifier") + + test(!sf.isInherited(), " not inherited") + + test(!sf.isStatic(), " not static") + + test(zf.getName() == "ZERO", "FieldName: ZERO") + + test(zf.getOwnerType() == pt, " OwnerType: Point3D") + + test(zf.getType() == DoubleType.VAL, " Type: double") + + test(zf.getAttributes() == 1, " static attribute") + + test(zf.getAccessModifier() == AccessModifier.PUBLIC, " public access modififer") + + test((zf.getStaticValue() as Double).unboxed() == Point3D.ZERO, " static value") + + test(!zf.isInherited(), " not inherited") + + test(zf.isStatic(), " static") +} + +function main(): int { + let failures = 0 + failures += testField() + if (failures == 0) { + console.println("PASSED: All tests run") + } else { + console.println("FAILED: All tests run") + } + return failures +} \ No newline at end of file diff --git a/plugins/ets/tests/ets_func_tests/std/core/TypeInterfaceTypeTest.ets b/plugins/ets/tests/ets_func_tests/std/core/TypeInterfaceTypeTest.ets new file mode 100644 index 0000000000000000000000000000000000000000..ecfb09d3c375fa737d03c43fc1d9f6244409ee22 --- /dev/null +++ b/plugins/ets/tests/ets_func_tests/std/core/TypeInterfaceTypeTest.ets @@ -0,0 +1,86 @@ +function test(result: boolean, name: String): int { + if (result) { + console.println("PASSED: " + name) + return 0 + } + console.println("FAILED: " + name) + return 1 +} + +interface A { + doA(): Object; +} + +interface B extends A { + doB(): Object; +} + +interface C extends A { + doC(): Object; +} + +interface D extends B, C { + doD(): Object; +} + +class InstanceC implements C { + override doA(): Object { + return new Int() as Object + } + override doC(): Object { + return "" as Object + } +} + +class InstanceD implements D { + override doA(): Object { + return new Int() as Object + } + override doB(): Object { + return new Double() as Object + } + override doC(): Object { + return "" as Object + } + override doD(): Object { + return "" as Object + } +} + +function testInterfaceTypeC(): int { + let ict = (Type.of(new InstanceC()) as ClassType).getInterface(0) + let iat = ict.getInterface(0) + return test(ict.getName() == "C", "InterfaceName: C") + + test(ict.getInterfacesNum() == 1, " 1 Interfaces:") + + test(ict.getInterface(0) == iat, " A interface") + + test(ict.getMethodsNum() == 2, " 2 Methods:") + + test(ict.hasMethod("doA"), " doA method") + + test(ict.hasMethod("doC"), " doC method") +} + +function testInterfaceTypeD(): int { + let idt = (Type.of(new InstanceD()) as ClassType).getInterface(0) + let ibt = idt.getInterface(0) + let ict = idt.getInterface(1) + return test(idt.getName() == "D", "InterfaceName: D") + + test(idt.getInterfacesNum() == 2, " 2 Interfaces:") + + test(idt.getInterface(0) == ibt, " B interface") + + test(idt.getInterface(1) == ict, " C interface") + + test(idt.getMethodsNum() == 4, " 4 Methods:") + + test(idt.hasMethod("doA"), " doA method") + + test(idt.hasMethod("doB"), " doB method") + + test(idt.hasMethod("doC"), " doC method") + + test(idt.hasMethod("doD"), " doD method") +} + +function main(): int { + let failures = 0 + failures += testInterfaceTypeC() + failures += testInterfaceTypeD() + if (failures == 0) { + console.println("PASSED: All tests run") + } else { + console.println("FAILED: All tests run") + } + return failures +} \ No newline at end of file diff --git a/plugins/ets/tests/ets_func_tests/std/core/TypeLambdaTypeTest.ets b/plugins/ets/tests/ets_func_tests/std/core/TypeLambdaTypeTest.ets new file mode 100644 index 0000000000000000000000000000000000000000..25efdfad503305da11039d1dc2ba6309e401c060 --- /dev/null +++ b/plugins/ets/tests/ets_func_tests/std/core/TypeLambdaTypeTest.ets @@ -0,0 +1,40 @@ +function test(result: boolean, name: String): int { + if (result) { + console.println("PASSED: " + name) + return 0 + } + console.println("FAILED: " + name) + return 1 +} + +class Base {} + +class Derived extends Base {} + +function testLambdaType(): int { + let foo: () => Base = () : Base => { return new Base() } + let foo2: (p: Base) => Derived = (p: Base): Derived => { return new Derived() } + + let baseType = Type.of(new Base()) as ClassType + let derivedType = Type.of(new Derived()) as ClassType + + let fooType = Type.of(foo) as LambdaType + let foo2Type = Type.of(foo2) as LambdaType + + return test(fooType.getParametersNum() == 0, " 0 Parameters") + + test(fooType.getResultType() == baseType, " Base result type") + + test(foo2Type.getParametersNum() == 1, " 1 Parameter") + + test(foo2Type.getParameter(0).getType() == baseType," base type param") + + test(foo2Type.getResultType() == derivedType, " Derived result type") +} + +function main(): int { + let failures = 0 + failures += testLambdaType() + if (failures == 0) { + console.println("PASSED: All tests run") + } else { + console.println("FAILED: All tests run") + } + return failures +} \ No newline at end of file diff --git a/plugins/ets/tests/ets_func_tests/std/core/TypeMethodTest.ets b/plugins/ets/tests/ets_func_tests/std/core/TypeMethodTest.ets new file mode 100644 index 0000000000000000000000000000000000000000..a52a76c0973731d5dc71cc51943891557cd5f319 --- /dev/null +++ b/plugins/ets/tests/ets_func_tests/std/core/TypeMethodTest.ets @@ -0,0 +1,172 @@ +function test(result: boolean, name: String): int { + if (result) { + console.println("PASSED: " + name) + return 0 + } + console.println("FAILED: " + name) + return 1 +} + +interface Serializable { + serialize(): String; +} + +class Point implements Serializable { + protected x: double + y: double + + override serialize(): String { + return "{" + this.x + "," + this.y + "}" + } + + add(oth: Point): Point { + let res = new Point() + res.x = this.x + oth.x + res.y = this.y + oth.y + return res + } +} + +abstract class Writer { + abstract write(): Int; + protected close() {} +} + +class HTMLWriter extends Writer { + private state_: int + + get state(): int { + return this.state_ + } + + private set state(state: int) { + this.state_ = state; + } + + static createFileExt(file: String): String { + return file + ".html" + } + + override write(): Int { + return new Int(2) + } + + constructor(state: int) { + this.state_ = state + } +} + +function findMethodByName(ct: ClassType, name: string): Method | null { + for (let i = 0; i < ct.getMethodsNum(); ++i) { + let method = ct.getMethod(i) + if (method.getName() == name) { + return method + } + } + return null +} + +function testMethodType(): int { + let pt = Type.of(new Point()) as ClassType + let hwt = Type.of(new HTMLWriter(10)) as ClassType + + let serializeMethodType = findMethodByName(pt, "serialize")!.getType() + let addMethodType = findMethodByName(pt, "add")!.getType() + let cType = hwt.getConstructor(0).getType() + let getterType = findMethodByName(hwt, "state")!.getType() + let setterType = findMethodByName(hwt, "state")!.getType() + + return test(serializeMethodType.getParametersNum() == 0, " 0 Parameters") + + test(serializeMethodType.getResultType() == StringType.REF, " has String result type") + + test(serializeMethodType.getReceiverType() == pt, " has Point receiver type") + + test(addMethodType.getParametersNum() == 1, " 1 parameter:") + + test(addMethodType.getParameter(0).getType() == pt, " Point parameter") + + test(addMethodType.getResultType() == pt, " has Point result type") + + test(addMethodType.getReceiverType() == pt, " has Point receiver type") + + test(cType.getParametersNum() == 1, " 1 Parameter") + + test(cType.getParameter(0).getType() == IntType.VAL, " int parameter") + + test(cType.getResultType() == VoidType.REF, " has void result type") + + test(cType.getReceiverType() == hwt, " has HTMLWriter receiver type") + + test(getterType.getParametersNum() == 0, " 0 Parameters") + + test(getterType.getResultType() == IntType.VAL, " has int result type") + + test(getterType.getReceiverType() == hwt, " has HTMLWriter receiver type") + + test(setterType.getParametersNum() == 1, " 1 Parameter") + + test(setterType.getParameter(0).getType() == IntType.VAL, " int parameter") + + test(setterType.getResultType() == VoidType.REF, " has void result type") + + test(setterType.getReceiverType() == hwt, " has HTMLWriter receiver type") +} + +function testMethod() { + let pt = Type.of(new Point()) as ClassType + let hwt = Type.of(new HTMLWriter(10)) as ClassType + let wt = hwt.getBaseType() + + let cMethod = hwt.getConstructor(0) + let getterMethod = findMethodByName(hwt, "state")! + let setterMethod = findMethodByName(hwt, "state")! + let createFileExtMethod = findMethodByName(hwt, "createFileExt")! + let abstractWriteMethod = findMethodByName(wt, "write")! + let closeMethod = findMethodByName(hwt, "close")! + + return test(cMethod.getName() == "constructor", "MethodName: constructor") + + test(cMethod.getAttributes() == Attributes.CONSTRUCTOR, " constructor attrib") + + test(cMethod.getAccessModifier() == AccessModifier.PUBLIC, " public access modifier") + + test(!cMethod.isInherited(), " not inherited") + + test(!cMethod.isStatic(), " not static") + + test(!cMethod.isAbstract(), " not abstract") + + test(!cMethod.isGetter(), " not getter") + + test(!cMethod.isSetter(), " not setter") + + test(getterMethod.getName() == "state", "MethodName: state") + + test(getterMethod.getAttributes() == Attributes.GETTER, " getter attrib") + + test(getterMethod.getAccessModifier() == AccessModifier.PUBLIC, " public access modifier") + + test(!getterMethod.isInherited(), " not inherited") + + test(!getterMethod.isStatic(), " not static") + + test(!getterMethod.isAbstract(), " not abstract") + + test(getterMethod.isGetter(), " getter") + + test(!getterMethod.isSetter(), " not setter") + + test(setterMethod.getName() == "state", "MethodName: state") + + test(setterMethod.getAttributes() == Attributes.SETTER, " setter attrib") + + test(setterMethod.getAccessModifier() == AccessModifier.PRIVATE, " private access modifier") + + test(!setterMethod.isInherited(), " not inherited") + + test(!setterMethod.isStatic(), " not static") + + test(!setterMethod.isAbstract(), " not abstract") + + test(!setterMethod.isGetter(), " not getter") + + test(setterMethod.isSetter(), " setter") + + test(createFileExtMethod.getName() == "createFileExt", "MethodName: createFileExt") + + test(createFileExtMethod.getAttributes() == Attributes.STATIC, " static attrib") + + test(createFileExtMethod.getAccessModifier() == AccessModifier.PUBLIC, " public access modifier") + + test(!createFileExtMethod.isInherited(), " not inherited") + + test(createFileExtMethod.isStatic(), " static") + + test(!createFileExtMethod.isAbstract(), " not abstract") + + test(!createFileExtMethod.isGetter(), " not getter") + + test(!createFileExtMethod.isSetter(), " not setter") + + test(abstractWriteMethod.getName() == "write", "MethodName: write") + + test(abstractWriteMethod.getAttributes() == Attributes.ABSTRACT, " abstract attrib") + + test(abstractWriteMethod.getAccessModifier() == AccessModifier.PUBLIC, " public access modifier") + + test(!abstractWriteMethod.isInherited(), " not inherited") + + test(!abstractWriteMethod.isStatic(), " not static") + + test(abstractWriteMethod.isAbstract(), " abstract") + + test(!abstractWriteMethod.isGetter(), " not getter") + + test(!abstractWriteMethod.isSetter(), " not setter") + + test(closeMethod.getName() == "close", "MethodName: close") + + test(closeMethod.getAttributes() == Attributes.INHERITED, " inherited attrib") + + test(closeMethod.getAccessModifier() == AccessModifier.PROTECTED, " protected access modifier") + + test(closeMethod.isInherited(), " inherited") + + test(!closeMethod.isStatic(), " not static") + + test(!closeMethod.isAbstract(), " not abstract") + + test(!closeMethod.isGetter(), " not getter") + + test(!closeMethod.isSetter(), " not setter") + +} + +function main(): int { + let failures = 0 + failures += testMethodType() + failures += testMethod() + if (failures == 0) { + console.println("PASSED: All tests run") + } else { + console.println("FAILED: All tests run") + } + return failures +} \ No newline at end of file diff --git a/plugins/ets/tests/stdlib-templates/std/core/list.std_core_type_array_type.yaml b/plugins/ets/tests/stdlib-templates/std/core/list.std_core_type_array_type.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8ada798eab26b19487613e8c59ab1ddf69c9b3a0 --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/std/core/list.std_core_type_array_type.yaml @@ -0,0 +1,80 @@ +- { + name: char, + init_value: "0 as char", + array_sizes: {1, 2, 10, 100}, + } +- { + name: boolean, + init_value: "false", + array_sizes: {1, 2, 10, 100}, + } +- { + name: byte, + init_value: "0 as byte", + array_sizes: {1, 2, 10, 100}, + } +- { + name: short, + init_value: "0 as short", + array_sizes: {1, 2, 10, 100}, + } +- { + name: int, + init_value: "0 as int", + array_sizes: {1, 2, 10, 100}, + } +- { + name: long, + init_value: "0 as long", + array_sizes: {1, 2, 10, 100}, + } +- { + name: float, + init_value: "0.0 as float", + array_sizes: {1, 2, 10, 100}, + } +- { + name: double, + init_value: "0 as double", + array_sizes: {1, 2, 10, 100}, + } +- { + name: Char, + init_value: "new Char()", + array_sizes: {1, 2, 10, 100}, + } +- { + name: Boolean, + init_value: "new Boolean()", + array_sizes: {1, 2, 10, 100}, + } +- { + name: Byte, + init_value: "new Byte()", + array_sizes: {1, 2, 10, 100}, + } +- { + name: Short, + init_value: "new Short()", + array_sizes: {1, 2, 10, 100}, + } +- { + name: Int, + init_value: "new Int()", + array_sizes: {1, 2, 10, 100}, + } +- { + name: Long, + init_value: "new Long()", + array_sizes: {1, 2, 10, 100}, + } +- { + name: Float, + init_value: "new Float()", + array_sizes: {1, 2, 10, 100}, + } +- { + name: Double, + init_value: "new Double()", + array_sizes: {1, 2, 10, 100}, +} diff --git a/plugins/ets/tests/stdlib-templates/std/core/list.std_core_type_numeric_type.yaml b/plugins/ets/tests/stdlib-templates/std/core/list.std_core_type_numeric_type.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8584a8b8551da29e03584641d53d508d052d11b5 --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/std/core/list.std_core_type_numeric_type.yaml @@ -0,0 +1,21 @@ +- { + types: + { + char: "0", + boolean: "false", + byte: "0", + short: "0", + int: "0", + long: "0", + float: "0.0", + double: "0.0", + Char: "new Char()", + Boolean: "new Boolean()", + Byte: "new Byte()", + Short: "new Short()", + Int: "new Int()", + Long: "new Long()", + Float: "new Float()", + Double: "new Double()" + } + } diff --git a/plugins/ets/tests/stdlib-templates/std/core/list.std_core_value.yaml b/plugins/ets/tests/stdlib-templates/std/core/list.std_core_value.yaml new file mode 100644 index 0000000000000000000000000000000000000000..46049a9267e8cd2a25a7370a58c7dce1ccccf36d --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/std/core/list.std_core_value.yaml @@ -0,0 +1,204 @@ +- { + name: char, + init_values: {"0 as char", "1 as char", "Char.MIN_VALUE as char", "Char.MAX_VALUE as char"}, + value_name: Char, + primitive: true + } +- { + name: boolean, + init_values: {"false", "true"}, + value_name: Boolean, + primitive: true + } +- { + name: byte, + init_values: {"0 as byte", "1 as byte", "-1 as byte", "Byte.MIN_VALUE as byte", "Byte.MAX_VALUE as byte"}, + value_name: Byte, + primitive: true + } +- { + name: short, + init_values: {"0 as short", "1 as short", "-1 as short", "Short.MIN_VALUE as short", "Short.MAX_VALUE as short"}, + value_name: Short, + primitive: true + } +- { + name: int, + init_values: {"0 as int", "1 as int", "-1 as int", "Int.MIN_VALUE as int", "Int.MAX_VALUE as int"}, + value_name: Int, + primitive: true + } +- { + name: long, + init_values: {"0 as long", "1 as long", "-1 as long", "Long.MIN_VALUE as long", "Long.MAX_VALUE as long"}, + value_name: Long, + primitive: true + } +- { + name: float, + init_values: {"0.0 as float", "1.0 as float", "-1.0 as float", "Float.MIN_VALUE as float", "Float.MAX_VALUE as float"}, + value_name: Float, + primitive: true + } +- { + name: double, + init_values: {"0.0 as double", "1.0 as double", "-1.0 as double", "Double.MIN_VALUE as double", "Double.MAX_VALUE as double"}, + value_name: Double, + primitive: true + } +- { + name: Char, + init_values: {"Char.valueOf(0 as char)", "Char.valueOf(1 as char)", "Char.valueOf(Char.MIN_VALUE as char)", "Char.valueOf(Char.MAX_VALUE as char)"}, + value_name: Char, + primitive: false + } +- { + name: Boolean, + init_values: {"Boolean.valueOf(false)", "Boolean.valueOf(true)"}, + value_name: Boolean, + primitive: false + } +- { + name: Byte, + init_values: {"Byte.valueOf(0 as byte)", "Byte.valueOf(1 as byte)", "Byte.valueOf(-1 as byte)", "Byte.valueOf(Byte.MIN_VALUE as byte)", "Byte.valueOf(Byte.MAX_VALUE as byte)"}, + value_name: Byte, + primitive: false + } +- { + name: Short, + init_values: {"Short.valueOf(0 as short)", "Short.valueOf(1 as short)", "Short.valueOf(-1 as short)", "Short.valueOf(Short.MIN_VALUE as short)", "Short.valueOf(Short.MAX_VALUE as short)"}, + value_name: Short, + primitive: false + } +- { + name: Int, + init_values: {"Int.valueOf(0 as int)", "Int.valueOf(1 as int)", "Int.valueOf(-1 as int)", "Int.valueOf(Int.MIN_VALUE as int)", "Int.valueOf(Int.MAX_VALUE as int)"}, + value_name: Int, + primitive: false + } +- { + name: Long, + init_values: {"Long.valueOf(0 as long)", "Long.valueOf(1 as long)", "Long.valueOf(-1 as long)", "Long.valueOf(Long.MIN_VALUE as long)", "Long.valueOf(Long.MAX_VALUE as long)"}, + value_name: Long, + primitive: false + } +- { + name: Float, + init_values: {"Float.valueOf(0.0 as float)", "Float.valueOf(1.0 as float)", "Float.valueOf(-1.0 as float)", "Float.valueOf(Float.MIN_VALUE as float)", "Float.valueOf(Float.MAX_VALUE as float)"}, + value_name: Float, + primitive: false + } +- { + name: Double, + init_values: {"Double.valueOf(0.0 as double)", "Double.valueOf(1.0 as double)", "Double.valueOf(-1.0 as double)", "Double.valueOf(Double.MIN_VALUE as double)", "Double.valueOf(Double.MAX_VALUE as double)"}, + value_name: Double, + primitive: false + } +- { + name: String, + init_values: {'""', '"\u0000 abcd"', '"abcd"', '"\u0000"'}, + value_name: String, + primitive: false + } +- { + name: "char[]", + init_values: {"[0 as char]", "[0 as char, 1 as char, Char.MIN_VALUE as char, Char.MAX_VALUE as char]"}, + value_name: Array, + primitive: false + } +- { + name: "boolean[]", + init_values: {"[false]", "[false, true]"}, + value_name: Array, + primitive: false + } +- { + name: "byte[]", + init_values: {"[0 as byte]", "[0 as byte, 1 as byte, -1 as byte, Byte.MIN_VALUE as byte, Byte.MAX_VALUE as byte]"}, + value_name: Array, + primitive: false + } +- { + name: "short[]", + init_values: {"[0 as short]", "[0 as short, 1 as short, -1 as short, Short.MIN_VALUE as short, Short.MAX_VALUE as short]"}, + value_name: Array, + primitive: false + } +- { + name: "int[]", + init_values: {"[0 as int]", "[0 as int, 1 as int, -1 as int, Int.MIN_VALUE as int, Int.MAX_VALUE as int]"}, + value_name: Array, + primitive: false + } +- { + name: "long[]", + init_values: {"[0 as long]", "[0 as long, 1 as long, -1 as long, Long.MIN_VALUE as long, Long.MAX_VALUE as long]"}, + value_name: Array, + primitive: false + } +- { + name: "float[]", + init_values: {"[0.0 as float]", "[0.0 as float, 1.0 as float, -1.0 as float, Float.MIN_VALUE as float, Float.MAX_VALUE as float]"}, + value_name: Array, + primitive: false + } +- { + name: "double[]", + init_values: {"[0.0 as double]", "[0.0 as double, 1.0 as double, -1.0 as double, Double.MIN_VALUE as double, Double.MAX_VALUE as double]"}, + value_name: Array, + primitive: false + } +- { + name: "Char[]", + init_values: {"[Char.valueOf(0 as char)]", "[Char.valueOf(0 as char), Char.valueOf(1 as char), Char.valueOf(Char.MIN_VALUE as char), Char.valueOf(Char.MAX_VALUE as char)]"}, + value_name: Array, + primitive: false + } +- { + name: "Boolean[]", + init_values: {"[Boolean.valueOf(false)]", "[Boolean.valueOf(false), Boolean.valueOf(true)]"}, + value_name: Array, + primitive: false + } +- { + name: "Byte[]", + init_values: {"[Byte.valueOf(0 as byte)]", "[Byte.valueOf(0 as byte), Byte.valueOf(1 as byte), Byte.valueOf(-1 as byte), Byte.valueOf(Byte.MIN_VALUE as byte), Byte.valueOf(Byte.MAX_VALUE as byte)]"}, + value_name: Array, + primitive: false + } +- { + name: "Short[]", + init_values: {"[Short.valueOf(0 as short)]", "[Short.valueOf(0 as short), Short.valueOf(1 as short), Short.valueOf(-1 as short), Short.valueOf(Short.MIN_VALUE as short), Short.valueOf(Short.MAX_VALUE as short)]"}, + value_name: Array, + primitive: false + } +- { + name: "Int[]", + init_values: {"[Int.valueOf(0 as int)]", "[Int.valueOf(0 as int), Int.valueOf(1 as int), Int.valueOf(-1 as int), Int.valueOf(Int.MIN_VALUE as int), Int.valueOf(Int.MAX_VALUE as int)]"}, + value_name: Array, + primitive: false + } +- { + name: "Long[]", + init_values: {"[Long.valueOf(0 as long)]", "[Long.valueOf(0 as long), Long.valueOf(1 as long), Long.valueOf(-1 as long), Long.valueOf(Long.MIN_VALUE as long), Long.valueOf(Long.MAX_VALUE as long)]"}, + value_name: Array, + primitive: false + } +- { + name: "Float[]", + init_values: {"[Float.valueOf(0.0 as float)]", "[Float.valueOf(0.0 as float), Float.valueOf(1.0 as float), Float.valueOf(-1.0 as float), Float.valueOf(Float.MIN_VALUE as float), Float.valueOf(Float.MAX_VALUE as float)]"}, + value_name: Array, + primitive: false + } +- { + name: "Double[]", + init_values: {"[Double.valueOf(0.0 as double),]", "[Double.valueOf(0.0 as double), Double.valueOf(1.0 as double), Double.valueOf(-1.0 as double), Double.valueOf(Double.MIN_VALUE as double), Double.valueOf(Double.MAX_VALUE as double)]"}, + value_name: Array, + primitive: false + } +- { + name: "String[]", + init_values: {'[""]', '["", "\u0000 abcd", "abcd", "\u0000"]'}, + value_name: Array, + primitive: false + } diff --git a/plugins/ets/tests/stdlib-templates/std/core/std_core_type_array_type.ets b/plugins/ets/tests/stdlib-templates/std/core/std_core_type_array_type.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fe9cfb262b8bae4f457d521ed94b85c26e7ca40 --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/std/core/std_core_type_array_type.ets @@ -0,0 +1,6 @@ +{% for item in std_core_type_array_type %} +/*--- +desc: {function: all } +---*/ +{% include 'utils/test_core_type_array_type.j2' with context %} +{%- endfor %} diff --git a/plugins/ets/tests/stdlib-templates/std/core/std_core_type_numeric_type.ets b/plugins/ets/tests/stdlib-templates/std/core/std_core_type_numeric_type.ets new file mode 100644 index 0000000000000000000000000000000000000000..e65b9a64791f307bd9538c28abca241573150945 --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/std/core/std_core_type_numeric_type.ets @@ -0,0 +1,7 @@ +{% for item in std_core_type_numeric_type %} +/*--- +desc: {function: numeric_type } +---*/ +{% include 'utils/test_core_type_numeric_type.j2' with context %} +{%- endfor %} +{% include 'utils/test_check_test_string_result.j2' with context %} \ No newline at end of file diff --git a/plugins/ets/tests/stdlib-templates/std/core/std_core_value.ets b/plugins/ets/tests/stdlib-templates/std/core/std_core_value.ets new file mode 100644 index 0000000000000000000000000000000000000000..4c1e4430ca548960708332088f898b6df45ccc27 --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/std/core/std_core_value.ets @@ -0,0 +1,7 @@ +{% for item in std_core_value %} +/*--- +desc: {function: all } +---*/ +{% include 'utils/test_core_value.j2' with context %} +{% include 'utils/test_check_test_value_data.j2' with context %} +{%- endfor %} \ No newline at end of file diff --git a/plugins/ets/tests/stdlib-templates/std/core/std_core_value_array_value.ets b/plugins/ets/tests/stdlib-templates/std/core/std_core_value_array_value.ets new file mode 100644 index 0000000000000000000000000000000000000000..3848211cd0aedb30e1ce470def3e07e2b96fb5f0 --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/std/core/std_core_value_array_value.ets @@ -0,0 +1,7 @@ +{% for item in std_core_value %} +/*--- +desc: {function: all } +---*/ +{% include 'utils/test_core_value_array_value.j2' with context %} +{% include 'utils/test_check_test_value_data.j2' with context %} +{%- endfor %} \ No newline at end of file diff --git a/plugins/ets/tests/stdlib-templates/std/core/std_core_value_class_value.ets b/plugins/ets/tests/stdlib-templates/std/core/std_core_value_class_value.ets new file mode 100644 index 0000000000000000000000000000000000000000..964058e5086a7498a5989e5191c74865cba701a1 --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/std/core/std_core_value_class_value.ets @@ -0,0 +1,7 @@ +{% for item in std_core_value %} +/*--- +desc: {function: all } +---*/ +{% include 'utils/test_core_value_class_value.j2' with context %} +{% include 'utils/test_check_test_value_data.j2' with context %} +{%- endfor %} \ No newline at end of file diff --git a/plugins/ets/tests/stdlib-templates/utils/test_check_test_value_data.j2 b/plugins/ets/tests/stdlib-templates/utils/test_check_test_value_data.j2 new file mode 100644 index 0000000000000000000000000000000000000000..57d297ec6629834690332747cdac1c3eb0b12d1d --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/utils/test_check_test_value_data.j2 @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{% if item.value_name == "Array" %} +function checkTestResult(actual : {{.item.name}}, expected : {{.item.name}}) : int { + console.print("\nACTUAL\n") + for (let i: int = 0; i < actual.length; i++) { + console.print(actual[i] + " ") + } + console.print("\nEXPECTED\n") + for (let i: int = 0; i < expected.length; i++) { + console.print(expected[i] + " ") + } + + for (let i: int = 0; i < actual.length; i++) { + if (actual[i] != expected[i]) return 1 + } + console.println("\n****") + return 0; +} +{% else %} +function checkTestResult(actual : {{.item.name}}, expected : {{.item.name}}) : int { + if (actual == expected) return 0; + return 1; +} +{% endif %} \ No newline at end of file diff --git a/plugins/ets/tests/stdlib-templates/utils/test_core_type_array_type.j2 b/plugins/ets/tests/stdlib-templates/utils/test_core_type_array_type.j2 new file mode 100644 index 0000000000000000000000000000000000000000..ce922267ac40efa8a02b54311dd6265ad3f22dcf --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/utils/test_core_type_array_type.j2 @@ -0,0 +1,54 @@ +function main(): int { + let failCounter: int = 0; + let testResult: int = 0; + let arrayVar : {{.item.name}}[]; + let expectedType : Type; + let arrayType : ArrayType; + let obj : {{.item.name}}[]; + {% for array_size in item.array_sizes %} + arrayVar = new {{.item.name}}[{{.array_size}}]; + for (let i = 0; i < {{.array_size}}; ++i) { + arrayVar[i] = {{.item.init_value}}; + } + arrayType = Type.of(arrayVar) as ArrayType; + testResult = checkTestResult(arrayType.getElementType(), Type.of({{.item.init_value}})); + printTestVerdict(testResult, "Type.of({{.item.name}}[]).getElementType() == {{.item.name}}"); + failCounter += testResult; + obj = arrayType.make({{.array_size}}) as {{.item.name}}[]; + testResult = checkTestResult(obj, arrayVar); + printTestVerdict(testResult, "Type.of({{.item.name}}[]).make()"); + failCounter += testResult; + {% endfor %} + if (failCounter > 0) return 1 + return 0; +} + +function printTestVerdict(flag: int, testName: String) { + if (flag == 0) { + console.println(testName + " : PASSED") + } else { + console.println(testName + " : FAILED") + } +} + +function checkTestResult(actual: Type, expected: Type) : int { + if (actual == expected) return 0; + return 1; +} + +function checkTestResult(actual : {{.item.name}}[], expected : {{.item.name}}[]) : int { + console.print("\nACTUAL\n") + for (let i: int = 0; i < actual.length; i++) { + console.print(actual[i] + " ") + } + console.print("\nEXPECTED\n") + for (let i: int = 0; i < expected.length; i++) { + console.print(expected[i] + " ") + } + + for (let i: int = 0; i < actual.length; i++) { + if (actual[i] != expected[i]) return 1 + } + console.println("\n****") + return 0; +} diff --git a/plugins/ets/tests/stdlib-templates/utils/test_core_type_numeric_type.j2 b/plugins/ets/tests/stdlib-templates/utils/test_core_type_numeric_type.j2 new file mode 100644 index 0000000000000000000000000000000000000000..f3e9a59d2a35946268568a75fff93ce44c40885a --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/utils/test_core_type_numeric_type.j2 @@ -0,0 +1,21 @@ +function main(): int { + let failCounter: int = 0; + let testResult: int = 0; + {% for type_name, init_value in item.types.items() %} + let var{{.type_name}} : {{.type_name}} = {{.init_value}}; + let actualType{{.type_name}}String = Type.of(var{{.type_name}}).getLiteral(); + testResult = checkTestResult(actualType{{.type_name}}String, "{{.type_name}}"); + printTestVerdict(testResult, "{{.type_name}}") + failCounter += testResult + {% endfor %} + if (failCounter > 0) return 1 + return 0; +} + +function printTestVerdict(flag: int, testName: String) { + if (flag == 0) { + console.println(testName + " : PASSED") + } else { + console.println(testName + " : FAILED") + } +} diff --git a/plugins/ets/tests/stdlib-templates/utils/test_core_value.j2 b/plugins/ets/tests/stdlib-templates/utils/test_core_value.j2 new file mode 100644 index 0000000000000000000000000000000000000000..6a611fac177796325850d7da10783033e0e378cb --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/utils/test_core_value.j2 @@ -0,0 +1,35 @@ +function main(): int { + let failCounter: int = 0; + let testResult: int = 0; + let variable : {{.item.name}}; + let actualValue : {{.item.value_name}}Value; + {% for init_value in item.init_values %} + variable = {{.init_value}}; + actualValue = Value.of(variable) as {{.item.value_name}}Value; + {% if item.primitive %} + testResult = checkTestResult(actualValue.getValueData() as {{.item.name}}, variable as {{.item.name}}); + {% else %} + testResult = checkTestResult(actualValue.getData() as {{.item.name}}, variable as {{.item.name}}); + {% endif %} + printTestVerdict(testResult, "Value.of({{.item.name}}).getData()"); + failCounter += testResult; + testResult = checkTestResult(actualValue.getType(), Type.of(variable)); + printTestVerdict(testResult, "Value.of({{.item.name}}}).getType() == {{.item.name}}"); + failCounter += testResult; + {% endfor %} + if (failCounter > 0) return 1 + return 0; +} + +function printTestVerdict(flag: int, testName: String) { + if (flag == 0) { + console.println(testName + " : PASSED") + } else { + console.println(testName + " : FAILED") + } +} + +function checkTestResult(actual: Type, expected: Type) : int { + if (actual == expected) return 0; + return 1; +} diff --git a/plugins/ets/tests/stdlib-templates/utils/test_core_value_array_value.j2 b/plugins/ets/tests/stdlib-templates/utils/test_core_value_array_value.j2 new file mode 100644 index 0000000000000000000000000000000000000000..a4505744f4429b6e7b483f9cd2579ec4e046d22d --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/utils/test_core_value_array_value.j2 @@ -0,0 +1,35 @@ +function main(): int { + let failCounter: int = 0; + let testResult: int = 0; + let arrayValue : ArrayValue = Value.of([{{.item.init_values | first}}]) as ArrayValue; + let actualValue : {{.item.value_name}}Value; + let storedValue : {{.item.value_name}}Value; + if (arrayValue.getLength() == 1) { + testResult = 1; + } else { + testResult = 0; + } + printTestVerdict(testResult, "Length of array is 1"); + {% for init_value in item.init_values %} + actualValue = Value.of({{.init_value}}) as {{.item.value_name}}Value; + arrayValue.setElement(0, actualValue); + storedValue = arrayValue.getElement(0) as {{.item.value_name}}Value; + {% if item.primitive %} + testResult = checkTestResult(actualValue.getValueData() as {{.item.name}}, storedValue.getValueData() as {{.item.name}}); + {% else %} + testResult = checkTestResult(actualValue.getData() as {{.item.name}}, storedValue.getData() as {{.item.name}}); + {% endif %} + printTestVerdict(testResult, "Element of array of {{.item.name}} type"); + failCounter += testResult; + {% endfor %} + if (failCounter > 0) return 1 + return 0; +} + +function printTestVerdict(flag: int, testName: String) { + if (flag == 0) { + console.println(testName + " : PASSED") + } else { + console.println(testName + " : FAILED") + } +} diff --git a/plugins/ets/tests/stdlib-templates/utils/test_core_value_class_value.j2 b/plugins/ets/tests/stdlib-templates/utils/test_core_value_class_value.j2 new file mode 100644 index 0000000000000000000000000000000000000000..1932c2161682fb4e00d33a6a9dd60a208f850087 --- /dev/null +++ b/plugins/ets/tests/stdlib-templates/utils/test_core_value_class_value.j2 @@ -0,0 +1,36 @@ +class TestClass { + field: {{.item.name}}; + constructor() { + this.field = {{.item.init_values | first}}; + } +} + +function main(): int { + let failCounter: int = 0; + let testResult: int = 0; + let classValue : ClassValue = Value.of(new TestClass()) as ClassValue; + let actualValue : {{.item.value_name}}Value; + let storedValue : {{.item.value_name}}Value; + {% for init_value in item.init_values %} + actualValue = Value.of({{.init_value}}) as {{.item.value_name}}Value; + classValue.setFieldByName("field", actualValue); + storedValue = classValue.getFieldByName("field") as {{.item.value_name}}Value; + {% if item.primitive %} + testResult = checkTestResult(actualValue.getValueData() as {{.item.name}}, storedValue.getValueData() as {{.item.name}}); + {% else %} + testResult = checkTestResult(actualValue.getData() as {{.item.name}}, storedValue.getData() as {{.item.name}}); + {% endif %} + printTestVerdict(testResult, "TestClass field of {{.item.name}} type"); + failCounter += testResult; + {% endfor %} + if (failCounter > 0) return 1 + return 0; +} + +function printTestVerdict(flag: int, testName: String) { + if (flag == 0) { + console.println(testName + " : PASSED") + } else { + console.println(testName + " : FAILED") + } +} diff --git a/runtime/mem/heap_verifier.cpp b/runtime/mem/heap_verifier.cpp index abade8c8b698048f27f61312f7031519dc7c8cbc..c5d7353f9f61607fca98f5adec677cce9ae800c8 100644 --- a/runtime/mem/heap_verifier.cpp +++ b/runtime/mem/heap_verifier.cpp @@ -13,6 +13,8 @@ * limitations under the License. */ +#include "include/mem/panda_string.h" +#include "mem/mem.h" #include "runtime/include/runtime.h" #include "runtime/include/panda_vm.h" #include "runtime/mem/gc/gc_root.h" @@ -174,7 +176,8 @@ size_t FastHeapVerifier::VerifyAll() const } LOG_HEAP_VERIFIER << "Heap object " << std::hex << object_cache.heap_object << " references a dead object at " << object_cache.referent << "(" << class_str - << " class)"; + << " class) " << coretypes::String::Cast(const_cast(object_cache.referent))->GetDataMUtf8(); +; ++fails_count; } }