mirror of https://github.com/KLayout/klayout.git
WIP
This commit is contained in:
parent
a0758aa493
commit
85696e2bc2
|
|
@ -437,7 +437,7 @@ public:
|
|||
throw tl::EvalError (tl::to_string (tr ("Annotation function must not have arguments")), context);
|
||||
}
|
||||
|
||||
const Object &obj = mp_eval->obj ();
|
||||
const ant::Object &obj = mp_eval->obj ();
|
||||
const db::DFTrans &trans = mp_eval->trans ();
|
||||
|
||||
if (m_function == 'L') {
|
||||
|
|
@ -471,18 +471,18 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
db::DPoint p1 (const Object &obj) const
|
||||
db::DPoint p1 (const ant::Object &obj) const
|
||||
{
|
||||
return obj.seg_p1 (m_index);
|
||||
}
|
||||
|
||||
db::DPoint p2 (const Object &obj) const
|
||||
db::DPoint p2 (const ant::Object &obj) const
|
||||
{
|
||||
return obj.seg_p2 (m_index);
|
||||
}
|
||||
|
||||
double
|
||||
delta_x (const Object &obj, const db::DFTrans &t) const
|
||||
delta_x (const ant::Object &obj, const db::DFTrans &t) const
|
||||
{
|
||||
double dx = ((t * p2 (obj)).x () - (t * p1 (obj)).x ());
|
||||
|
||||
|
|
@ -495,7 +495,7 @@ public:
|
|||
}
|
||||
|
||||
double
|
||||
delta_y (const Object &obj, const db::DFTrans &t) const
|
||||
delta_y (const ant::Object &obj, const db::DFTrans &t) const
|
||||
{
|
||||
double dy = ((t * p2 (obj)).y () - (t * p1 (obj)).y ());
|
||||
|
||||
|
|
|
|||
|
|
@ -590,6 +590,12 @@ static void def_func (tl::Eval *eval, const std::string &name, FunctionBody *fun
|
|||
eval->define_function (name, func);
|
||||
}
|
||||
|
||||
static void def_global_func (const std::string &name, FunctionBody *func)
|
||||
{
|
||||
func->keep ();
|
||||
tl::Eval::define_global_function (name, func);
|
||||
}
|
||||
|
||||
Class<FunctionBody> decl_FunctionBody ("tl", "FunctionBody",
|
||||
gsi::method ("with_kwargs=", &FunctionBody::set_with_kwargs, gsi::arg ("f"),
|
||||
"@brief Sets a value indicating whether this function accepts keyword arguments.\n"
|
||||
|
|
@ -625,12 +631,115 @@ Class<FunctionBody> decl_FunctionBody ("tl", "FunctionBody",
|
|||
"This class has been introduced in version 0.29.6."
|
||||
);
|
||||
|
||||
tl::Eval *new_expr_ctx0 ()
|
||||
{
|
||||
return new tl::Eval ();
|
||||
}
|
||||
|
||||
tl::Eval *new_expr_ctx1 (tl::Eval *parent)
|
||||
{
|
||||
return new tl::Eval (parent);
|
||||
}
|
||||
|
||||
tl::Eval *new_expr_ctx2 (tl::Eval *global, tl::Eval *parent)
|
||||
{
|
||||
return new tl::Eval (global, parent);
|
||||
}
|
||||
|
||||
void import3 (tl::Eval *eval, tl::Eval *from, const std::string &name)
|
||||
{
|
||||
tl::Variant *var = from->var (name);
|
||||
if (var) {
|
||||
eval->set_var (name, *var);
|
||||
} else {
|
||||
tl::EvalFunction *func = from->function (name);
|
||||
if (func) {
|
||||
eval->define_function (name, func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void import4 (tl::Eval *eval, tl::Eval *from, const std::vector<std::string> &names)
|
||||
{
|
||||
for (auto i = names.begin (); i != names.end (); ++i) {
|
||||
import3 (eval, from, *i);
|
||||
}
|
||||
}
|
||||
|
||||
void import1 (tl::Eval *eval, const std::string &name)
|
||||
{
|
||||
import3 (eval, &tl::Eval::global_context (), name);
|
||||
}
|
||||
|
||||
void import2 (tl::Eval *eval, const std::vector<std::string> &names)
|
||||
{
|
||||
import4 (eval, &tl::Eval::global_context (), names);
|
||||
}
|
||||
|
||||
Class<tl::Eval> decl_ExpressionContext ("tl", "ExpressionContext",
|
||||
gsi::constructor ("new", &new_expr_ctx0,
|
||||
"@brief Creates a new expression context\n"
|
||||
"The expression context acts as a namespace for variables and functions. "
|
||||
"This version of the context is connected to the global, singleton context. "
|
||||
"There are other constructors available for creating expression contexts with "
|
||||
"a parent context or connected to another global context.\n"
|
||||
) +
|
||||
gsi::constructor ("new", &new_expr_ctx1, gsi::arg ("parent"),
|
||||
"@brief Creates a context with a parent context.\n"
|
||||
"This context uses a parent context which is searched for variables and functions "
|
||||
"when not local definition can be found. This version of the context also connects to "
|
||||
"the global singleton context.\n"
|
||||
"\n"
|
||||
"This constructor was introduced in version 0.29.6."
|
||||
) +
|
||||
gsi::constructor ("new", &new_expr_ctx2, gsi::arg ("global"), gsi::arg ("parent"),
|
||||
"@brief Creates a context with a parent context and connecting to a separate global context.\n"
|
||||
"This version allows specifying a global and parent context. The global context is not "
|
||||
"the singleton context in this case. Specifically, this methods allows creating a detached "
|
||||
"context by using 'nil' for both global and parent contexts. Such a context provides no "
|
||||
"specific definitions and can be used to establish a safe environment without access to "
|
||||
"higher-level classes.\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"ctx = RBA::ExpressionContext::new(nil, nil)\n"
|
||||
"# imports the 'Box' class from the global singleton namespace\n"
|
||||
"ctx.import('Box')\n"
|
||||
"# Box is the only class that can be used here:\n"
|
||||
"ctx.eval('Box(0,0,100,200)')\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This constructor was introduced in version 0.29.6."
|
||||
) +
|
||||
gsi::method_ext ("import", &import1, gsi::arg ("name"),
|
||||
"@brief Imports a variable from the global, singleton namespace.\n"
|
||||
"This method can be used for importing classes from the global namespace and make it accessible to "
|
||||
"this context, even if it is not connected to the global singleton one.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.6."
|
||||
) +
|
||||
gsi::method_ext ("import", &import2, gsi::arg ("names"),
|
||||
"@brief Imports variables from the global, singleton namespace.\n"
|
||||
"This variant allows specifying a list of names to import.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.6."
|
||||
) +
|
||||
gsi::method_ext ("import", &import3, gsi::arg ("from"), gsi::arg ("name"),
|
||||
"@brief Import a variable from the given context.\n"
|
||||
"This variant allows to give a source context.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.6."
|
||||
) +
|
||||
gsi::method_ext ("import", &import4, gsi::arg ("from"), gsi::arg ("names"),
|
||||
"@brief Imports variables from the given context.\n"
|
||||
"This variant allows to give a source context and a list of names to import.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.6."
|
||||
) +
|
||||
gsi::method ("var", &tl::Eval::set_var, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Defines a variable with the given name and value\n"
|
||||
"@brief Defines a variable with the given name and value.\n"
|
||||
) +
|
||||
gsi::method_ext ("func", &def_func, gsi::arg ("name"), gsi::arg ("body"),
|
||||
"@brief Defines a function with the given name and function body\n"
|
||||
"@brief Defines a function with the given name and function body.\n"
|
||||
"The function body is an implementation of the \\FunctionBody class. To use it, create a subclass, i.e.\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
|
|
@ -651,9 +760,18 @@ Class<tl::Eval> decl_ExpressionContext ("tl", "ExpressionContext",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.29.6."
|
||||
) +
|
||||
gsi::method ("global_func", &def_global_func, gsi::arg ("name"), gsi::arg ("body"),
|
||||
"Defines a function in the global namespace.\n"
|
||||
"This method defines a function in the global singleton namespace. It works like \\func and acts "
|
||||
"on the global namespace like \\global_var.\n"
|
||||
"Note that the new function only becomes visible to contexts that connect to the global context.\n"
|
||||
"\n"
|
||||
"It has been introduced in version 0.29.6."
|
||||
) +
|
||||
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"
|
||||
"Global variables are available to all expressions sharing the same global context."
|
||||
"This method defines a variable in the global singleton namespace. "
|
||||
"Note that the new variable only becomes visible to contexts that connect to the global context.\n"
|
||||
) +
|
||||
gsi::method ("eval", &tl::Eval::eval, gsi::arg ("expr"),
|
||||
"@brief Compiles and evaluates the given expression in this context\n"
|
||||
|
|
|
|||
|
|
@ -3184,14 +3184,11 @@ Eval::Eval (Eval *global, Eval *parent, bool sloppy)
|
|||
|
||||
Eval::~Eval ()
|
||||
{
|
||||
for (std::map <std::string, EvalFunction *>::iterator f = m_local_functions.begin (); f != m_local_functions.end (); ++f) {
|
||||
delete f->second;
|
||||
}
|
||||
m_local_functions.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
Eval::check ()
|
||||
Eval::check () const
|
||||
{
|
||||
if (m_has_parent) {
|
||||
if (! mp_parent.get ()) {
|
||||
|
|
@ -3227,11 +3224,7 @@ Eval::var (const std::string &name)
|
|||
void
|
||||
Eval::define_function (const std::string &name, EvalFunction *function)
|
||||
{
|
||||
EvalFunction *&f = m_local_functions.insert (std::make_pair (name, (EvalFunction *) 0)).first->second;
|
||||
if (f != 0) {
|
||||
delete f;
|
||||
}
|
||||
f = function;
|
||||
m_local_functions [name].reset (function);
|
||||
}
|
||||
|
||||
EvalFunction *
|
||||
|
|
@ -3239,7 +3232,7 @@ Eval::function (const std::string &name)
|
|||
{
|
||||
auto f = m_local_functions.find (name);
|
||||
if (f != m_local_functions.end ()) {
|
||||
return f->second;
|
||||
return f->second.get ();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -4040,13 +4033,11 @@ Eval::resolve_name (const std::string &t, const EvalFunction *&function, const t
|
|||
value = 0;
|
||||
var = 0;
|
||||
|
||||
std::map <std::string, EvalFunction *>::const_iterator f;
|
||||
f = m_local_functions.find (t);
|
||||
auto f = m_local_functions.find (t);
|
||||
if (f != m_local_functions.end ()) {
|
||||
function = f->second;
|
||||
function = f->second.get ();
|
||||
} else if ((function = EvalStaticFunction::function_by_name (t)) == 0) {
|
||||
std::map<std::string, tl::Variant>::iterator v;
|
||||
v = m_local_vars.find (t);
|
||||
auto v = m_local_vars.find (t);
|
||||
if (v != m_local_vars.end ()) {
|
||||
var = &v->second;
|
||||
} else {
|
||||
|
|
@ -4054,12 +4045,11 @@ Eval::resolve_name (const std::string &t, const EvalFunction *&function, const t
|
|||
}
|
||||
}
|
||||
|
||||
if (! function && ! value && ! var) {
|
||||
if (mp_parent) {
|
||||
mp_parent->resolve_name (t, function, value, var);
|
||||
} else if (mp_global) {
|
||||
mp_global->resolve_name (t, function, value, var);
|
||||
}
|
||||
if (mp_parent && ! function && ! value && ! var) {
|
||||
mp_parent->resolve_name (t, function, value, var);
|
||||
}
|
||||
if (mp_global && ! function && ! value && ! var) {
|
||||
mp_global->resolve_name (t, function, value, var);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -270,6 +270,7 @@ public:
|
|||
* @brief A base class for a function
|
||||
*/
|
||||
class TL_PUBLIC EvalFunction
|
||||
: public tl::Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
|
@ -583,7 +584,7 @@ public:
|
|||
/**
|
||||
* @brief Checks the contexts and throws an exception if one of them got lost
|
||||
*/
|
||||
void check ();
|
||||
void check () const;
|
||||
|
||||
private:
|
||||
friend class Expression;
|
||||
|
|
@ -593,7 +594,7 @@ private:
|
|||
tl::weak_ptr<Eval> mp_global;
|
||||
bool m_has_global;
|
||||
std::map <std::string, tl::Variant> m_local_vars;
|
||||
std::map <std::string, EvalFunction *> m_local_functions;
|
||||
std::map <std::string, tl::shared_ptr<EvalFunction> > m_local_functions;
|
||||
bool m_sloppy;
|
||||
const ContextHandler *mp_ctx_handler;
|
||||
std::vector<std::string> m_match_substrings;
|
||||
|
|
|
|||
|
|
@ -274,7 +274,53 @@ class Tl_TestClass < TestBase
|
|||
|
||||
pc._destroy
|
||||
|
||||
self.assert_equal(e1.eval, 5)
|
||||
begin
|
||||
e1.eval
|
||||
self.assert_equal(true, false)
|
||||
rescue => ex
|
||||
self.assert_equal(ex.to_s, "Parent context was destroyed in Expression::eval")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Parent contexts
|
||||
def test_5_GlobalContext
|
||||
|
||||
# this is a new disconnected context
|
||||
pc = RBA::ExpressionContext::new(nil, nil)
|
||||
pc.var("A", 10)
|
||||
|
||||
# this is a new disconnected context
|
||||
gc = RBA::ExpressionContext::new(nil, nil)
|
||||
gc.var("B", 1.5)
|
||||
|
||||
e = RBA::Expression::new(gc, pc)
|
||||
e.text = "B * A"
|
||||
self.assert_equal(e.eval, 15)
|
||||
|
||||
# built-in functions still work
|
||||
e.text = "pow(A,2)"
|
||||
self.assert_equal(e.eval, 100)
|
||||
|
||||
# but other classes don't
|
||||
begin
|
||||
e.text = "Box.new(1, 2, 3, 4)"
|
||||
self.assert_equal(true, false)
|
||||
rescue => ex
|
||||
end
|
||||
|
||||
# borrow "Box" from the global context (reference context)
|
||||
e.import("Box")
|
||||
|
||||
e.text = "Box.new(1, 2, 3, 4)"
|
||||
self.assert_equal(e.eval.to_s, "(1,2;3,4)")
|
||||
|
||||
# DBox still does not work
|
||||
begin
|
||||
e.text = "DBox.new(1, 2, 3, 4)"
|
||||
self.assert_equal(true, false)
|
||||
rescue => ex
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue