Order typed functions over untyped
specifically the chaiscript defined ones
This commit is contained in:
parent
8f98e16e5e
commit
bd9af5eff4
@ -732,7 +732,6 @@ namespace chaiscript
|
|||||||
/// \throws std::range_error if it does not
|
/// \throws std::range_error if it does not
|
||||||
Boxed_Value get_function_object(const std::string &t_name) const
|
Boxed_Value get_function_object(const std::string &t_name) const
|
||||||
{
|
{
|
||||||
// std::cout << "Getting function object: " << t_name << '\n';
|
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
|
||||||
const auto &funs = get_boxed_functions_int();
|
const auto &funs = get_boxed_functions_int();
|
||||||
@ -1026,6 +1025,13 @@ namespace chaiscript
|
|||||||
void dump_function(const std::pair<const std::string, Proxy_Function > &f) const
|
void dump_function(const std::pair<const std::string, Proxy_Function > &f) const
|
||||||
{
|
{
|
||||||
std::vector<Type_Info> params = f.second->get_param_types();
|
std::vector<Type_Info> params = f.second->get_param_types();
|
||||||
|
std::vector<std::pair<std::string, Type_Info>> typed_params;
|
||||||
|
|
||||||
|
auto func(std::dynamic_pointer_cast<const dispatch::Dynamic_Function_Interface>(f.second));
|
||||||
|
if (func) {
|
||||||
|
typed_params = func->get_dynamic_param_types().types();
|
||||||
|
}
|
||||||
|
|
||||||
std::string annotation = f.second->annotation();
|
std::string annotation = f.second->annotation();
|
||||||
|
|
||||||
if (annotation.size() > 0) {
|
if (annotation.size() > 0) {
|
||||||
@ -1034,19 +1040,20 @@ namespace chaiscript
|
|||||||
dump_type(params.front());
|
dump_type(params.front());
|
||||||
std::cout << " " << f.first << "(";
|
std::cout << " " << f.first << "(";
|
||||||
|
|
||||||
for (std::vector<Type_Info>::const_iterator itr = params.begin() + 1;
|
for (size_t i = 1; i < params.size(); ++i)
|
||||||
itr != params.end();
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
dump_type(*itr);
|
if (!typed_params.empty() && !typed_params[i-1].first.empty()) {
|
||||||
++itr;
|
std::cout << typed_params[i-1].first;
|
||||||
|
} else {
|
||||||
|
dump_type(params[i]);
|
||||||
|
}
|
||||||
|
|
||||||
if (itr != params.end())
|
if (i != params.size() - 1) {
|
||||||
{
|
|
||||||
std::cout << ", ";
|
std::cout << ", ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::cout << ") \n";
|
std::cout << ") \n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1253,34 +1260,50 @@ namespace chaiscript
|
|||||||
return m_state.m_functions;
|
return m_state.m_functions;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
|
|
||||||
{
|
|
||||||
|
|
||||||
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(lhs));
|
static std::vector<Type_Info> param_types(const Proxy_Function &t_f)
|
||||||
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(rhs));
|
|
||||||
|
|
||||||
if (dynamic_lhs && dynamic_rhs)
|
|
||||||
{
|
{
|
||||||
if (dynamic_lhs->get_guard())
|
assert(t_f);
|
||||||
{
|
return t_f->get_param_types();
|
||||||
return dynamic_rhs->get_guard() ? false : true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dynamic_lhs && !dynamic_rhs)
|
static std::vector<std::pair<std::string, Type_Info>> param_types(const std::shared_ptr<const dispatch::Dynamic_Function_Interface> &t_f)
|
||||||
{
|
{
|
||||||
return false;
|
assert(t_f);
|
||||||
|
const auto types = t_f->get_dynamic_param_types().types();
|
||||||
|
std::vector<std::pair<std::string, Type_Info>> ret(1);
|
||||||
|
ret.insert(ret.end(), types.begin(), types.end());
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dynamic_lhs && dynamic_rhs)
|
static Type_Info type_info(const std::pair<std::string, Type_Info> &t_ti)
|
||||||
{
|
{
|
||||||
return true;
|
return t_ti.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &lhsparamtypes = lhs->get_param_types();
|
static Type_Info type_info(const Type_Info &t_ti)
|
||||||
const auto &rhsparamtypes = rhs->get_param_types();
|
{
|
||||||
|
return t_ti;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string dynamic_type_name(const std::pair<std::string, Type_Info> &t_ti)
|
||||||
|
{
|
||||||
|
return t_ti.first.empty()?t_ti.second.name():t_ti.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string dynamic_type_name(const Type_Info &ti)
|
||||||
|
{
|
||||||
|
return ti.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename LHS, typename RHS>
|
||||||
|
static bool params_less_than(const LHS &t_lhs, const RHS &t_rhs)
|
||||||
|
{
|
||||||
|
assert(t_lhs);
|
||||||
|
assert(t_rhs);
|
||||||
|
const auto lhsparamtypes = param_types(t_lhs);
|
||||||
|
const auto rhsparamtypes = param_types(t_rhs);
|
||||||
|
|
||||||
const auto lhssize = lhsparamtypes.size();
|
const auto lhssize = lhsparamtypes.size();
|
||||||
const auto rhssize = rhsparamtypes.size();
|
const auto rhssize = rhsparamtypes.size();
|
||||||
@ -1288,15 +1311,38 @@ namespace chaiscript
|
|||||||
#ifdef CHAISCRIPT_HAS_MAGIC_STATICS
|
#ifdef CHAISCRIPT_HAS_MAGIC_STATICS
|
||||||
static auto boxed_type = user_type<Boxed_Value>();
|
static auto boxed_type = user_type<Boxed_Value>();
|
||||||
static auto boxed_pod_type = user_type<Boxed_Number>();
|
static auto boxed_pod_type = user_type<Boxed_Number>();
|
||||||
|
static auto dynamic_type = user_type<dispatch::Dynamic_Object>();
|
||||||
#else
|
#else
|
||||||
auto boxed_type = user_type<Boxed_Value>();
|
auto boxed_type = user_type<Boxed_Value>();
|
||||||
auto boxed_pod_type = user_type<Boxed_Number>();
|
auto boxed_pod_type = user_type<Boxed_Number>();
|
||||||
|
auto dynamic_type = user_type<dispatch::Dynamic_Object>();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (size_t i = 1; i < lhssize && i < rhssize; ++i)
|
for (size_t i = 1; i < lhssize && i < rhssize; ++i)
|
||||||
{
|
{
|
||||||
const Type_Info < = lhsparamtypes[i];
|
const Type_Info lt = type_info(lhsparamtypes[i]);
|
||||||
const Type_Info &rt = rhsparamtypes[i];
|
const Type_Info rt = type_info(rhsparamtypes[i]);
|
||||||
|
const std::string ln = dynamic_type_name(lhsparamtypes[i]);
|
||||||
|
const std::string rn = dynamic_type_name(rhsparamtypes[i]);
|
||||||
|
|
||||||
|
if ( (lt.bare_equal(dynamic_type) || lt.is_undef())
|
||||||
|
&& (rt.bare_equal(dynamic_type) || rt.is_undef()))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!ln.empty() && rn.empty()) {
|
||||||
|
return true;
|
||||||
|
} else if (ln.empty() && !rn.empty()) {
|
||||||
|
return false;
|
||||||
|
} else if (!ln.empty() && !rn.empty()) {
|
||||||
|
if (ln < rn) {
|
||||||
|
return true;
|
||||||
|
} else if (rn < ln) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the remaining cases are handled by the is_const rules below
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (lt.bare_equal(rt) && lt.is_const() == rt.is_const())
|
if (lt.bare_equal(rt) && lt.is_const() == rt.is_const())
|
||||||
{
|
{
|
||||||
@ -1343,8 +1389,38 @@ namespace chaiscript
|
|||||||
return lt < rt;
|
return lt < rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if everything else checks out, sort on guard
|
||||||
|
//
|
||||||
|
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_lhs));
|
||||||
|
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_rhs));
|
||||||
|
|
||||||
|
if (dynamic_lhs && dynamic_rhs) {
|
||||||
|
if (dynamic_lhs->get_guard() && !dynamic_rhs->get_guard()) {
|
||||||
|
return true;
|
||||||
|
} else if (dynamic_rhs->get_guard()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs)
|
||||||
|
{
|
||||||
|
auto dynamic_lhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Function_Interface>(lhs));
|
||||||
|
auto dynamic_rhs(std::dynamic_pointer_cast<const dispatch::Dynamic_Function_Interface>(rhs));
|
||||||
|
|
||||||
|
if (dynamic_lhs && dynamic_rhs)
|
||||||
|
{
|
||||||
|
return params_less_than(dynamic_lhs, dynamic_rhs);
|
||||||
|
} else if (dynamic_lhs) {
|
||||||
|
return params_less_than(dynamic_lhs, rhs);
|
||||||
|
} else if (dynamic_rhs) {
|
||||||
|
return params_less_than(lhs, dynamic_rhs);
|
||||||
|
} else {
|
||||||
|
return params_less_than(lhs, rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Throw a reserved_word exception if the name is not allowed
|
/// Throw a reserved_word exception if the name is not allowed
|
||||||
|
@ -39,7 +39,8 @@ namespace chaiscript
|
|||||||
/// A Proxy_Function implementation designed for calling a function
|
/// A Proxy_Function implementation designed for calling a function
|
||||||
/// that is automatically guarded based on the first param based on the
|
/// that is automatically guarded based on the first param based on the
|
||||||
/// param's type name
|
/// param's type name
|
||||||
class Dynamic_Object_Function : public Proxy_Function_Base
|
class Dynamic_Object_Function : public Proxy_Function_Base, public Dynamic_Function_Interface
|
||||||
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Dynamic_Object_Function(
|
Dynamic_Object_Function(
|
||||||
@ -72,6 +73,17 @@ namespace chaiscript
|
|||||||
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
|
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
|
||||||
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
|
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
|
||||||
|
|
||||||
|
virtual Param_Types get_dynamic_param_types() const {
|
||||||
|
auto dynamic(std::dynamic_pointer_cast<dispatch::Dynamic_Function_Interface>(m_func));
|
||||||
|
|
||||||
|
if (dynamic) {
|
||||||
|
return dynamic->get_dynamic_param_types();
|
||||||
|
} else {
|
||||||
|
return Param_Types(get_param_types());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
|
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
|
||||||
{
|
{
|
||||||
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
|
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
|
||||||
@ -182,7 +194,7 @@ namespace chaiscript
|
|||||||
* that is automatically guarded based on the first param based on the
|
* that is automatically guarded based on the first param based on the
|
||||||
* param's type name
|
* param's type name
|
||||||
*/
|
*/
|
||||||
class Dynamic_Object_Constructor : public Proxy_Function_Base
|
class Dynamic_Object_Constructor : public Proxy_Function_Base, public Dynamic_Function_Interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Dynamic_Object_Constructor(
|
Dynamic_Object_Constructor(
|
||||||
@ -191,6 +203,7 @@ namespace chaiscript
|
|||||||
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
|
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
|
||||||
m_type_name(std::move(t_type_name)), m_func(t_func)
|
m_type_name(std::move(t_type_name)), m_func(t_func)
|
||||||
{
|
{
|
||||||
|
assert( t_func );
|
||||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||||
}
|
}
|
||||||
@ -210,6 +223,17 @@ namespace chaiscript
|
|||||||
|
|
||||||
virtual ~Dynamic_Object_Constructor() {}
|
virtual ~Dynamic_Object_Constructor() {}
|
||||||
|
|
||||||
|
virtual Param_Types get_dynamic_param_types() const {
|
||||||
|
auto dynamic(std::dynamic_pointer_cast<dispatch::Dynamic_Function_Interface>(m_func));
|
||||||
|
|
||||||
|
if (dynamic) {
|
||||||
|
return dynamic->get_dynamic_param_types();
|
||||||
|
} else {
|
||||||
|
return Param_Types(get_param_types());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
|
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
|
||||||
{
|
{
|
||||||
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
||||||
@ -232,7 +256,7 @@ namespace chaiscript
|
|||||||
protected:
|
protected:
|
||||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||||
{
|
{
|
||||||
auto bv = var(Dynamic_Object(m_type_name));
|
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
|
||||||
std::vector<Boxed_Value> new_params{bv};
|
std::vector<Boxed_Value> new_params{bv};
|
||||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||||
|
|
||||||
|
@ -53,6 +53,13 @@ namespace chaiscript
|
|||||||
m_doti(user_type<Dynamic_Object>())
|
m_doti(user_type<Dynamic_Object>())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
Param_Types(const std::vector<Type_Info> &t_types)
|
||||||
|
: m_types(build_param_types(t_types)),
|
||||||
|
m_has_types(false),
|
||||||
|
m_doti(user_type<Dynamic_Object>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
|
Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
|
||||||
: m_types(std::move(t_types)),
|
: m_types(std::move(t_types)),
|
||||||
m_has_types(false),
|
m_has_types(false),
|
||||||
@ -61,6 +68,18 @@ namespace chaiscript
|
|||||||
update_has_types();
|
update_has_types();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<std::pair<std::string, Type_Info>> build_param_types(const std::vector<Type_Info> &t_types)
|
||||||
|
{
|
||||||
|
std::vector<std::pair<std::string, Type_Info>> retval;
|
||||||
|
std::transform(t_types.begin(), t_types.end(), std::back_inserter(retval),
|
||||||
|
[](const Type_Info &ti){
|
||||||
|
return std::make_pair(std::string(), ti);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
void push_front(std::string t_name, Type_Info t_ti)
|
void push_front(std::string t_name, Type_Info t_ti)
|
||||||
{
|
{
|
||||||
m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti));
|
m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti));
|
||||||
@ -295,11 +314,18 @@ namespace chaiscript
|
|||||||
|
|
||||||
namespace dispatch
|
namespace dispatch
|
||||||
{
|
{
|
||||||
|
class Dynamic_Function_Interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Dynamic_Function_Interface() {}
|
||||||
|
virtual Param_Types get_dynamic_param_types() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Proxy_Function implementation that is not type safe, the called function
|
* A Proxy_Function implementation that is not type safe, the called function
|
||||||
* is expecting a vector<Boxed_Value> that it works with how it chooses.
|
* is expecting a vector<Boxed_Value> that it works with how it chooses.
|
||||||
*/
|
*/
|
||||||
class Dynamic_Proxy_Function : public Proxy_Function_Base
|
class Dynamic_Proxy_Function : public Proxy_Function_Base, public Dynamic_Function_Interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Dynamic_Proxy_Function(
|
Dynamic_Proxy_Function(
|
||||||
@ -349,6 +375,9 @@ namespace chaiscript
|
|||||||
return m_description;
|
return m_description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Param_Types get_dynamic_param_types() const {
|
||||||
|
return m_param_types;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool test_guard(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const
|
bool test_guard(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const
|
||||||
@ -367,6 +396,8 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
|
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
|
||||||
{
|
{
|
||||||
@ -678,6 +709,8 @@ namespace chaiscript
|
|||||||
std::reference_wrapper<std::function<Func>> m_f;
|
std::reference_wrapper<std::function<Func>> m_f;
|
||||||
std::shared_ptr<std::function<Func>> m_shared_ptr_holder;
|
std::shared_ptr<std::function<Func>> m_shared_ptr_holder;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Attribute getter Proxy_Function implementation
|
/// Attribute getter Proxy_Function implementation
|
||||||
template<typename T, typename Class>
|
template<typename T, typename Class>
|
||||||
class Attribute_Access : public Proxy_Function_Base
|
class Attribute_Access : public Proxy_Function_Base
|
||||||
@ -875,6 +908,15 @@ namespace chaiscript
|
|||||||
std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
|
std::vector<std::pair<size_t, const Proxy_Function_Base *>> ordered_funcs;
|
||||||
ordered_funcs.reserve(funcs.size());
|
ordered_funcs.reserve(funcs.size());
|
||||||
|
|
||||||
|
#ifdef CHAISCRIPT_HAS_MAGIC_STATICS
|
||||||
|
static auto boxed_type = user_type<Boxed_Value>();
|
||||||
|
static auto dynamic_type = user_type<Dynamic_Object>();
|
||||||
|
#else
|
||||||
|
auto boxed_type = user_type<Boxed_Value>();
|
||||||
|
auto dynamic_type = user_type<Dynamic_Object>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
for (const auto &func : funcs)
|
for (const auto &func : funcs)
|
||||||
{
|
{
|
||||||
const auto arity = func->get_arity();
|
const auto arity = func->get_arity();
|
||||||
@ -886,7 +928,10 @@ namespace chaiscript
|
|||||||
size_t numdiffs = 0;
|
size_t numdiffs = 0;
|
||||||
for (size_t i = 0; i < plist.size(); ++i)
|
for (size_t i = 0; i < plist.size(); ++i)
|
||||||
{
|
{
|
||||||
if (!func->get_param_types()[i+1].bare_equal(plist[i].get_type_info()))
|
const auto &p_type = plist[i].get_type_info();
|
||||||
|
const auto &f_type = func->get_param_types()[i+1];
|
||||||
|
|
||||||
|
if (!(f_type.bare_equal(boxed_type) && p_type.bare_equal(dynamic_type)) && !f_type.bare_equal(p_type))
|
||||||
{
|
{
|
||||||
++numdiffs;
|
++numdiffs;
|
||||||
}
|
}
|
||||||
|
38
unittests/clone_object.chai
Normal file
38
unittests/clone_object.chai
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
GLOBAL clone_count = 0;
|
||||||
|
|
||||||
|
class Cloneable
|
||||||
|
{
|
||||||
|
def Cloneable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def clone(Cloneable c)
|
||||||
|
{
|
||||||
|
print("Clone called");
|
||||||
|
++clone_count;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MyObject
|
||||||
|
{
|
||||||
|
def MyObject() {
|
||||||
|
this.data = Cloneable();
|
||||||
|
}
|
||||||
|
|
||||||
|
var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
assert_equal(0, clone_count);
|
||||||
|
|
||||||
|
var o = MyObject();
|
||||||
|
|
||||||
|
assert_equal(0, clone_count);
|
||||||
|
|
||||||
|
var p = o;
|
||||||
|
|
||||||
|
assert_equal(1, clone_count);
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user