mirror of https://github.com/KLayout/klayout.git
commit
16ae0346b8
|
|
@ -2427,9 +2427,9 @@ LayoutQuery::dump () const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 ()) {
|
while (! iq.at_end ()) {
|
||||||
++iq;
|
++iq;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -468,8 +468,10 @@ public:
|
||||||
* as "delete" or "with ... do".
|
* as "delete" or "with ... do".
|
||||||
* It is basically equivalent to iterating over the query until it is
|
* It is basically equivalent to iterating over the query until it is
|
||||||
* done.
|
* 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)
|
* @brief A dump method (for debugging)
|
||||||
|
|
|
||||||
|
|
@ -75,8 +75,8 @@ struct LayoutQueryIteratorWrapper
|
||||||
typedef void difference_type;
|
typedef void difference_type;
|
||||||
typedef void pointer;
|
typedef void pointer;
|
||||||
|
|
||||||
LayoutQueryIteratorWrapper (const db::LayoutQuery &q, const db::Layout *layout)
|
LayoutQueryIteratorWrapper (const db::LayoutQuery &q, const db::Layout *layout, tl::Eval *eval)
|
||||||
: mp_iter (new db::LayoutQueryIterator (q, layout))
|
: mp_iter (new db::LayoutQueryIterator (q, layout, eval))
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -100,9 +100,9 @@ private:
|
||||||
tl::shared_ptr<db::LayoutQueryIterator> mp_iter;
|
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)
|
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 "
|
"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"
|
"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"
|
"@brief Executes the query\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method can be used to execute \"active\" queries such\n"
|
"This method can be used to execute \"active\" queries such\n"
|
||||||
"as \"delete\" or \"with ... do\".\n"
|
"as \"delete\" or \"with ... do\".\n"
|
||||||
"It is basically equivalent to iterating over the query until it is\n"
|
"It is basically equivalent to iterating over the query until it is\n"
|
||||||
"done.\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"
|
"@brief Executes the query and delivered the results iteratively.\n"
|
||||||
"The argument to the block is a \\LayoutQueryIterator object which can be "
|
"The argument to the block is a \\LayoutQueryIterator object which can be "
|
||||||
"asked for specific results.\n"
|
"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"
|
"@brief A layout query\n"
|
||||||
"Layout queries are the backbone of the \"Search & replace\" feature. Layout queries allow retrieval of "
|
"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
|
* @brief A convenience wrapper for the expression parser
|
||||||
*/
|
*/
|
||||||
class ExpressionWrapper
|
class ExpressionWrapper
|
||||||
: public tl::Object
|
: public tl::Eval, public gsi::ObjectBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ExpressionWrapper ()
|
ExpressionWrapper ()
|
||||||
: mp_eval (new tl::Eval ())
|
: tl::Eval ()
|
||||||
{
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse (const std::string &e)
|
void parse (const std::string &e)
|
||||||
|
|
@ -457,20 +458,10 @@ public:
|
||||||
mp_expr.reset (0);
|
mp_expr.reset (0);
|
||||||
|
|
||||||
std::auto_ptr<tl::Expression> ex (new tl::Expression ());
|
std::auto_ptr<tl::Expression> ex (new tl::Expression ());
|
||||||
mp_eval->parse (*ex, e);
|
tl::Eval::parse (*ex, e);
|
||||||
mp_expr.reset (ex.release ());
|
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 ()
|
tl::Variant eval ()
|
||||||
{
|
{
|
||||||
if (mp_expr.get ()) {
|
if (mp_expr.get ()) {
|
||||||
|
|
@ -482,24 +473,23 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::auto_ptr<tl::Expression> mp_expr;
|
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;
|
ExpressionWrapper expr;
|
||||||
expr.parse (e);
|
expr.parse (e);
|
||||||
return expr.eval ();
|
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 ());
|
std::auto_ptr<ExpressionWrapper> expr (new ExpressionWrapper ());
|
||||||
expr->parse (e);
|
expr->parse (e);
|
||||||
return expr.release ();
|
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 ());
|
std::auto_ptr<ExpressionWrapper> expr (new ExpressionWrapper ());
|
||||||
for (std::map<std::string, tl::Variant>::const_iterator v = variables.begin (); v != variables.end (); ++v) {
|
for (std::map<std::string, tl::Variant>::const_iterator v = variables.begin (); v != variables.end (); ++v) {
|
||||||
|
|
@ -523,7 +513,25 @@ namespace tl {
|
||||||
namespace gsi
|
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"),
|
gsi::constructor ("new", &new_expr1, gsi::arg ("expr"),
|
||||||
"@brief Creates an expression evaluator\n"
|
"@brief Creates an expression evaluator\n"
|
||||||
) +
|
) +
|
||||||
|
|
@ -534,12 +542,6 @@ Class<ExpressionWrapper> decl_ExpressionWrapper ("tl", "Expression",
|
||||||
gsi::method ("text=", &ExpressionWrapper::parse, gsi::arg ("expr"),
|
gsi::method ("text=", &ExpressionWrapper::parse, gsi::arg ("expr"),
|
||||||
"@brief Sets the given text as the expression."
|
"@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,
|
gsi::method ("eval", &ExpressionWrapper::eval,
|
||||||
"@brief Evaluates the current expression and returns the result\n"
|
"@brief Evaluates the current expression and returns the result\n"
|
||||||
) +
|
) +
|
||||||
|
|
@ -555,10 +557,9 @@ Class<ExpressionWrapper> decl_ExpressionWrapper ("tl", "Expression",
|
||||||
"\n"
|
"\n"
|
||||||
"An expression is 'compiled' into an Expression object and can be evaluated multiple times.\n"
|
"An expression is 'compiled' into an Expression object and can be evaluated multiple times.\n"
|
||||||
"\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)
|
static tl::GlobPattern *new_glob_pattern (const std::string &s)
|
||||||
{
|
{
|
||||||
return new tl::GlobPattern (s);
|
return new tl::GlobPattern (s);
|
||||||
|
|
|
||||||
|
|
@ -3127,7 +3127,7 @@ Expression::execute (EvalTarget &v) const
|
||||||
|
|
||||||
Eval Eval::m_global;
|
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)
|
: mp_parent (parent), m_sloppy (sloppy), mp_ctx_handler (0)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
|
|
@ -3867,14 +3867,14 @@ Eval::eval_atomic (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n
|
||||||
const tl::Variant *value = 0;
|
const tl::Variant *value = 0;
|
||||||
tl::Variant *var = 0;
|
tl::Variant *var = 0;
|
||||||
|
|
||||||
|
if (am == 2) {
|
||||||
resolve_var_name (t, var);
|
resolve_var_name (t, var);
|
||||||
if (! var) {
|
if (! var) {
|
||||||
if (am == 2) {
|
|
||||||
set_var (t, tl::Variant ());
|
set_var (t, tl::Variant ());
|
||||||
resolve_var_name (t, var);
|
resolve_var_name (t, var);
|
||||||
} else {
|
|
||||||
resolve_name (t, function, value);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
resolve_name (t, function, value, var);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (function) {
|
if (function) {
|
||||||
|
|
@ -3935,31 +3935,31 @@ Eval::resolve_var_name (const std::string &t, tl::Variant *&value)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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;
|
function = 0;
|
||||||
value = 0;
|
value = 0;
|
||||||
|
var = 0;
|
||||||
|
|
||||||
std::map <std::string, EvalFunction *>::const_iterator f;
|
std::map <std::string, EvalFunction *>::const_iterator f;
|
||||||
f = m_local_functions.find (t);
|
f = m_local_functions.find (t);
|
||||||
if (f != m_local_functions.end ()) {
|
if (f != m_local_functions.end ()) {
|
||||||
function = f->second;
|
function = f->second;
|
||||||
} else if ((function = EvalStaticFunction::function_by_name (t)) == 0) {
|
} else if ((function = EvalStaticFunction::function_by_name (t)) == 0) {
|
||||||
|
std::map<std::string, tl::Variant>::iterator v;
|
||||||
std::map<std::string, tl::Variant>::const_iterator v;
|
|
||||||
v = m_local_vars.find (t);
|
v = m_local_vars.find (t);
|
||||||
if (v != m_local_vars.end ()) {
|
if (v != m_local_vars.end ()) {
|
||||||
value = &v->second;
|
var = &v->second;
|
||||||
} else {
|
} else {
|
||||||
value = EvalStaticConstant::constant_by_name (t);
|
value = EvalStaticConstant::constant_by_name (t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! function && ! value) {
|
if (! function && ! value && ! var) {
|
||||||
if (mp_parent) {
|
if (mp_parent) {
|
||||||
mp_parent->resolve_name (t, function, value);
|
mp_parent->resolve_name (t, function, value, var);
|
||||||
} else if (this != &m_global) {
|
} 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 parent The parent evaluation context
|
||||||
* @param sloppy True to enable sloppy evaluation for pure parsing
|
* @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.
|
* @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);
|
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
|
* @brief Interpolate the string and return the result
|
||||||
*
|
*
|
||||||
|
|
@ -508,14 +513,13 @@ public:
|
||||||
private:
|
private:
|
||||||
friend class Expression;
|
friend class Expression;
|
||||||
|
|
||||||
const Eval *mp_parent;
|
Eval *mp_parent;
|
||||||
std::map <std::string, tl::Variant> m_local_vars;
|
std::map <std::string, tl::Variant> m_local_vars;
|
||||||
std::map <std::string, EvalFunction *> m_local_functions;
|
std::map <std::string, EvalFunction *> m_local_functions;
|
||||||
bool m_sloppy;
|
bool m_sloppy;
|
||||||
const ContextHandler *mp_ctx_handler;
|
const ContextHandler *mp_ctx_handler;
|
||||||
std::vector<std::string> m_match_substrings;
|
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_top (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v);
|
||||||
void eval_assign (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);
|
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_unary (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v);
|
||||||
void eval_atomic (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v, int am);
|
void eval_atomic (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v, int am);
|
||||||
void eval_suffix (ExpressionParserContext &context, std::auto_ptr<ExpressionNode> &v);
|
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);
|
void resolve_var_name (const std::string &name, tl::Variant *&value);
|
||||||
|
|
||||||
static Eval m_global;
|
static Eval m_global;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,11 @@ class TLTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_1(self):
|
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()
|
expr = pya.Expression()
|
||||||
res = expr.eval()
|
res = expr.eval()
|
||||||
self.assertEqual(str(type(res)).replace("class", "type"), "<type 'NoneType'>")
|
self.assertEqual(str(type(res)).replace("class", "type"), "<type 'NoneType'>")
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,37 @@ class DBLayoutQuery_TestClass < TestBase
|
||||||
|
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
load("test_epilogue.rb")
|
load("test_epilogue.rb")
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,11 @@ class Tl_TestClass < TestBase
|
||||||
# Expression basics
|
# Expression basics
|
||||||
def test_1_Expression
|
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
|
expr = RBA::Expression::new
|
||||||
res = expr.eval
|
res = expr.eval
|
||||||
assert_equal(res.class.to_s, "NilClass")
|
assert_equal(res.class.to_s, "NilClass")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue