mirror of https://github.com/KLayout/klayout.git
Ported upgrade to expressions too
This commit is contained in:
parent
2b93dc2dc7
commit
cb1589b2ba
|
|
@ -286,6 +286,25 @@ struct test_arg_func<gsi::ObjectType>
|
|||
return;
|
||||
}
|
||||
|
||||
if (arg.is_list ()) {
|
||||
|
||||
// we may implicitly convert an array into a constructor call of a target object -
|
||||
// for now we only check whether the number of arguments is compatible with the array given.
|
||||
|
||||
int n = arg.size ();
|
||||
|
||||
*ret = false;
|
||||
for (gsi::ClassBase::method_iterator c = atype.cls ()->begin_constructors (); c != atype.cls ()->end_constructors (); ++c) {
|
||||
if ((*c)->compatible_with_num_args (n)) {
|
||||
*ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (! arg.is_user ()) {
|
||||
*ret = false;
|
||||
return;
|
||||
|
|
@ -628,29 +647,77 @@ struct writer<gsi::ObjectType>
|
|||
{
|
||||
void operator() (gsi::SerialArgs *aa, tl::Variant *arg, const gsi::ArgType &atype, tl::Heap *heap)
|
||||
{
|
||||
if (atype.is_ref () || atype.is_cref () || atype.is_ptr () || atype.is_cptr ()) {
|
||||
if (arg->is_nil ()) {
|
||||
|
||||
if (arg->is_nil ()) {
|
||||
if (atype.is_ref () || atype.is_cref ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot pass nil to reference parameters")));
|
||||
} else if (! atype.is_cptr () && ! atype.is_ptr ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot pass nil to direct parameters")));
|
||||
}
|
||||
|
||||
if (atype.is_ref () || atype.is_cref ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot pass nil to reference parameters")));
|
||||
aa->write<void *> ((void *) 0);
|
||||
|
||||
} else if (arg->is_list ()) {
|
||||
|
||||
// we may implicitly convert an array into a constructor call of a target object -
|
||||
// for now we only check whether the number of arguments is compatible with the array given.
|
||||
|
||||
int n = arg->size ();
|
||||
const gsi::MethodBase *meth = 0;
|
||||
for (gsi::ClassBase::method_iterator c = atype.cls ()->begin_constructors (); c != atype.cls ()->end_constructors (); ++c) {
|
||||
if ((*c)->compatible_with_num_args (n)) {
|
||||
meth = *c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
aa->write<void *> ((void *) 0);
|
||||
if (!meth) {
|
||||
throw tl::Exception (tl::to_string (tr ("No constructor of %s available that takes %d arguments (implicit call from tuple)")), atype.cls ()->name (), n);
|
||||
}
|
||||
|
||||
} else {
|
||||
// implicit call of constructor
|
||||
gsi::SerialArgs retlist (meth->retsize ());
|
||||
gsi::SerialArgs arglist (meth->argsize ());
|
||||
|
||||
if (! arg->is_user ()) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s)")), atype.cls ()->name ()));
|
||||
int narg = 0;
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && narg < n; ++a, ++narg) {
|
||||
try {
|
||||
// Note: this const_cast is ugly, but it will basically enable "out" parameters
|
||||
// TODO: clean this up.
|
||||
gsi::do_on_type<writer> () (a->type (), &arglist, (arg->get_list ().begin () + narg).operator-> (), *a, heap);
|
||||
} catch (tl::Exception &ex) {
|
||||
std::string msg = ex.msg () + tl::sprintf (tl::to_string (tr (" (argument '%s')")), a->spec ()->name ());
|
||||
throw tl::Exception (msg);
|
||||
}
|
||||
}
|
||||
|
||||
const tl::VariantUserClassBase *cls = arg->user_cls ();
|
||||
if (!cls) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s)")), atype.cls ()->name ()));
|
||||
}
|
||||
if (cls->is_const () && (atype.is_ref () || atype.is_ptr ())) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot pass a const reference of class %s to a non-const reference or pointer parameter")), atype.cls ()->name ()));
|
||||
}
|
||||
meth->call (0, arglist, retlist);
|
||||
|
||||
void *new_obj = retlist.read<void *> (*heap);
|
||||
if (new_obj && (atype.is_ptr () || atype.is_cptr () || atype.is_ref () || atype.is_cref ())) {
|
||||
// For pointers or refs, ownership over these objects is not transferred.
|
||||
// Hence we have to keep them on the heap.
|
||||
// TODO: what if the called method takes ownership using keep()?
|
||||
heap->push (new gsi::ObjectHolder (atype.cls (), new_obj));
|
||||
}
|
||||
|
||||
aa->write<void *> (new_obj);
|
||||
|
||||
} else {
|
||||
|
||||
if (! arg->is_user ()) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s)")), atype.cls ()->name ()));
|
||||
}
|
||||
|
||||
const tl::VariantUserClassBase *cls = arg->user_cls ();
|
||||
if (!cls) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s)")), atype.cls ()->name ()));
|
||||
}
|
||||
if (cls->is_const () && (atype.is_ref () || atype.is_ptr ())) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot pass a const reference of class %s to a non-const reference or pointer parameter")), atype.cls ()->name ()));
|
||||
}
|
||||
|
||||
if (atype.is_ref () || atype.is_cref () || atype.is_ptr () || atype.is_cptr ()) {
|
||||
|
||||
if (cls->gsi_cls ()->is_derived_from (atype.cls ())) {
|
||||
|
||||
|
|
@ -673,36 +740,24 @@ struct writer<gsi::ObjectType>
|
|||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s)")), atype.cls ()->name ()));
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
} else {
|
||||
if (cls->gsi_cls ()->is_derived_from (atype.cls ())) {
|
||||
|
||||
if (! arg->is_user ()) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s)")), atype.cls ()->name ()));
|
||||
}
|
||||
if (cls->gsi_cls ()->adapted_type_info ()) {
|
||||
aa->write<void *> (cls->gsi_cls ()->create_adapted_from_obj (get_object (*arg)));
|
||||
} else {
|
||||
aa->write<void *> ((void *) cls->gsi_cls ()->clone (get_object (*arg)));
|
||||
}
|
||||
|
||||
const tl::VariantUserClassBase *cls = arg->user_cls ();
|
||||
if (!cls) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s)")), atype.cls ()->name ()));
|
||||
}
|
||||
if (cls->is_const () && (atype.is_ref () || atype.is_ptr ())) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot pass a const reference of class %s to a non-const reference or pointer parameter")), atype.cls ()->name ()));
|
||||
}
|
||||
} else if (cls->gsi_cls ()->can_convert_to (atype.cls ())) {
|
||||
|
||||
if (cls->gsi_cls ()->is_derived_from (atype.cls ())) {
|
||||
aa->write<void *> (atype.cls ()->create_obj_from (cls->gsi_cls (), get_object (*arg)));
|
||||
|
||||
if (cls->gsi_cls ()->adapted_type_info ()) {
|
||||
aa->write<void *> (cls->gsi_cls ()->create_adapted_from_obj (get_object (*arg)));
|
||||
} else {
|
||||
aa->write<void *> ((void *) cls->gsi_cls ()->clone (get_object (*arg)));
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s)")), atype.cls ()->name ()));
|
||||
}
|
||||
|
||||
} else if (cls->gsi_cls ()->can_convert_to (atype.cls ())) {
|
||||
|
||||
aa->write<void *> (atype.cls ()->create_obj_from (cls->gsi_cls (), get_object (*arg)));
|
||||
|
||||
} else {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Unexpected object type (expected argument of class %s)")), atype.cls ()->name ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,14 +57,14 @@ TEST(1)
|
|||
v = e.parse ("A.aa").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("static_a"));
|
||||
|
||||
v = e.parse ("A.new.a1").execute ();
|
||||
v = e.parse ("A.new.get_n").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("17"));
|
||||
v = e.parse ("var a=A.new").execute ();
|
||||
v = e.parse ("a.a5(-5); a.a1").execute ();
|
||||
v = e.parse ("a.a5(-5); a.get_n").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("-5"));
|
||||
|
||||
// mapping of property assignment to method
|
||||
v = e.parse ("a.n = -177; a.a1").execute ();
|
||||
v = e.parse ("a.n = -177; a.get_n").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("-177"));
|
||||
bool error = false;
|
||||
try {
|
||||
|
|
@ -104,9 +104,9 @@ TEST(1)
|
|||
v = e.parse ("A.instance_count").execute ();
|
||||
EXPECT_EQ (v.to_int (), base_insts); // remaining instances
|
||||
|
||||
v = e.parse ("var a1=A.new; a1.a5(-15); var a2=a1.dup; a2.a5(107); a1.a1").execute ();
|
||||
v = e.parse ("var a1=A.new; a1.a5(-15); var a2=a1.dup; a2.a5(107); a1.get_n").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("-15"));
|
||||
v = e.parse ("var a1=A.new; a1.a5(-15); var a2=a1.dup; a2.a5(107); a2.a1").execute ();
|
||||
v = e.parse ("var a1=A.new; a1.a5(-15); var a2=a1.dup; a2.a5(107); a2.get_n").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("107"));
|
||||
|
||||
v = e.parse ("var a=A.new; a.get_e.to_s").execute ();
|
||||
|
|
@ -218,12 +218,22 @@ TEST(2)
|
|||
EXPECT_EQ (v.to_string (), std::string ("5"));
|
||||
v = e.parse ("var b=B.new; var a1=A.new(-17); var a2=A.new(42); b.av = [ a1, a2 ]; to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: -17,A: 42"));
|
||||
v = e.parse ("var b=B.new; var a1=A.new(-17); var a2=A.new(42); b.av = []; b.push_a(a1); b.push_a(a2); to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: -17,A: 42"));
|
||||
v = e.parse ("var b=B.new; var a1=A.new(-17); var a2=A.new(42); b.av = []; b.push_a_cref(a1); b.push_a_cptr(a2); to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: -17,A: 42"));
|
||||
v = e.parse ("var b=B.new; var a1=A.new(-17); var a2=A.new(42); b.av = []; b.push_a_ref(a1); b.push_a_ptr(a2); to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: -17,A: 42"));
|
||||
v = e.parse ("var b=B.new; var a1=A.new(-17); var a2=A.new(1); b.av_cref = [ a1, a2 ]; to_s(b.av_cref)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: -17,A: 1"));
|
||||
v = e.parse ("var b=B.new; b.av = [ A.new(-13) ]; b.av_cptr = nil; to_s(b.av)").execute ();
|
||||
v = e.parse ("var b=B.new; b.av_cptr = [ A.new(-13) ]; to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: -13"));
|
||||
v = e.parse ("var b=B.new; b.av = [ A.new(13) ]; b.av_ptr = nil; to_s(b.av)").execute ();
|
||||
v = e.parse ("var b=B.new; b.av_ptr = [ A.new(13) ]; to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: 13"));
|
||||
v = e.parse ("var b=B.new; b.av = [ A.new(-13) ]; b.av_cptr = nil; to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string (""));
|
||||
v = e.parse ("var b=B.new; b.av = [ A.new(13) ]; b.av_ptr = nil; to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string (""));
|
||||
v = e.parse ("var b=B.new; var a1=A.new(17); b.av_ref = [ a1 ]; to_s(b.av_ref)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: 17"));
|
||||
v = e.parse ("var b=B.new; b.arg_is_not_nil(nil)").execute ();
|
||||
|
|
@ -234,6 +244,21 @@ TEST(2)
|
|||
EXPECT_EQ (v.to_string (), std::string ("17"));
|
||||
v = e.parse ("var b=B.new; b.bx(-1)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("xz"));
|
||||
|
||||
// List to constructor call
|
||||
v = e.parse ("var b=B.new; b.av = [ [5, 6], [4, 6, 0.5], [42] ]; to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: 11,A: 5,A: 42"));
|
||||
v = e.parse ("var b=B.new; b.av = []; b.push_a([ 1, 2 ]); b.push_a([ 17 ]); to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: 3,A: 17"));
|
||||
v = e.parse ("var b=B.new; b.av = []; b.push_a([ 1, 2 ]); b.push_a_cref([ 17 ]); to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: 3,A: 17"));
|
||||
v = e.parse ("var b=B.new; b.av = []; b.push_a([ 1, 2 ]); b.push_a_cptr([ 17 ]); to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: 3,A: 17"));
|
||||
v = e.parse ("var b=B.new; b.av = []; b.push_a([ 1, 2 ]); b.push_a_ref([ 17 ]); to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: 3,A: 17"));
|
||||
v = e.parse ("var b=B.new; b.av = []; b.push_a([ 1, 2 ]); b.push_a_ptr([ 17 ]); to_s(b.av)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("A: 3,A: 17"));
|
||||
|
||||
/*
|
||||
TODO: No detailed type analysis for ambiguity resolution so far:
|
||||
v = e.parse ("var b=B.new; b.bx('hello', 1)").execute ();
|
||||
|
|
@ -316,15 +341,15 @@ TEST(2)
|
|||
EXPECT_EQ (v.to_string (), std::string ("A: 177"));
|
||||
v = e.parse ("b.amember_or_nil(false)").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("nil"));
|
||||
v = e.parse ("b.amember_ptr.a5(177); b.amember_ref.a1").execute ();
|
||||
v = e.parse ("b.amember_ptr.a5(177); b.amember_ref.get_n").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("177"));
|
||||
v = e.parse ("b.amember_ref.a1c").execute ();
|
||||
v = e.parse ("b.amember_ref.get_n_const").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("177"));
|
||||
v = e.parse ("b.amember_cref.a1c").execute ();
|
||||
v = e.parse ("b.amember_cref.get_n_const").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("177"));
|
||||
error = false;
|
||||
try {
|
||||
v = e.parse ("b.amember_cref.a1").execute ();
|
||||
v = e.parse ("b.amember_cref.get_n").execute ();
|
||||
} catch (...) {
|
||||
// can't call non-const method on const ref
|
||||
error = true;
|
||||
|
|
@ -334,16 +359,16 @@ TEST(2)
|
|||
// references: storage in variables
|
||||
v = e.parse ("var aref = b.amember_ptr").execute ();
|
||||
v = e.parse ("aref.n = 178").execute ();
|
||||
v = e.parse ("aref.a1").execute ();
|
||||
v = e.parse ("aref.get_n").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("178"));
|
||||
v = e.parse ("aref.a1 == 178").execute ();
|
||||
v = e.parse ("aref.get_n == 178").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("true"));
|
||||
v = e.parse ("b.amember_ref.a1").execute ();
|
||||
v = e.parse ("b.amember_ref.get_n").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("178"));
|
||||
|
||||
// references: storage in variables
|
||||
v = e.parse ("var aref = b.amember_cptr").execute ();
|
||||
v = e.parse ("aref.a1c").execute ();
|
||||
v = e.parse ("aref.get_n_const").execute ();
|
||||
EXPECT_EQ (v.to_string (), std::string ("178"));
|
||||
error = false;
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -265,7 +265,15 @@ bool TestBase::do_test (bool editable, bool slow)
|
|||
|
||||
reset_checkpoint ();
|
||||
|
||||
execute (this);
|
||||
try {
|
||||
execute (this);
|
||||
} catch (tl::Exception &ex) {
|
||||
raise (std::string ("Exception caught: ") + ex.msg ());
|
||||
} catch (std::runtime_error &ex) {
|
||||
raise (std::string ("std::runtime_error caught: ") + ex.what ());
|
||||
} catch (...) {
|
||||
raise (std::string ("unspecific exception caught: "));
|
||||
}
|
||||
|
||||
m_testtmp.clear ();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue