Merge pull request #937 from KLayout/more-macro-bindings

More macro bindings
This commit is contained in:
Matthias Köfferlein 2021-11-14 16:18:23 +01:00 committed by GitHub
commit 91d358398b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 506 additions and 65 deletions

View File

@ -22,12 +22,24 @@
#include "gsiDeclBasic.h"
#include "gsiInterpreter.h"
#include "gsiDecl.h"
#include "tlTypeTraits.h"
namespace tl
{
template <> struct type_traits<gsi::Interpreter>
: tl::type_traits<void>
{
typedef false_tag has_copy_constructor;
typedef false_tag has_default_constructor;
typedef false_tag has_public_destructor;
};
}
namespace gsi
{
// ---------------------------------------------------------------------------------
// A generic value wrapper that allows wrapping a plain data type into an object
@ -66,4 +78,83 @@ Class<Value> decl_Value ("tl", "Value",
"This class has been introduced in version 0.22."
);
static void eval_string_impl (Interpreter *ip, const char *string, const char *filename, int line)
{
ip->eval_string (string, filename, line);
}
static tl::Variant eval_expr_impl (Interpreter *ip, const char *string, const char *filename, int line)
{
return ip->eval_expr (string, filename, line);
}
static void define_variable_impl (Interpreter *ip, const std::string &name, const tl::Variant &value)
{
ip->define_variable (name, value);
}
static gsi::Interpreter *interpreter_by_name (const std::string &name)
{
for (tl::Registrar<gsi::Interpreter>::iterator i = gsi::interpreters.begin (); i != gsi::interpreters.end (); ++i) {
if (i.current_name () == name) {
return i->available () ? i.operator-> () : 0;
}
}
return 0;
}
static gsi::Interpreter *python_interpreter ()
{
return interpreter_by_name ("pya");
}
static gsi::Interpreter *ruby_interpreter ()
{
return interpreter_by_name ("rba");
}
Class<Interpreter> decl_Macro ("tl", "Interpreter",
gsi::method ("load_file", &Interpreter::load_file, gsi::arg ("path"),
"@brief Loads the given file into the interpreter\n"
"This will execute the code inside the file.\n"
) +
gsi::method_ext ("eval_string", &eval_string_impl, gsi::arg ("string"), gsi::arg ("filename", (const char *) 0, "nil"), gsi::arg ("line", 1),
"@brief Executes the code inside the given string\n"
"Use 'filename' and 'line' to indicate the original source for the error messages.\n"
) +
gsi::method_ext ("eval_expr", &eval_expr_impl, gsi::arg ("string"), gsi::arg ("filename", (const char *) 0, "nil"), gsi::arg ("line", 1),
"@brief Executes the expression inside the given string and returns the result value\n"
"Use 'filename' and 'line' to indicate the original source for the error messages.\n"
) +
gsi::method_ext ("define_variable", &define_variable_impl, gsi::arg ("name"), gsi::arg ("value"),
"@brief Defines a (global) variable with the given name and value\n"
"You can use the \\Value class to provide 'out' or 'inout' parameters which can be modified by code executed inside the interpreter and read back by the caller."
) +
gsi::method ("python_interpreter", &python_interpreter,
"@brief Gets the instance of the Python interpreter\n"
) +
gsi::method ("ruby_interpreter", &ruby_interpreter,
"@brief Gets the instance of the Ruby interpreter\n"
),
"@brief A generalization of script interpreters\n"
"The main purpose of this class is to provide cross-language call options. "
"Using the Python interpreter, it is possible to execute Python code from Ruby for example.\n"
"\n"
"The following example shows how to use the interpreter class to execute Python code from Ruby "
"and how to pass values from Ruby to Python and back using the \\Value wrapper object:\n"
"\n"
"@code\n"
"pya = RBA::Interpreter::python_interpreter\n"
"out_param = RBA::Value::new(17)\n"
"pya.define_variable(\"out_param\", out_param)\n"
"pya.eval_string(<<END)\n"
"print(\"This is Python now!\")\n"
"out_param.value = out_param.value + 25\n"
"END\n"
"puts out_param.value # gives '42'"
"@/code\n"
"\n"
"This class was introduced in version 0.27.5.\n"
);
}

View File

@ -30,6 +30,7 @@
#include <iostream>
#include "tlVariant.h"
#include "gsiObject.h"
namespace gsi
{
@ -38,6 +39,7 @@ namespace gsi
* @brief Provides a basic implementation for a "boxed" plain value using a Variant as the basic type
*/
class GSI_PUBLIC Value
: public gsi::ObjectBase
{
public:
/**

View File

@ -25,6 +25,7 @@
#include "tlScriptError.h"
#include "tlClassRegistry.h"
#include "tlVariant.h"
#include "gsiCommon.h"
namespace gsi
@ -267,7 +268,7 @@ public:
/**
* @brief Defines a global variable with the given name and value
*/
virtual void define_variable (const std::string &name, const std::string &value) = 0;
virtual void define_variable (const std::string &name, const tl::Variant &value) = 0;
/**
* @brief Installs the given console for output

View File

@ -24,6 +24,7 @@
#include "gsiDecl.h"
#include "gsiDeclBasic.h"
#include "gsiInterpreter.h"
#include "gsiEnums.h"
#include "lymMacroInterpreter.h"
#include "lymMacro.h"
#include "rba.h"
@ -96,11 +97,11 @@ Class<gsi::MacroExecutionContext> decl_MacroExecutionContext ("lay", "MacroExecu
"suppress exceptions when re-raising them."
);
class MacroInterpreter
class MacroInterpreterImpl
: public lym::MacroInterpreter
{
public:
MacroInterpreter ()
MacroInterpreterImpl ()
: lym::MacroInterpreter (),
mp_registration (0), m_supports_include_expansion (true)
{
@ -111,7 +112,7 @@ public:
m_debugger_scheme = lym::MacroInterpreter::debugger_scheme ();
}
~MacroInterpreter ()
~MacroInterpreterImpl ()
{
delete mp_registration;
mp_registration = 0;
@ -161,9 +162,9 @@ public:
return m_supports_include_expansion;
}
void set_storage_scheme (int scheme)
void set_storage_scheme (lym::Macro::Format scheme)
{
m_storage_scheme = lym::Macro::Format (scheme);
m_storage_scheme = scheme;
}
virtual lym::Macro::Format storage_scheme () const
@ -171,9 +172,9 @@ public:
return m_storage_scheme;
}
void set_debugger_scheme (int scheme)
void set_debugger_scheme (lym::Macro::Interpreter scheme)
{
m_debugger_scheme = lym::Macro::Interpreter (scheme);
m_debugger_scheme = scheme;
}
virtual lym::Macro::Interpreter debugger_scheme () const
@ -256,50 +257,58 @@ private:
bool m_supports_include_expansion;
};
int const_PlainTextFormat ()
{
return int (lym::Macro::PlainTextFormat);
}
int const_PlainTextWithHashAnnotationsFormat ()
{
return int (lym::Macro::PlainTextWithHashAnnotationsFormat);
}
int const_MacroFormat ()
{
return int (lym::Macro::MacroFormat);
}
int const_RubyDebugger ()
{
return int (lym::Macro::Ruby);
}
int const_NoDebugger ()
{
return int (lym::Macro::None);
}
Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
gsi::method ("PlainTextFormat", &const_PlainTextFormat,
"@brief Indicates plain text format for \\storage_scheme\n"
gsi::EnumIn<lym::Macro, lym::Macro::Format> decl_FormatEnum ("lay", "Format",
gsi::enum_const ("PlainTextFormat", lym::Macro::PlainTextFormat,
"@brief The macro has plain text format"
) +
gsi::method ("PlainTextWithHashAnnotationsFormat", &const_PlainTextWithHashAnnotationsFormat,
"@brief Indicates plain text format for \\storage_scheme\n"
"This format is identical to \\PlainTextFormat but indicates that it is possible "
"to insert annotations (properties) into the text in a hash-commented header."
gsi::enum_const ("PlainTextWithHashAnnotationsFormat", lym::Macro::PlainTextWithHashAnnotationsFormat,
"@brief The macro has plain text format with special pseudo-comment annotations"
) +
gsi::method ("MacroFormat", &const_MacroFormat,
"@brief Indicates macro (XML) format for \\storage_scheme\n"
gsi::enum_const ("MacroFormat", lym::Macro::MacroFormat,
"@brief The macro has macro (XML) format"
),
"@brief Specifies the format of a macro\n"
"This enum has been introduced in version 0.27.5."
);
gsi::EnumIn<lym::Macro, lym::Macro::Interpreter> decl_InterpreterEnum ("lay", "Interpreter",
gsi::enum_const ("Ruby", lym::Macro::Ruby,
"@brief The interpreter is Ruby"
) +
gsi::enum_const ("Python", lym::Macro::Python,
"@brief The interpreter is Python"
) +
gsi::enum_const ("Text", lym::Macro::Text,
"@brief Plain text"
) +
gsi::enum_const ("DSLInterpreter", lym::Macro::DSLInterpreter,
"@brief A domain-specific interpreter (DSL)"
) +
gsi::enum_const ("None", lym::Macro::None,
"@brief No specific interpreter"
),
"@brief Specifies the interpreter used for executing a macro\n"
"This enum has been introduced in version 0.27.5."
);
lym::Macro::Interpreter const_RubyDebugger ()
{
return lym::Macro::Ruby;
}
lym::Macro::Interpreter const_NoDebugger ()
{
return lym::Macro::None;
}
Class<MacroInterpreterImpl> decl_MacroInterpreter ("lay", "MacroInterpreter",
gsi::method ("RubyDebugger", &const_RubyDebugger,
"@brief Indicates Ruby debugger for \\debugger_scheme\n"
) +
gsi::method ("NoDebugger", &const_NoDebugger,
"@brief Indicates no debugging for \\debugger_scheme\n"
) +
gsi::method ("register", &MacroInterpreter::register_gsi, gsi::arg ("name"),
gsi::method ("register", &MacroInterpreterImpl::register_gsi, gsi::arg ("name"),
"@brief Registers the macro interpreter\n"
"@param name The interpreter name. This is an arbitrary string which should be unique.\n"
"\n"
@ -307,7 +316,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"is set to 'dsl' can use this object to run the script. For executing a script, the system will "
"call the interpreter's \\execute method.\n"
) +
gsi::method ("create_template", &MacroInterpreter::create_template, gsi::arg ("url"),
gsi::method ("create_template", &MacroInterpreterImpl::create_template, gsi::arg ("url"),
"@brief Creates a new macro template\n"
"@param url The template will be initialized from that URL.\n"
"\n"
@ -317,7 +326,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"\n"
"This method must be called after \\register has called.\n"
) +
gsi::method ("supports_include_expansion=", &MacroInterpreter::set_supports_include_expansion, gsi::arg ("flag"),
gsi::method ("supports_include_expansion=", &MacroInterpreterImpl::set_supports_include_expansion, gsi::arg ("flag"),
"@brief Sets a value indicating whether this interpreter supports the default include file expansion scheme.\n"
"If this value is set to true (the default), lines like '# %include ...' will be substituted by the "
"content of the file following the '%include' keyword.\n"
@ -325,7 +334,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"\n"
"This attribute has been introduced in version 0.27.\n"
) +
gsi::method ("syntax_scheme=", &gsi::MacroInterpreter::set_syntax_scheme, gsi::arg ("scheme"),
gsi::method ("syntax_scheme=", &MacroInterpreterImpl::set_syntax_scheme, gsi::arg ("scheme"),
"@brief Sets a string indicating the syntax highlighter scheme\n"
"\n"
"The scheme string can be empty (indicating no syntax highlighting), \"ruby\" for the Ruby syntax "
@ -337,7 +346,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"Before version 0.25 this attribute was a re-implementable method. It has been turned into an attribute for "
"performance reasons in version 0.25.\n"
) +
gsi::method ("debugger_scheme=", &gsi::MacroInterpreter::set_debugger_scheme, gsi::arg ("scheme"),
gsi::method ("debugger_scheme=", &MacroInterpreterImpl::set_debugger_scheme, gsi::arg ("scheme"),
"@brief Sets the debugger scheme (which debugger to use for the DSL macro)\n"
"\n"
"The value can be one of the constants \\RubyDebugger or \\NoDebugger.\n"
@ -347,7 +356,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"Before version 0.25 this attribute was a re-implementable method. It has been turned into an attribute for "
"performance reasons in version 0.25.\n"
) +
gsi::method ("storage_scheme=", &gsi::MacroInterpreter::set_storage_scheme, gsi::arg ("scheme"),
gsi::method ("storage_scheme=", &MacroInterpreterImpl::set_storage_scheme, gsi::arg ("scheme"),
"@brief Sets the storage scheme (the format as which the macro is stored)\n"
"\n"
"This value indicates how files for this DSL macro type shall be stored. "
@ -358,7 +367,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"Before version 0.25 this attribute was a re-implementable method. It has been turned into an attribute for "
"performance reasons in version 0.25.\n"
) +
gsi::method ("description=", &gsi::MacroInterpreter::set_description, gsi::arg ("description"),
gsi::method ("description=", &MacroInterpreterImpl::set_description, gsi::arg ("description"),
"@brief Sets a description string\n"
"\n"
"This string is used for showing the type of DSL macro in the file selection box together with the "
@ -369,7 +378,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"Before version 0.25 this attribute was a re-implementable method. It has been turned into an attribute for "
"performance reasons in version 0.25.\n"
) +
gsi::method ("suffix=", &gsi::MacroInterpreter::set_suffix, gsi::arg ("suffix"),
gsi::method ("suffix=", &MacroInterpreterImpl::set_suffix, gsi::arg ("suffix"),
"@brief Sets the file suffix\n"
"\n"
"This string defines which file suffix to associate with the DSL macro. If an empty string is given (the default) "
@ -380,7 +389,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"Before version 0.25 this attribute was a re-implementable method. It has been turned into an attribute for "
"performance reasons in version 0.25.\n"
) +
gsi::callback ("executable", &gsi::MacroInterpreter::executable, &gsi::MacroInterpreter::f_executable, gsi::arg ("macro"),
gsi::callback ("executable", &MacroInterpreterImpl::executable, &MacroInterpreterImpl::f_executable, gsi::arg ("macro"),
"@brief Returns the executable object which implements the macro execution\n"
"This method must be reimplemented to return an \\Executable object for the actual implementation. "
"The system will use this function to execute the script when a macro with interpreter type 'dsl' and the "
@ -469,6 +478,9 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"This class has been introduced in version 0.23 and modified in 0.27.\n"
);
// Inject the Macro::Format declarations into MacroInterpreter:
gsi::ClassExt<MacroInterpreterImpl> inject_Format_in_parent (decl_FormatEnum.defs ());
static lym::Macro *macro_by_path (const std::string &path)
{
return lym::MacroCollection::root ().find_macro (path);
@ -492,7 +504,133 @@ static int real_line (const std::string &path, int line)
}
}
lym::Macro *new_from_path (const std::string &path)
{
std::unique_ptr<lym::Macro> m (new lym::Macro ());
m->set_is_file ();
m->set_file_path (path);
m->load_from (path);
return m.release ();
}
Class<lym::Macro> decl_Macro ("lay", "Macro",
gsi::constructor ("new", &new_from_path, gsi::arg ("path"),
"@brief Loads the macro from the given file path\n"
"\n"
"This constructor has been introduced in version 0.27.5.\n"
) +
gsi::method ("run", &lym::Macro::run,
"@brief Executes the macro\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("save_to", &lym::Macro::save_to, gsi::arg ("path"),
"@brief Saves the macro to the given file\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("version", &lym::Macro::version,
"@brief Gets the macro's version\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("version=", &lym::Macro::set_version, gsi::arg ("version"),
"@brief Sets the macro's version\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("doc", &lym::Macro::doc,
"@brief Gets the macro's documentation string\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("doc=", &lym::Macro::set_doc, gsi::arg ("doc"),
"@brief Sets the macro's documentation string\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("shortcut", &lym::Macro::shortcut,
"@brief Gets the macro's keyboard shortcut\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("shortcut=", &lym::Macro::set_shortcut, gsi::arg ("shortcut"),
"@brief Sets the macro's keyboard shortcut\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("is_autorun?", &lym::Macro::is_autorun,
"@brief Gets a flag indicating whether the macro is automatically executed on startup\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("is_autorun=", &lym::Macro::set_autorun, gsi::arg ("flag"),
"@brief Sets a flag indicating whether the macro is automatically executed on startup\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("is_autorun_early?", &lym::Macro::is_autorun_early,
"@brief Gets a flag indicating whether the macro is automatically executed early on startup\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("is_autorun_early=", &lym::Macro::set_autorun_early, gsi::arg ("flag"),
"@brief Sets a flag indicating whether the macro is automatically executed early on startup\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("format", &lym::Macro::format,
"@brief Gets the macro's storage format\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("format=", &lym::Macro::set_format, gsi::arg ("format"),
"@brief Sets the macro's storage format\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("interpreter", &lym::Macro::interpreter,
"@brief Gets the macro's interpreter\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("interpreter=", &lym::Macro::set_interpreter, gsi::arg ("interpreter"),
"@brief Sets the macro's interpreter\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("interpreter_name", &lym::Macro::interpreter_name,
"@brief Gets the macro interpreter name\n"
"This is the string version of \\interpreter.\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("dsl_interpreter", &lym::Macro::dsl_interpreter,
"@brief Gets the macro's DSL interpreter name (if interpreter is DSLInterpreter)\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("dsl_interpreter=", &lym::Macro::set_dsl_interpreter, gsi::arg ("dsl_interpreter"),
"@brief Sets the macro's DSL interpreter name (if interpreter is DSLInterpreter)\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("sync_text_with_properties", &lym::Macro::sync_text_with_properties,
"@brief Synchronizes the macro text with the properties\n"
"\n"
"This method applies to PlainTextWithHashAnnotationsFormat format. The macro text will "
"be enhanced with pseudo-comments reflecting the macro properties. This way, the macro "
"properties can be stored in plain files.\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("sync_properties_with_text", &lym::Macro::sync_properties_with_text,
"@brief Synchronizes the macro properties with the text\n"
"\n"
"This method performs the reverse process of \\sync_text_with_properties.\n"
"\n"
"This method has been introduced in version 0.27.5.\n"
) +
gsi::method ("path", &lym::Macro::path,
"@brief Gets the path of the macro\n"
"\n"
@ -589,7 +727,7 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"@brief Sets the menu path\n"
"See \\menu_path for details.\n"
) +
gsi::method ("real_path", &real_path,
gsi::method ("real_path", &real_path, gsi::arg ("path"), gsi::arg ("line"),
"@brief Gets the real path for an include-encoded path and line number\n"
"\n"
"When using KLayout's include scheme based on '# %include ...', __FILE__ and __LINE__ (Ruby) will "
@ -614,7 +752,7 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"\n"
"This feature has been introduced in version 0.27."
) +
gsi::method ("real_line", &real_line,
gsi::method ("real_line", &real_line, gsi::arg ("path"), gsi::arg ("line"),
"@brief Gets the real line number for an include-encoded path and line number\n"
"\n"
"When using KLayout's include scheme based on '# %include ...', __FILE__ and __LINE__ (Ruby) will "
@ -647,7 +785,27 @@ Class<lym::Macro> decl_Macro ("lay", "Macro",
"This class is provided mainly to support generation of template macros in the "
"DSL interpreter framework provided by \\MacroInterpreter. The implementation may be "
"enhanced in future versions and provide access to macros stored inside KLayout's macro repository."
"\n"
"But it can be used to execute macro code in a consistent way:\n"
"\n"
"@code\n"
"path = \"path-to-macro.lym\"\n"
"RBA::Macro::new(path).run()\n"
"@/code\n"
"\n"
"Using the Macro class with \\run for executing code will chose the right interpreter and is "
"able to execute DRC and LVS scripts in the proper environment. This also provides an option to "
"execute Ruby code from Python and vice versa.\n"
"\n"
"In this scenario you can pass values to the script using \\Interpreter#define_variable. "
"The interpreter to choose for DRC and LVS scripts is \\Interpreter#ruby_interpreter. "
"For passing values back from the script, wrap the variable value into a \\Value object "
"which can be modified by the called script and read back by the caller."
);
// Inject the Macro::Format declarations into MacroInterpreter:
gsi::ClassExt<lym::Macro> inject_Format_in_macro (decl_FormatEnum.defs ());
gsi::ClassExt<lym::Macro> inject_Interpreter_in_macro (decl_InterpreterEnum.defs ());
}

View File

@ -175,7 +175,8 @@ static void reset_interpreter ()
}
PythonInterpreter::PythonInterpreter (bool embedded)
: mp_current_console (0), mp_current_exec_handler (0), m_current_exec_level (0),
: gsi::Interpreter (0, "pya"),
mp_current_console (0), mp_current_exec_handler (0), m_current_exec_level (0),
m_in_trace (false), m_block_exceptions (false), m_ignore_next_exception (false),
mp_current_frame (NULL), mp_py3_app_name (0), m_embedded (embedded)
{
@ -572,7 +573,7 @@ PythonInterpreter::inspector (int context)
}
void
PythonInterpreter::define_variable (const std::string &name, const std::string &value)
PythonInterpreter::define_variable (const std::string &name, const tl::Variant &value)
{
PythonPtr main_module (PyImport_AddModule ("__main__"));
PythonPtr dict (PyModule_GetDict (main_module.get ()));

View File

@ -182,7 +182,7 @@ public:
/**
* @brief Defines a global variable with the given name and value
*/
void define_variable (const std::string &name, const std::string &value);
void define_variable (const std::string &name, const tl::Variant &value);
/**
* @brief Gets a value indicating whether the interpreter is available

View File

@ -35,6 +35,7 @@ static void fail (const char *file, int line)
static PythonInterpreter *sp_pya_interpreter = 0;
PythonInterpreter::PythonInterpreter ()
: gsi::Interpreter (0, "pya")
{
tl_assert (! sp_pya_interpreter);
sp_pya_interpreter = this;
@ -118,7 +119,7 @@ PythonInterpreter::inspector (int)
}
void
PythonInterpreter::define_variable (const std::string &, const std::string &)
PythonInterpreter::define_variable (const std::string &, const tl::Variant &)
{
// .. nothing ..
}

View File

@ -114,7 +114,7 @@ public:
/**
* @brief Defines a global variable with the given name and value
*/
void define_variable (const std::string &name, const std::string &value);
void define_variable (const std::string &name, const tl::Variant &value);
/**
* @brief Gets a value indicating whether the interpreter is available

View File

@ -1758,7 +1758,8 @@ rba_init (RubyInterpreterPrivateData *d)
}
RubyInterpreter::RubyInterpreter ()
: d (new RubyInterpreterPrivateData ())
: gsi::Interpreter (0, "rba"),
d (new RubyInterpreterPrivateData ())
{
tl::SelfTimer timer (tl::verbosity () >= 21, "Initializing Ruby");
@ -2057,9 +2058,9 @@ RubyInterpreter::eval_string_and_print (const char *expr, const char *file, int
}
void
RubyInterpreter::define_variable (const std::string &name, const std::string &value)
RubyInterpreter::define_variable (const std::string &name, const tl::Variant &value)
{
rb_gv_set (name.c_str (), rb_str_new (value.c_str (), long (value.size ())));
rb_gv_set (name.c_str (), c2ruby (value));
}
gsi::Inspector *

View File

@ -127,7 +127,7 @@ public:
/**
* @brief Defines a global variable with the given name and value
*/
void define_variable (const std::string &name, const std::string &value);
void define_variable (const std::string &name, const tl::Variant &value);
/**
* @brief Gets a value indicating whether the interpreter is available

View File

@ -141,6 +141,7 @@ RUBYTEST (imgObject, "imgObject.rb")
RUBYTEST (layLayers, "layLayers.rb")
RUBYTEST (layLayoutView, "layLayoutView.rb")
RUBYTEST (layMarkers, "layMarkers.rb")
RUBYTEST (layMacro, "layMacro.rb")
RUBYTEST (layMenuTest, "layMenuTest.rb")
RUBYTEST (laySession, "laySession.rb")
RUBYTEST (layTechnologies, "layTechnologies.rb")

View File

@ -34,6 +34,7 @@ static void fail (const char *file, int line)
static RubyInterpreter *sp_rba_interpreter = 0;
RubyInterpreter::RubyInterpreter ()
: gsi::Interpreter (0, "rba")
{
tl_assert (! sp_rba_interpreter);
sp_rba_interpreter = this;
@ -110,7 +111,7 @@ RubyInterpreter::eval_string_and_print (const char *, const char *file, int line
}
void
RubyInterpreter::define_variable (const std::string &, const std::string &)
RubyInterpreter::define_variable (const std::string &, const tl::Variant &)
{
// .. nothing ..
}

View File

@ -111,7 +111,7 @@ public:
/**
* @brief Defines a global variable with the given name and value
*/
void define_variable (const std::string &name, const std::string &value);
void define_variable (const std::string &name, const tl::Variant &value);
/**
* @brief Gets a value indicating whether the interpreter is available

184
testdata/ruby/layMacro.rb vendored Normal file
View File

@ -0,0 +1,184 @@
# encoding: UTF-8
# KLayout Layout Viewer
# Copyright (C) 2006-2021 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
if !$:.member?(File::dirname($0))
$:.push(File::dirname($0))
end
load("test_prologue.rb")
class LAYMacro_TestClass < TestBase
def test_1
macro = RBA::Macro::new
macro.version = "1.7"
assert_equal(macro.version, "1.7")
macro.doc = "%doc"
assert_equal(macro.doc, "%doc")
macro.description = "%description"
assert_equal(macro.description, "%description")
macro.prolog = "%prolog"
assert_equal(macro.prolog, "%prolog")
macro.epilog = "%epilog"
assert_equal(macro.epilog, "%epilog")
macro.category = "%category"
assert_equal(macro.category, "%category")
macro.shortcut = "%shortcut"
assert_equal(macro.shortcut, "%shortcut")
assert_equal(macro.is_autorun?, false)
macro.is_autorun = true
assert_equal(macro.is_autorun?, true)
assert_equal(macro.is_autorun_early?, false)
macro.is_autorun_early = true
assert_equal(macro.is_autorun_early?, true)
macro.format = RBA::Macro::PlainTextFormat
assert_equal(macro.format == RBA::Macro::PlainTextFormat, true)
macro.format = RBA::Macro::MacroFormat
assert_equal(macro.format == RBA::Macro::MacroFormat, true)
macro.interpreter = RBA::Macro::Ruby
assert_equal(macro.interpreter == RBA::Macro::Ruby, true)
assert_equal(macro.interpreter_name, "Ruby")
macro.interpreter = RBA::Macro::Python
assert_equal(macro.interpreter == RBA::Macro::Python, true)
assert_equal(macro.interpreter_name, "Python")
macro.dsl_interpreter = "%dsl"
assert_equal(macro.dsl_interpreter, "%dsl")
macro.text = "%text"
macro.format = RBA::Macro::PlainTextWithHashAnnotationsFormat
assert_equal(macro.text, "%text")
macro.sync_text_with_properties
assert_equal(macro.text, "# $description: %description\n" +
"# $prolog: %prolog\n" +
"# $epilog: %epilog\n" +
"# $version: 1.7\n" +
"# $autorun\n" +
"# $autorun-early\n" +
"# $shortcut: %shortcut\n" +
"%text")
macro.text = "# $description: %description\n" +
"# $prolog: %prolog\n" +
"# $epilog: %epilog\n" +
"# $version: 7.1\n" +
"# $autorun\n" +
"# $autorun-early\n" +
"# $shortcut: %shortcut\n" +
"%text"
macro.sync_properties_with_text
assert_equal(macro.version, "7.1")
macro.group_name = "%group"
assert_equal(macro.group_name, "%group")
assert_equal(macro.show_in_menu?, false)
macro.show_in_menu = true
assert_equal(macro.show_in_menu?, true)
macro.menu_path = "menu.path"
assert_equal(macro.menu_path, "menu.path")
end
def test_2
macro_file = File.join($ut_testtmp, "test.lym")
File.open(macro_file, "w") do |file|
file.write(<<"END")
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
<description>%description</description>
<version>42</version>
<interpreter>ruby</interpreter>
<text>
$test_output = "x" + $test_input
</text>
</klayout-macro>
END
end
macro = RBA::Macro::new(macro_file)
assert_equal(macro.description, "%description")
assert_equal(macro.path, macro_file)
$test_input = "42"
$test_output = ""
macro.run
assert_equal($test_output, "x42")
macro_file2 = File.join($ut_testtmp, "test2.lym")
macro.save_to(macro_file2)
macro2 = RBA::Macro::new(macro_file2)
assert_equal(macro2.path, macro_file2)
end
def test_3
pya = RBA::Interpreter.python_interpreter
if !pya
return
end
macro_file = File.join($ut_testtmp, "test.lym")
File.open(macro_file, "w") do |file|
file.write(<<"END")
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
<description>%description</description>
<version>42</version>
<interpreter>python</interpreter>
<text>
print("Python calling!")
context.value = "x" + context.value
</text>
</klayout-macro>
END
end
macro = RBA::Macro::new(macro_file)
assert_equal(macro.description, "%description")
assert_equal(macro.path, macro_file)
context = RBA::Value::new
context.value = "42"
pya.define_variable("context", context)
macro.run
assert_equal(context.value, "x42")
end
end
load("test_epilogue.rb")