mirror of https://github.com/KLayout/klayout.git
Enabling multiple bases and child classes for GSI expressions
This commit is contained in:
parent
a0546098b3
commit
ea83b4285d
|
|
@ -106,6 +106,10 @@ public:
|
||||||
std::pair<bool, size_t> find (bool st, const std::string &name) const
|
std::pair<bool, size_t> find (bool st, const std::string &name) const
|
||||||
{
|
{
|
||||||
std::map<std::pair<bool, std::string>, size_t>::const_iterator t = m_name_map.find (std::make_pair (st, name));
|
std::map<std::pair<bool, std::string>, size_t>::const_iterator t = m_name_map.find (std::make_pair (st, name));
|
||||||
|
if (! st && t == m_name_map.end ()) {
|
||||||
|
// can also use static methods for instances
|
||||||
|
t = m_name_map.find (std::make_pair (true, name));
|
||||||
|
}
|
||||||
if (t != m_name_map.end ()) {
|
if (t != m_name_map.end ()) {
|
||||||
return std::make_pair (true, t->second);
|
return std::make_pair (true, t->second);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1088,11 +1092,7 @@ initialize_expressions ()
|
||||||
// skip external classes
|
// skip external classes
|
||||||
continue;
|
continue;
|
||||||
} else if ((*c)->declaration () != *c) {
|
} else if ((*c)->declaration () != *c) {
|
||||||
// we might encounter a child class which is a reference to a top-level class (e.g.
|
|
||||||
// duplication of enums into child classes). In this case we should create a reference inside the
|
|
||||||
// target class.
|
|
||||||
tl_assert ((*c)->parent () != 0); // top-level classes should be merged
|
tl_assert ((*c)->parent () != 0); // top-level classes should be merged
|
||||||
// TODO: implement (see rba.cc:1544 for example)
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1360,6 +1360,65 @@ special_method_impl (gsi::MethodBase::special_method_type smt, tl::Variant &self
|
||||||
return tl::Variant ();
|
return tl::Variant ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::pair<const ExpressionMethodTable *, size_t> find_method (const gsi::ClassBase *cls, bool as_static, const std::string &method)
|
||||||
|
{
|
||||||
|
const ExpressionMethodTable *mt = 0;
|
||||||
|
size_t mid = 0;
|
||||||
|
|
||||||
|
while (cls) {
|
||||||
|
|
||||||
|
mt = ExpressionMethodTable::method_table_by_class (cls);
|
||||||
|
std::pair<bool, size_t> t = mt->find (as_static, method);
|
||||||
|
if (t.first) {
|
||||||
|
mid = t.second;
|
||||||
|
return std::make_pair (mt, mid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// try unnamed child classes as static
|
||||||
|
for (auto cc = cls->begin_child_classes (); cc != cls->end_child_classes (); ++cc) {
|
||||||
|
if (cc->name ().empty ()) {
|
||||||
|
std::pair<const ExpressionMethodTable *, size_t> m = find_method (cc->declaration (), true, method);
|
||||||
|
if (m.first) {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cls = cls->base ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair ((const ExpressionMethodTable *) 0, size_t (0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gsi::ClassBase *find_class_scope (const gsi::ClassBase *cls, const std::string &name)
|
||||||
|
{
|
||||||
|
while (cls) {
|
||||||
|
|
||||||
|
// try named child classes
|
||||||
|
for (auto cc = cls->begin_child_classes (); cc != cls->end_child_classes (); ++cc) {
|
||||||
|
if (cc->name () == name) {
|
||||||
|
return cc->declaration ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try unnamed child classes as additional bases
|
||||||
|
for (auto cc = cls->begin_child_classes (); cc != cls->end_child_classes (); ++cc) {
|
||||||
|
if (cc->name ().empty ()) {
|
||||||
|
const gsi::ClassBase *scope = find_class_scope (cc->declaration (), name);
|
||||||
|
if (scope) {
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cls = cls->base ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context*/, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const
|
VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context*/, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const
|
||||||
{
|
{
|
||||||
|
|
@ -1374,25 +1433,34 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExpressionMethodTable *mt = 0;
|
auto m = find_method (clsact, mp_object_cls != 0 /*static*/, method);
|
||||||
size_t mid = 0;
|
|
||||||
|
|
||||||
const gsi::ClassBase *cls = clsact;
|
|
||||||
while (cls) {
|
|
||||||
|
|
||||||
mt = ExpressionMethodTable::method_table_by_class (cls);
|
const ExpressionMethodTable *mt = m.first;
|
||||||
std::pair<bool, size_t> t = mt->find (mp_object_cls != 0 /*static*/, method);
|
size_t mid = m.second;
|
||||||
if (t.first) {
|
|
||||||
mid = t.second;
|
if (! mt) {
|
||||||
break;
|
|
||||||
|
// try class scope
|
||||||
|
const gsi::ClassBase *scope = find_class_scope (clsact, method);
|
||||||
|
if (scope) {
|
||||||
|
|
||||||
|
if (! args.empty ()) {
|
||||||
|
throw tl::Exception (tl::to_string (tr ("'%s' is not a function and cannot have parameters")), method);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we found a class scope: return a reference to that
|
||||||
|
const tl::VariantUserClassBase *scope_var_cls = scope->var_cls_cls ();
|
||||||
|
if (scope_var_cls) {
|
||||||
|
out = tl::Variant ((void *) 0, scope_var_cls, false);
|
||||||
|
} else {
|
||||||
|
out = tl::Variant ();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw tl::Exception (tl::to_string (tr ("Unknown method '%s' of class '%s'")), method, clsact->name ());
|
||||||
}
|
}
|
||||||
|
|
||||||
cls = cls->base ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cls == 0) {
|
|
||||||
throw tl::Exception (tl::to_string (tr ("Unknown method")) + " '" + method + "' of class '" + clsact->name () + "'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const gsi::MethodBase *meth = 0;
|
const gsi::MethodBase *meth = 0;
|
||||||
|
|
|
||||||
|
|
@ -565,3 +565,27 @@ TEST(9)
|
||||||
EXPECT_EQ (collect_func->values[1], 14400);
|
EXPECT_EQ (collect_func->values[1], 14400);
|
||||||
EXPECT_EQ (collect_func->values[2], 19600);
|
EXPECT_EQ (collect_func->values[2], 19600);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(10)
|
||||||
|
{
|
||||||
|
tl::Eval e;
|
||||||
|
tl::Variant v;
|
||||||
|
|
||||||
|
v = e.parse ("var b3 = B3.new(); b3.E.E3B").execute ();
|
||||||
|
EXPECT_EQ (v.to_string (), std::string ("E3B"));
|
||||||
|
v = e.parse ("B3.E.E3B").execute ();
|
||||||
|
EXPECT_EQ (v.to_string (), std::string ("E3B"));
|
||||||
|
v = e.parse ("var bb = BB.new(); bb.C1").execute ();
|
||||||
|
EXPECT_EQ (v.to_string (), std::string ("42"));
|
||||||
|
v = e.parse ("var bb = BB.new(); bb.C2").execute ();
|
||||||
|
EXPECT_EQ (v.to_string (), std::string ("17"));
|
||||||
|
v = e.parse ("var bb = BB.new(); bb.C3").execute ();
|
||||||
|
EXPECT_EQ (v.to_string (), std::string ("-1"));
|
||||||
|
v = e.parse ("var bb = BB.new(); bb.E.E3A").execute ();
|
||||||
|
EXPECT_EQ (v.to_string (), std::string ("E3A"));
|
||||||
|
v = e.parse ("BB.E.E3C").execute ();
|
||||||
|
EXPECT_EQ (v.to_string (), std::string ("E3C"));
|
||||||
|
v = e.parse ("var bb = BB.new(); bb.d3(BB.E.E3A, BB.E.E3C)").execute ();
|
||||||
|
EXPECT_EQ (v.to_string (), std::string ("2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ TARGET = gsi_tests
|
||||||
include($$PWD/../../lib_ut.pri)
|
include($$PWD/../../lib_ut.pri)
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
gsiExpression.cc \
|
gsiExpressionTests.cc
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue