diff --git a/src/gsi/gsi/gsiDeclBasic.cc b/src/gsi/gsi/gsiDeclBasic.cc index 78f857372..dab1ce035 100644 --- a/src/gsi/gsi/gsiDeclBasic.cc +++ b/src/gsi/gsi/gsiDeclBasic.cc @@ -22,12 +22,24 @@ #include "gsiDeclBasic.h" +#include "gsiInterpreter.h" #include "gsiDecl.h" +#include "tlTypeTraits.h" + +namespace tl +{ + template <> struct tl::type_traits + : tl::type_traits + { + 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,75 @@ Class 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::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 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' parameters which can be modified by code executed inside the interpreter." + ) + + 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 and vice versa.\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(\"print(\"This is Python now!\")\nout_param.value = out_param.value + 25\")\n" + "puts out_param.value # gives '42'" + "@/code\n" +); + } diff --git a/src/gsi/gsi/gsiDeclBasic.h b/src/gsi/gsi/gsiDeclBasic.h index cbd41cbca..43acb605a 100644 --- a/src/gsi/gsi/gsiDeclBasic.h +++ b/src/gsi/gsi/gsiDeclBasic.h @@ -30,6 +30,7 @@ #include #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: /** diff --git a/src/gsi/gsi/gsiInterpreter.h b/src/gsi/gsi/gsiInterpreter.h index 36ddea1e1..818719001 100644 --- a/src/gsi/gsi/gsiInterpreter.h +++ b/src/gsi/gsi/gsiInterpreter.h @@ -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 diff --git a/src/lym/lym/gsiDeclLymMacro.cc b/src/lym/lym/gsiDeclLymMacro.cc index 2ab526368..d41d4ef80 100644 --- a/src/lym/lym/gsiDeclLymMacro.cc +++ b/src/lym/lym/gsiDeclLymMacro.cc @@ -97,11 +97,11 @@ Class 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) { @@ -112,7 +112,7 @@ public: m_debugger_scheme = lym::MacroInterpreter::debugger_scheme (); } - ~MacroInterpreter () + ~MacroInterpreterImpl () { delete mp_registration; mp_registration = 0; @@ -257,7 +257,7 @@ private: bool m_supports_include_expansion; }; -gsi::EnumIn decl_FormatEnum ("lay", "MacroFormat", +gsi::EnumIn decl_FormatEnum ("lay", "Format", gsi::enum_const ("PlainTextFormat", lym::Macro::PlainTextFormat, "@brief The macro has plain text format" ) + @@ -271,7 +271,7 @@ gsi::EnumIn decl_FormatEnum ("lay", "MacroFormat "This enum has been introduced in version 0.27.5." ); -gsi::EnumIn decl_InterpreterEnum ("lay", "MacroInterpreter", +gsi::EnumIn decl_InterpreterEnum ("lay", "Interpreter", gsi::enum_const ("Ruby", lym::Macro::Ruby, "@brief The interpreter is Ruby" ) + @@ -301,14 +301,14 @@ lym::Macro::Interpreter const_NoDebugger () return lym::Macro::None; } -Class decl_MacroInterpreter ("lay", "MacroInterpreter", +Class 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" @@ -316,7 +316,7 @@ Class 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" @@ -326,7 +326,7 @@ Class 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" @@ -334,7 +334,7 @@ Class 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 " @@ -346,7 +346,7 @@ Class 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" @@ -356,7 +356,7 @@ Class 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. " @@ -367,7 +367,7 @@ Class 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 " @@ -378,7 +378,7 @@ Class 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) " @@ -389,7 +389,7 @@ Class 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 " @@ -479,7 +479,7 @@ Class decl_MacroInterpreter ("lay", "MacroInterpreter", ); // Inject the Macro::Format declarations into MacroInterpreter: -gsi::ClassExt inject_Format_in_parent (decl_FormatEnum.defs ()); +gsi::ClassExt inject_Format_in_parent (decl_FormatEnum.defs ()); static lym::Macro *macro_by_path (const std::string &path) { @@ -529,11 +529,6 @@ Class decl_Macro ("lay", "Macro", "\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" - "\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" @@ -549,7 +544,7 @@ Class decl_Macro ("lay", "Macro", "\n" "This method has been introduced in version 0.27.5.\n" ) + - gsi::method ("doc=", &lym::Macro::set_version, gsi::arg ("doc"), + 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" @@ -604,6 +599,12 @@ Class decl_Macro ("lay", "Macro", "\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" @@ -614,7 +615,7 @@ Class decl_Macro ("lay", "Macro", "\n" "This method has been introduced in version 0.27.5.\n" ) + - gsi::method ("sync_text_with_properties=", &lym::Macro::sync_text_with_properties, + 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 " @@ -623,7 +624,7 @@ Class decl_Macro ("lay", "Macro", "\n" "This method has been introduced in version 0.27.5.\n" ) + - gsi::method ("sync_properties_with_text=", &lym::Macro::sync_properties_with_text, + 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" @@ -784,11 +785,27 @@ Class 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 inject_Format_in_macro (decl_FormatEnum.defs ()); -gsi::ClassExt inject_Interprert_in_macro (decl_InterpreterEnum.defs ()); +gsi::ClassExt inject_Interpreter_in_macro (decl_InterpreterEnum.defs ()); } diff --git a/src/pya/pya/pya.cc b/src/pya/pya/pya.cc index dee876b65..6266282f1 100644 --- a/src/pya/pya/pya.cc +++ b/src/pya/pya/pya.cc @@ -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 ())); diff --git a/src/pya/pya/pya.h b/src/pya/pya/pya.h index 4688e64e8..ff69ab37c 100644 --- a/src/pya/pya/pya.h +++ b/src/pya/pya/pya.h @@ -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 diff --git a/src/pyastub/pya.cc b/src/pyastub/pya.cc index f1dcdf1b3..d8b6643e9 100644 --- a/src/pyastub/pya.cc +++ b/src/pyastub/pya.cc @@ -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 .. } diff --git a/src/pyastub/pya.h b/src/pyastub/pya.h index 45826dc9d..e9ee98cc5 100644 --- a/src/pyastub/pya.h +++ b/src/pyastub/pya.h @@ -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 diff --git a/src/rba/rba/rba.cc b/src/rba/rba/rba.cc index b0978762a..7aaa7899e 100644 --- a/src/rba/rba/rba.cc +++ b/src/rba/rba/rba.cc @@ -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 * diff --git a/src/rba/rba/rba.h b/src/rba/rba/rba.h index bd8442724..094e031d3 100644 --- a/src/rba/rba/rba.h +++ b/src/rba/rba/rba.h @@ -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 diff --git a/src/rba/unit_tests/rbaTests.cc b/src/rba/unit_tests/rbaTests.cc index 7cdac9988..3d9a9f2c8 100644 --- a/src/rba/unit_tests/rbaTests.cc +++ b/src/rba/unit_tests/rbaTests.cc @@ -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") diff --git a/src/rbastub/rba.cc b/src/rbastub/rba.cc index dda501be6..2c1c821d7 100644 --- a/src/rbastub/rba.cc +++ b/src/rbastub/rba.cc @@ -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 .. } diff --git a/src/rbastub/rba.h b/src/rbastub/rba.h index 2fc5a7ca2..a17799994 100644 --- a/src/rbastub/rba.h +++ b/src/rbastub/rba.h @@ -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