mirror of https://github.com/KLayout/klayout.git
commit
16ae0346b8
|
|
@ -2427,9 +2427,9 @@ LayoutQuery::dump () const
|
|||
}
|
||||
|
||||
void
|
||||
LayoutQuery::execute (db::Layout &layout)
|
||||
LayoutQuery::execute (db::Layout &layout, tl::Eval *context)
|
||||
{
|
||||
LayoutQueryIterator iq (*this, &layout);
|
||||
LayoutQueryIterator iq (*this, &layout, context);
|
||||
while (! iq.at_end ()) {
|
||||
++iq;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -468,8 +468,10 @@ public:
|
|||
* as "delete" or "with ... do".
|
||||
* It is basically equivalent to iterating over the query until it is
|
||||
* done.
|
||||
*
|
||||
* The context provides a way to define variables and functions.
|
||||
*/
|
||||
void execute (db::Layout &layout);
|
||||
void execute (db::Layout &layout, tl::Eval *context = 0);
|
||||
|
||||
/**
|
||||
* @brief A dump method (for debugging)
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ struct LayoutQueryIteratorWrapper
|
|||
typedef void difference_type;
|
||||
typedef void pointer;
|
||||
|
||||
LayoutQueryIteratorWrapper (const db::LayoutQuery &q, const db::Layout *layout)
|
||||
: mp_iter (new db::LayoutQueryIterator (q, layout))
|
||||
LayoutQueryIteratorWrapper (const db::LayoutQuery &q, const db::Layout *layout, tl::Eval *eval)
|
||||
: mp_iter (new db::LayoutQueryIterator (q, layout, eval))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -100,9 +100,9 @@ private:
|
|||
tl::shared_ptr<db::LayoutQueryIterator> mp_iter;
|
||||
};
|
||||
|
||||
static LayoutQueryIteratorWrapper iterate (const db::LayoutQuery *q, const db::Layout *layout)
|
||||
static LayoutQueryIteratorWrapper iterate (const db::LayoutQuery *q, const db::Layout *layout, tl::Eval *eval)
|
||||
{
|
||||
return LayoutQueryIteratorWrapper (*q, layout);
|
||||
return LayoutQueryIteratorWrapper (*q, layout, eval);
|
||||
}
|
||||
|
||||
static tl::Variant iter_get (db::LayoutQueryIterator *iter, const std::string &name)
|
||||
|
|
@ -187,18 +187,24 @@ 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::method ("execute", &db::LayoutQuery::execute, 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"
|
||||
"as \"delete\" or \"with ... do\".\n"
|
||||
"It is basically equivalent to iterating over the query until it is\n"
|
||||
"done.\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", &iterate, gsi::arg ("layout"),
|
||||
gsi::iterator_ext ("each", &iterate, 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"
|
||||
),
|
||||
"@brief A layout query\n"
|
||||
"Layout queries are the backbone of the \"Search & replace\" feature. Layout queries allow retrieval of "
|
||||
|
|
|
|||
|
|
@ -444,12 +444,13 @@ namespace
|
|||
* @brief A convenience wrapper for the expression parser
|
||||
*/
|
||||
class ExpressionWrapper
|
||||
: public tl::Object
|
||||
: public tl::Eval, public gsi::ObjectBase
|
||||
{
|
||||
public:
|
||||
ExpressionWrapper ()
|
||||
: mp_eval (new tl::Eval ())
|
||||
: tl::Eval ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void parse (const std::string &e)
|
||||
|
|
@ -457,20 +458,10 @@ public:
|
|||
mp_expr.reset (0);
|
||||
|
||||
std::auto_ptr<tl::Expression> ex (new tl::Expression ());
|
||||
mp_eval->parse (*ex, e);
|
||||
tl::Eval::parse (*ex, e);
|
||||
mp_expr.reset (ex.release ());
|
||||
}
|
||||
|
||||
void set_var (const std::string &name, const tl::Variant &value)
|
||||
{
|
||||
mp_eval->set_var (name, value);
|
||||
}
|
||||
|
||||
static void set_global_var (const std::string &name, const tl::Variant &value)
|
||||
{
|
||||
tl::Eval::set_global_var (name, value);
|
||||
}
|
||||
|
||||
tl::Variant eval ()
|
||||
{
|
||||
if (mp_expr.get ()) {
|
||||
|
|
@ -482,24 +473,23 @@ public:
|
|||
|
||||
private:
|
||||
std::auto_ptr<tl::Expression> mp_expr;
|
||||
std::auto_ptr<tl::Eval> mp_eval;
|
||||
};
|
||||
|
||||
tl::Variant eval_expr (const std::string &e)
|
||||
static tl::Variant eval_expr (const std::string &e)
|
||||
{
|
||||
ExpressionWrapper expr;
|
||||
expr.parse (e);
|
||||
return expr.eval ();
|
||||
}
|
||||
|
||||
ExpressionWrapper *new_expr1 (const std::string &e)
|
||||
static ExpressionWrapper *new_expr1 (const std::string &e)
|
||||
{
|
||||
std::auto_ptr<ExpressionWrapper> expr (new ExpressionWrapper ());
|
||||
expr->parse (e);
|
||||
return expr.release ();
|
||||
}
|
||||
|
||||
ExpressionWrapper *new_expr2 (const std::string &e, const std::map<std::string, tl::Variant> &variables)
|
||||
static ExpressionWrapper *new_expr2 (const std::string &e, const std::map<std::string, tl::Variant> &variables)
|
||||
{
|
||||
std::auto_ptr<ExpressionWrapper> expr (new ExpressionWrapper ());
|
||||
for (std::map<std::string, tl::Variant>::const_iterator v = variables.begin (); v != variables.end (); ++v) {
|
||||
|
|
@ -523,7 +513,25 @@ namespace tl {
|
|||
namespace gsi
|
||||
{
|
||||
|
||||
Class<ExpressionWrapper> decl_ExpressionWrapper ("tl", "Expression",
|
||||
Class<tl::Eval> decl_ExpressionContext ("tl", "ExpressionContext",
|
||||
gsi::method ("var", &tl::Eval::set_var, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Defines a variable with the given name and value\n"
|
||||
) +
|
||||
gsi::method ("global_var", &tl::Eval::set_global_var, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Defines a global variable with the given name and value\n"
|
||||
) +
|
||||
gsi::method ("eval", &tl::Eval::eval, gsi::arg ("expr"),
|
||||
"@brief Compiles and evaluates the given expression in this context\n"
|
||||
"This method has been introduced in version 0.26."
|
||||
),
|
||||
"@brief Represents the context of an expression evaluation\n"
|
||||
"\n"
|
||||
"The context provides a variable namespace for the expression evaluation.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.26 when \\Expression was separated into the execution and context part.\n"
|
||||
);
|
||||
|
||||
Class<ExpressionWrapper> decl_ExpressionWrapper (decl_ExpressionContext, "tl", "Expression",
|
||||
gsi::constructor ("new", &new_expr1, gsi::arg ("expr"),
|
||||
"@brief Creates an expression evaluator\n"
|
||||
) +
|
||||
|
|
@ -534,12 +542,6 @@ Class<ExpressionWrapper> decl_ExpressionWrapper ("tl", "Expression",
|
|||
gsi::method ("text=", &ExpressionWrapper::parse, gsi::arg ("expr"),
|
||||
"@brief Sets the given text as the expression."
|
||||
) +
|
||||
gsi::method ("var", &ExpressionWrapper::set_var, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Defines a variable with the given name and value\n"
|
||||
) +
|
||||
gsi::method ("global_var", &ExpressionWrapper::set_global_var, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Defines a global variable with the given name and value\n"
|
||||
) +
|
||||
gsi::method ("eval", &ExpressionWrapper::eval,
|
||||
"@brief Evaluates the current expression and returns the result\n"
|
||||
) +
|
||||
|
|
@ -555,10 +557,9 @@ Class<ExpressionWrapper> decl_ExpressionWrapper ("tl", "Expression",
|
|||
"\n"
|
||||
"An expression is 'compiled' into an Expression object and can be evaluated multiple times.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.25.\n"
|
||||
"This class has been introduced in version 0.25. In version 0.26 it was separated into execution and context.\n"
|
||||
);
|
||||
|
||||
|
||||
static tl::GlobPattern *new_glob_pattern (const std::string &s)
|
||||
{
|
||||
return new tl::GlobPattern (s);
|
||||
|
|
|
|||
|
|
@ -3127,7 +3127,7 @@ Expression::execute (EvalTarget &v) const
|
|||
|
||||
Eval Eval::m_global;
|
||||
|
||||
Eval::Eval (const Eval *parent, bool sloppy)
|
||||
Eval::Eval (Eval *parent, bool sloppy)
|
||||
: mp_parent (parent), m_sloppy (sloppy), mp_ctx_handler (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -3867,14 +3867,14 @@ Eval::eval_atomic (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n
|
|||
const tl::Variant *value = 0;
|
||||
tl::Variant *var = 0;
|
||||
|
||||
resolve_var_name (t, var);
|
||||
if (! var) {
|
||||
if (am == 2) {
|
||||
if (am == 2) {
|
||||
resolve_var_name (t, var);
|
||||
if (! var) {
|
||||
set_var (t, tl::Variant ());
|
||||
resolve_var_name (t, var);
|
||||
} else {
|
||||
resolve_name (t, function, value);
|
||||
}
|
||||
} else {
|
||||
resolve_name (t, function, value, var);
|
||||
}
|
||||
|
||||
if (function) {
|
||||
|
|
@ -3935,31 +3935,31 @@ Eval::resolve_var_name (const std::string &t, tl::Variant *&value)
|
|||
}
|
||||
|
||||
void
|
||||
Eval::resolve_name (const std::string &t, const EvalFunction *&function, const tl::Variant *&value) const
|
||||
Eval::resolve_name (const std::string &t, const EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var)
|
||||
{
|
||||
function = 0;
|
||||
value = 0;
|
||||
var = 0;
|
||||
|
||||
std::map <std::string, EvalFunction *>::const_iterator f;
|
||||
f = m_local_functions.find (t);
|
||||
if (f != m_local_functions.end ()) {
|
||||
function = f->second;
|
||||
} else if ((function = EvalStaticFunction::function_by_name (t)) == 0) {
|
||||
|
||||
std::map<std::string, tl::Variant>::const_iterator v;
|
||||
std::map<std::string, tl::Variant>::iterator v;
|
||||
v = m_local_vars.find (t);
|
||||
if (v != m_local_vars.end ()) {
|
||||
value = &v->second;
|
||||
var = &v->second;
|
||||
} else {
|
||||
value = EvalStaticConstant::constant_by_name (t);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function && ! value) {
|
||||
if (! function && ! value && ! var) {
|
||||
if (mp_parent) {
|
||||
mp_parent->resolve_name (t, function, value);
|
||||
mp_parent->resolve_name (t, function, value, var);
|
||||
} else if (this != &m_global) {
|
||||
m_global.resolve_name (t, function, value);
|
||||
m_global.resolve_name (t, function, value, var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ public:
|
|||
* @param parent The parent evaluation context
|
||||
* @param sloppy True to enable sloppy evaluation for pure parsing
|
||||
*/
|
||||
Eval (const Eval *parent = 0, bool sloppy = false);
|
||||
Eval (Eval *parent = 0, bool sloppy = false);
|
||||
|
||||
/**
|
||||
* @brief virtual dtor to enable dynamic_cast on derived classes.
|
||||
|
|
@ -481,6 +481,11 @@ public:
|
|||
*/
|
||||
static std::string parse_expr (tl::Extractor &ex, bool top = true);
|
||||
|
||||
/**
|
||||
* @brief A convenience method to evaluate an expression (by string) in this context
|
||||
*/
|
||||
tl::Variant eval (const std::string &expr);
|
||||
|
||||
/**
|
||||
* @brief Interpolate the string and return the result
|
||||
*
|
||||
|
|
@ -508,14 +513,13 @@ public:
|
|||
private:
|
||||
friend class Expression;
|
||||
|
||||
const Eval *mp_parent;
|
||||
Eval *mp_parent;
|
||||
std::map <std::string, tl::Variant> m_local_vars;
|
||||
std::map <std::string, EvalFunction *> m_local_functions;
|
||||
bool m_sloppy;
|
||||
const ContextHandler *mp_ctx_handler;
|
||||
std::vector<std::string> m_match_substrings;
|
||||
|
||||
tl::Variant eval (const std::string &expr);
|
||||
void eval_top (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v);
|
||||
void eval_assign (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v);
|
||||
void eval_if (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v);
|
||||
|
|
@ -528,7 +532,7 @@ private:
|
|||
void eval_unary (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v);
|
||||
void eval_atomic (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v, int am);
|
||||
void eval_suffix (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v);
|
||||
void resolve_name (const std::string &name, const EvalFunction *&function, const tl::Variant *&value) const;
|
||||
void resolve_name (const std::string &name, const EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var);
|
||||
void resolve_var_name (const std::string &name, tl::Variant *&value);
|
||||
|
||||
static Eval m_global;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@ class TLTest(unittest.TestCase):
|
|||
|
||||
def test_1(self):
|
||||
|
||||
ctx = pya.ExpressionContext()
|
||||
self.assertEqual(ctx.eval("1+2"), 3)
|
||||
ctx.var("a", 21)
|
||||
self.assertEqual(ctx.eval("2*a"), 42)
|
||||
|
||||
expr = pya.Expression()
|
||||
res = expr.eval()
|
||||
self.assertEqual(str(type(res)).replace("class", "type"), "<type 'NoneType'>")
|
||||
|
|
|
|||
|
|
@ -68,6 +68,37 @@ class DBLayoutQuery_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# variables
|
||||
def test_4
|
||||
|
||||
ly = RBA::Layout::new
|
||||
ly.read(ENV["TESTSRC"] + "/testdata/gds/t11.gds")
|
||||
|
||||
ctx = RBA::ExpressionContext::new
|
||||
ctx.var("suffix", "!")
|
||||
ctx.var("all", [])
|
||||
ctx.var("nonmod", "")
|
||||
|
||||
q = RBA::LayoutQuery::new("select cell.name + suffix from *")
|
||||
res = []
|
||||
q.each(ly, ctx) do |iter|
|
||||
res << iter.data.inspect
|
||||
end
|
||||
|
||||
assert_equal(res.size, 2)
|
||||
assert_equal(res[0], "[\"TOPTOP!\"]")
|
||||
assert_equal(res[1], "[\"TOP!\"]")
|
||||
|
||||
q = RBA::LayoutQuery::new("with * do var nonmod = cell.name; all.push(nonmod)")
|
||||
q.execute(ly, ctx)
|
||||
|
||||
assert_equal(ctx.eval("all").join(","), "TOPTOP,TOP")
|
||||
# not modified, because we used "var nonmod" in the query which
|
||||
# creates a local variable:
|
||||
assert_equal(ctx.eval("nonmod"), "")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@ class Tl_TestClass < TestBase
|
|||
# Expression basics
|
||||
def test_1_Expression
|
||||
|
||||
ctx = RBA::ExpressionContext::new
|
||||
assert_equal(ctx.eval("1+2"), 3)
|
||||
ctx.var("a", 21)
|
||||
assert_equal(ctx.eval("2*a"), 42)
|
||||
|
||||
expr = RBA::Expression::new
|
||||
res = expr.eval
|
||||
assert_equal(res.class.to_s, "NilClass")
|
||||
|
|
|
|||
Loading…
Reference in New Issue