mirror of https://github.com/KLayout/klayout.git
Layout queries support diff as placeholder for the current cell
This commit is contained in:
parent
a22f48d87a
commit
efeb2c061b
|
|
@ -2282,7 +2282,7 @@ private:
|
|||
// --------------------------------------------------------------------------------
|
||||
// LayoutQueryIterator implementation
|
||||
|
||||
LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, db::Layout *layout, tl::Eval *parent_eval, tl::AbsoluteProgress *progress)
|
||||
LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, db::Layout *layout, db::Cell *cell, tl::Eval *parent_eval, tl::AbsoluteProgress *progress)
|
||||
: mp_q (const_cast<db::LayoutQuery *> (&q)), mp_layout (layout), m_eval (parent_eval), m_layout_ctx (layout, true /*can modify*/), mp_progress (progress), m_initialized (false)
|
||||
{
|
||||
m_eval.set_ctx_handler (&m_layout_ctx);
|
||||
|
|
@ -2290,13 +2290,16 @@ LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, db::Layout *layo
|
|||
for (unsigned int i = 0; i < mp_q->properties (); ++i) {
|
||||
m_eval.define_function (mp_q->property_name (i), new FilterStateFunction (i, &m_state));
|
||||
}
|
||||
if (cell && cell->layout ()) {
|
||||
m_eval.set_var ("_", cell->layout ()->cell_name (cell->cell_index ()));
|
||||
}
|
||||
|
||||
// Avoid update() calls while iterating in modifying mode
|
||||
mp_layout->update ();
|
||||
mp_layout->start_changes ();
|
||||
}
|
||||
|
||||
LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, const db::Layout *layout, tl::Eval *parent_eval, tl::AbsoluteProgress *progress)
|
||||
LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, const db::Layout *layout, const Cell *cell, tl::Eval *parent_eval, tl::AbsoluteProgress *progress)
|
||||
: mp_q (const_cast<db::LayoutQuery *> (&q)), mp_layout (const_cast <db::Layout *> (layout)), m_eval (parent_eval), m_layout_ctx (layout), mp_progress (progress), m_initialized (false)
|
||||
{
|
||||
// TODO: check whether the query is a modifying one (with .. do, delete)
|
||||
|
|
@ -2306,6 +2309,9 @@ LayoutQueryIterator::LayoutQueryIterator (const LayoutQuery &q, const db::Layout
|
|||
for (unsigned int i = 0; i < mp_q->properties (); ++i) {
|
||||
m_eval.define_function (mp_q->property_name (i), new FilterStateFunction (i, &m_state));
|
||||
}
|
||||
if (cell && cell->layout ()) {
|
||||
m_eval.set_var ("_", cell->layout ()->cell_name (cell->cell_index ()));
|
||||
}
|
||||
|
||||
// Avoid update() calls while iterating in modifying mode
|
||||
mp_layout->start_changes ();
|
||||
|
|
@ -2850,9 +2856,9 @@ LayoutQuery::dump () const
|
|||
}
|
||||
|
||||
void
|
||||
LayoutQuery::execute (db::Layout &layout, tl::Eval *context)
|
||||
LayoutQuery::execute (db::Layout &layout, db::Cell *cell, tl::Eval *context)
|
||||
{
|
||||
LayoutQueryIterator iq (*this, &layout, context);
|
||||
LayoutQueryIterator iq (*this, &layout, cell, context);
|
||||
while (! iq.at_end ()) {
|
||||
++iq;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -536,7 +536,7 @@ public:
|
|||
*
|
||||
* The context provides a way to define variables and functions.
|
||||
*/
|
||||
void execute (db::Layout &layout, tl::Eval *context = 0);
|
||||
void execute (db::Layout &layout, db::Cell *cell = 0, tl::Eval *context = 0);
|
||||
|
||||
/**
|
||||
* @brief A dump method (for debugging)
|
||||
|
|
@ -578,7 +578,7 @@ public:
|
|||
* @param q The query that this iterator walks over
|
||||
* @param layout The layout to which the query is applied
|
||||
*/
|
||||
LayoutQueryIterator (const LayoutQuery &q, db::Layout *layout, tl::Eval *parent_eval = 0, tl::AbsoluteProgress *progress = 0);
|
||||
LayoutQueryIterator (const LayoutQuery &q, db::Layout *layout, db::Cell *cell = 0, tl::Eval *parent_eval = 0, tl::AbsoluteProgress *progress = 0);
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
|
|
@ -586,7 +586,7 @@ public:
|
|||
* @param q The query that this iterator walks over
|
||||
* @param layout The layout to which the query is applied
|
||||
*/
|
||||
LayoutQueryIterator (const LayoutQuery &q, const db::Layout *layout, tl::Eval *parent_eval = 0, tl::AbsoluteProgress *progress = 0);
|
||||
LayoutQueryIterator (const LayoutQuery &q, const db::Layout *layout, const db::Cell *cell = 0, tl::Eval *parent_eval = 0, tl::AbsoluteProgress *progress = 0);
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ struct LayoutQueryIteratorWrapper
|
|||
typedef void difference_type;
|
||||
typedef void pointer;
|
||||
|
||||
LayoutQueryIteratorWrapper (const db::LayoutQuery &q, const db::Layout *layout, tl::Eval *eval)
|
||||
: mp_iter (new db::LayoutQueryIterator (q, layout, eval))
|
||||
LayoutQueryIteratorWrapper (const db::LayoutQuery &q, const db::Layout *layout, const db::Cell *cell, tl::Eval *eval)
|
||||
: mp_iter (new db::LayoutQueryIterator (q, layout, cell, eval))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -77,9 +77,14 @@ private:
|
|||
tl::shared_ptr<db::LayoutQueryIterator> mp_iter;
|
||||
};
|
||||
|
||||
static LayoutQueryIteratorWrapper iterate (const db::LayoutQuery *q, const db::Layout *layout, tl::Eval *eval)
|
||||
static LayoutQueryIteratorWrapper iterate1 (const db::LayoutQuery *q, const db::Layout *layout, tl::Eval *eval)
|
||||
{
|
||||
return LayoutQueryIteratorWrapper (*q, layout, eval);
|
||||
return LayoutQueryIteratorWrapper (*q, layout, 0, eval);
|
||||
}
|
||||
|
||||
static LayoutQueryIteratorWrapper iterate2 (const db::LayoutQuery *q, const db::Layout *layout, const db::Cell *cell, tl::Eval *eval)
|
||||
{
|
||||
return LayoutQueryIteratorWrapper (*q, layout, cell, eval);
|
||||
}
|
||||
|
||||
static tl::Variant iter_get (db::LayoutQueryIterator *iter, const std::string &name)
|
||||
|
|
@ -158,6 +163,16 @@ Class<db::LayoutQueryIterator> decl_LayoutQueryIterator ("db", "LayoutQueryItera
|
|||
"The LayoutQueryIterator class has been introduced in version 0.25."
|
||||
);
|
||||
|
||||
static void execute1 (db::LayoutQuery *q, db::Layout &layout, tl::Eval *context)
|
||||
{
|
||||
q->execute (layout, 0, context);
|
||||
}
|
||||
|
||||
static void execute2 (db::LayoutQuery *q, db::Layout &layout, db::Cell *cell, tl::Eval *context)
|
||||
{
|
||||
q->execute (layout, cell, context);
|
||||
}
|
||||
|
||||
Class<db::LayoutQuery> decl_LayoutQuery ("db", "LayoutQuery",
|
||||
gsi::constructor ("new", &new_query, gsi::arg ("query"),
|
||||
"@brief Creates a new query object from the given query string\n"
|
||||
|
|
@ -168,7 +183,7 @@ Class<db::LayoutQuery> decl_LayoutQuery ("db", "LayoutQuery",
|
|||
"This method allows detection of the properties available. Within the query, all of these "
|
||||
"properties can be obtained from the query iterator using \\LayoutQueryIterator#get.\n"
|
||||
) +
|
||||
gsi::method ("execute", &db::LayoutQuery::execute, gsi::arg("layout"), gsi::arg ("context", (tl::Eval *) 0, "nil"),
|
||||
gsi::method_ext ("execute", &execute1, gsi::arg("layout"), gsi::arg ("context", (tl::Eval *) 0, "nil"),
|
||||
"@brief Executes the query\n"
|
||||
"\n"
|
||||
"This method can be used to execute \"active\" queries such\n"
|
||||
|
|
@ -179,13 +194,27 @@ Class<db::LayoutQuery> decl_LayoutQuery ("db", "LayoutQuery",
|
|||
"The context argument allows supplying an expression execution context. This context can be used for "
|
||||
"example to supply variables for the execution. It has been added in version 0.26.\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each", &iterate, gsi::arg ("layout"), gsi::arg ("context", (tl::Eval *) 0, "nil"),
|
||||
gsi::method_ext ("execute", &execute2, gsi::arg("layout"), gsi::arg("cell"), gsi::arg ("context", (tl::Eval *) 0, "nil"),
|
||||
"@brief Executes the query\n"
|
||||
"\n"
|
||||
"This version allows specifying a context cell. This cell can be used as a default cell for cell expressions.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.30."
|
||||
) +
|
||||
gsi::iterator_ext ("each", &iterate1, gsi::arg ("layout"), gsi::arg ("context", (tl::Eval *) 0, "nil"),
|
||||
"@brief Executes the query and delivered the results iteratively.\n"
|
||||
"The argument to the block is a \\LayoutQueryIterator object which can be "
|
||||
"asked for specific results.\n"
|
||||
"\n"
|
||||
"The context argument allows supplying an expression execution context. This context can be used for "
|
||||
"example to supply variables for the execution. It has been added in version 0.26.\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each", &iterate2, gsi::arg ("layout"), gsi::arg("cell"), gsi::arg ("context", (tl::Eval *) 0, "nil"),
|
||||
"@brief Executes the query and delivered the results iteratively.\n"
|
||||
"\n"
|
||||
"This version allows specifying a context cell. This cell can be used as a default cell for cell expressions.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.30."
|
||||
),
|
||||
"@brief A layout query\n"
|
||||
"Layout queries are the backbone of the \"Search & replace\" feature. Layout queries allow retrieval of "
|
||||
|
|
|
|||
|
|
@ -515,6 +515,14 @@ TEST(1)
|
|||
EXPECT_EQ (s, "c1,c4,c5x");
|
||||
}
|
||||
|
||||
{
|
||||
// $_ is a placeholder for the current cell
|
||||
db::LayoutQuery q ("$_.*");
|
||||
db::LayoutQueryIterator iq (q, &g, &g.cell (g.cell_by_name ("c4").second));
|
||||
std::string s = q2s_var (iq, "cell_name");
|
||||
EXPECT_EQ (s, "c1,c3"); // child cells of "c4"
|
||||
}
|
||||
|
||||
{
|
||||
// Another way of saying "c2x.*"
|
||||
db::LayoutQuery q ("*.$(cell_name=='c2x'?'*':'')");
|
||||
|
|
|
|||
|
|
@ -281,6 +281,14 @@ select cell_name of cells TOP.. sorted by cell_name unique
|
|||
cells *.$("A"+cell_name)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The "$_" placeholder is the name of the cell selected in the view as the current cell.
|
||||
The following selects all child cells of the current cell:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
cells $_.*
|
||||
</pre>
|
||||
|
||||
<h2>Building queries: instances</h2>
|
||||
|
||||
|
|
|
|||
|
|
@ -1136,7 +1136,7 @@ BEGIN_PROTECTED
|
|||
progress.set_unit (100000);
|
||||
progress.set_format ("Processing ..");
|
||||
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), 0, &progress);
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), cv.cell (), 0, &progress);
|
||||
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::log << tl::to_string (QObject::tr ("Running query: ")) << m_last_query;
|
||||
|
|
@ -1198,7 +1198,7 @@ BEGIN_PROTECTED
|
|||
progress.set_unit (100000);
|
||||
progress.set_format ("Processing ..");
|
||||
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), 0, &progress);
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), cv.cell (), 0, &progress);
|
||||
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::log << tl::to_string (QObject::tr ("Running query: ")) << m_last_query;
|
||||
|
|
@ -1246,7 +1246,7 @@ BEGIN_PROTECTED
|
|||
progress.set_unit (100000);
|
||||
progress.set_format ("Processing ..");
|
||||
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), 0, &progress);
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), cv.cell (), 0, &progress);
|
||||
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::log << tl::to_string (QObject::tr ("Running query: ")) << m_last_query;
|
||||
|
|
@ -1317,7 +1317,7 @@ BEGIN_PROTECTED
|
|||
progress.set_unit (100000);
|
||||
progress.set_format ("Processing ..");
|
||||
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), 0, &progress);
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), cv.cell (), 0, &progress);
|
||||
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::log << tl::to_string (QObject::tr ("Running query: ")) << m_last_query;
|
||||
|
|
@ -1371,7 +1371,7 @@ BEGIN_PROTECTED
|
|||
progress.set_unit (100000);
|
||||
progress.set_format ("Processing ..");
|
||||
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), 0, &progress);
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), cv.cell (), 0, &progress);
|
||||
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::log << tl::to_string (QObject::tr ("Running query: ")) << m_last_query;
|
||||
|
|
@ -1668,7 +1668,7 @@ SearchReplaceDialog::issue_query (const std::string &q, const std::set<size_t> *
|
|||
progress.set_unit (100000);
|
||||
progress.set_format ("Processing ..");
|
||||
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), 0, &progress);
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), cv.cell (), 0, &progress);
|
||||
while (! iq.at_end ()) {
|
||||
++iq;
|
||||
}
|
||||
|
|
@ -1690,7 +1690,7 @@ SearchReplaceDialog::issue_query (const std::string &q, const std::set<size_t> *
|
|||
progress.set_format ("Processing ..");
|
||||
|
||||
size_t n = 0;
|
||||
for (db::LayoutQueryIterator iq (lq, &cv->layout (), 0, &progress); ! iq.at_end (); ++n) {
|
||||
for (db::LayoutQueryIterator iq (lq, &cv->layout (), cv.cell (), 0, &progress); ! iq.at_end (); ++n) {
|
||||
iq.next (selected_items->find (n) == selected_items->end ());
|
||||
}
|
||||
|
||||
|
|
@ -1767,7 +1767,7 @@ SearchReplaceDialog::update_results (const std::string &q)
|
|||
progress.set_unit (100000);
|
||||
progress.set_format ("Processing ..");
|
||||
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), 0, &progress);
|
||||
db::LayoutQueryIterator iq (lq, &cv->layout (), cv.cell (), 0, &progress);
|
||||
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::log << tl::to_string (QObject::tr ("Running query: ")) << q;
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ StatisticsTemplateProcessor::process (const QDomElement &element, tl::Eval &eval
|
|||
|
||||
db::LayoutQuery q (tl::to_string (element.attribute (template_name_expr, template_value_empty_query)));
|
||||
|
||||
db::LayoutQueryIterator qi (q, mp_layout, &eval);
|
||||
db::LayoutQueryIterator qi (q, mp_layout, 0, &eval);
|
||||
|
||||
process_child_nodes (begin_node, qi.eval (), writer);
|
||||
|
||||
|
|
|
|||
|
|
@ -3692,10 +3692,41 @@ scan_angle_bracket (tl::Extractor &ex, const char *term, std::string &s)
|
|||
ex.expect (term);
|
||||
}
|
||||
|
||||
static bool
|
||||
get_match_group (tl::Extractor &ex, int &group)
|
||||
{
|
||||
tl::Extractor ex1 = ex;
|
||||
group = 0;
|
||||
if (ex1.test ("$") && isdigit (*ex1)) {
|
||||
ex1.read (group);
|
||||
ex = ex1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
get_variable_name (tl::Extractor &ex, std::string &name)
|
||||
{
|
||||
tl::Extractor ex1 = ex;
|
||||
if (ex1.try_read_word (name, "_")) {
|
||||
ex = ex1;
|
||||
return true;
|
||||
} else if (ex1.test ("$")) {
|
||||
name = "$";
|
||||
ex = ex1;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Eval::eval_atomic (ExpressionParserContext &ex, std::unique_ptr<ExpressionNode> &n, int am)
|
||||
{
|
||||
double g = 0.0;
|
||||
int match_group = 0;
|
||||
std::string t;
|
||||
|
||||
ExpressionParserContext ex1 = ex;
|
||||
|
|
@ -3792,12 +3823,10 @@ Eval::eval_atomic (ExpressionParserContext &ex, std::unique_ptr<ExpressionNode>
|
|||
|
||||
}
|
||||
|
||||
} else if (ex.test ("$")) {
|
||||
} else if (get_match_group (ex, match_group)) {
|
||||
|
||||
// match substring
|
||||
int i = 0;
|
||||
ex.read (i);
|
||||
n.reset (new MatchSubstringReferenceNode (ex1, this, i - 1));
|
||||
n.reset (new MatchSubstringReferenceNode (ex1, this, match_group - 1));
|
||||
|
||||
} else if (ex.test ("{")) {
|
||||
|
||||
|
|
@ -3934,12 +3963,7 @@ Eval::eval_atomic (ExpressionParserContext &ex, std::unique_ptr<ExpressionNode>
|
|||
|
||||
n.reset (new ConstantExpressionNode (ex1, tl::Variant (t)));
|
||||
|
||||
} else if (ex.try_read_word (t, "_")) {
|
||||
|
||||
ExpressionParserContext ex2 = ex;
|
||||
|
||||
// for a function: collect the parameter or check if it's an assignment
|
||||
std::vector <tl::Variant> vv;
|
||||
} else if (get_variable_name (ex, t)) {
|
||||
|
||||
const EvalFunction *function = 0;
|
||||
const tl::Variant *value = 0;
|
||||
|
|
|
|||
|
|
@ -1084,9 +1084,14 @@ TEST(13)
|
|||
tl::Eval e, ee;
|
||||
e.set_var ("L", tl::Variant((long) 89));
|
||||
ee.set_var ("L", tl::Variant((long) 123));
|
||||
ee.set_var ("$", tl::Variant("dollar"));
|
||||
ee.set_var ("_", tl::Variant("underscore"));
|
||||
|
||||
EXPECT_EQ (e.interpolate("A$L B$(L+100)C"), std::string ("A89 B189C"));
|
||||
EXPECT_EQ (ee.interpolate("123*11=$(L*11)."), std::string ("123*11=1353."));
|
||||
EXPECT_EQ (e.interpolate ("A$L B$(L+100)C"), std::string ("A89 B189C"));
|
||||
EXPECT_EQ (ee.interpolate ("123*11=$(L*11)."), std::string ("123*11=1353."));
|
||||
EXPECT_EQ (ee.interpolate ("A$$C"), std::string ("A$C"));
|
||||
EXPECT_EQ (ee.interpolate ("A$_ C"), std::string ("Aunderscore C"));
|
||||
EXPECT_EQ (ee.interpolate ("A$($)C"), std::string ("AdollarC"));
|
||||
}
|
||||
|
||||
// assignment
|
||||
|
|
|
|||
Loading…
Reference in New Issue