]> granicus.if.org Git - icinga2/commitdiff
Implement a C++ code generator for libconfig
authorGunnar Beutner <gunnar@beutner.name>
Sat, 15 Nov 2014 07:20:22 +0000 (08:20 +0100)
committerGunnar Beutner <gunnar@beutner.name>
Thu, 20 Nov 2014 20:53:32 +0000 (21:53 +0100)
fixes #7699
fixes #7704
fixes #7706

13 files changed:
lib/cli/CMakeLists.txt
lib/cli/codegencommand.cpp [new file with mode: 0644]
lib/cli/codegencommand.hpp [new file with mode: 0644]
lib/cli/daemoncommand.cpp
lib/config/CMakeLists.txt
lib/config/config_parser.yy
lib/config/configcompiler.cpp
lib/config/configcompiler.hpp
lib/config/configtype.cpp
lib/config/expression-codegen.cpp [new file with mode: 0644]
lib/config/expression.cpp
lib/config/expression.hpp
lib/config/vmops.hpp [new file with mode: 0644]

index 121effb76d2186e99d72c4e7034120e8ba3c3b05..8590d36072fdc070f65bc418c43e2c4e84f44629 100644 (file)
@@ -16,6 +16,7 @@
 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
 set(cli_SOURCES
+  codegencommand.cpp
   nodeaddcommand.cpp nodeblackandwhitelistcommand.cpp nodelistcommand.cpp noderemovecommand.cpp
   nodesetcommand.cpp nodesetupcommand.cpp nodeupdateconfigcommand.cpp nodewizardcommand.cpp nodeutility.cpp
   clicommand.cpp
diff --git a/lib/cli/codegencommand.cpp b/lib/cli/codegencommand.cpp
new file mode 100644 (file)
index 0000000..57c3587
--- /dev/null
@@ -0,0 +1,121 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
+ *                                                                            *
+ * 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.             *
+ ******************************************************************************/
+
+#include "cli/codegencommand.hpp"
+#include "config/expression.hpp"
+#include "config/configcompiler.hpp"
+#include "config/configcompilercontext.hpp"
+#include "base/logger.hpp"
+
+using namespace icinga;
+
+REGISTER_CLICOMMAND("codegen", CodeGenCommand);
+
+String CodeGenCommand::GetDescription(void) const
+{
+       return "Generates native code for an Icinga 2 config file.";
+}
+
+String CodeGenCommand::GetShortDescription(void) const
+{
+       return "compiles an Icinga 2 config file";
+}
+
+void CodeGenCommand::InitParameters(boost::program_options::options_description& visibleDesc,
+       boost::program_options::options_description& hiddenDesc) const
+{
+}
+
+bool CodeGenCommand::IsHidden(void) const
+{
+       return true;
+}
+
+/**
+ * The entry point for the "codegen" CLI command.
+ *
+ * @returns An exit status.
+ */
+int CodeGenCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
+{
+       Logger::SetConsoleLogSeverity(LogWarning);
+
+       Expression *expr = ConfigCompiler::CompileStream("<stdin>", &std::cin);
+
+       int errors = 0;
+
+       BOOST_FOREACH(const ConfigCompilerMessage& message, ConfigCompilerContext::GetInstance()->GetMessages()) {
+               String logmsg = String("Config ") + (message.Error ? "error" : "warning") + ": " + message.Text;
+
+               if (message.Error) {
+                       Log(LogCritical, "config", logmsg);
+                       errors++;
+               } else {
+                       Log(LogWarning, "config", logmsg);
+               }
+       }
+
+       if (errors > 0)
+               return 1;
+
+       std::cout << "#include \"config/expression.hpp\"" << "\n"
+                 << "#include \"config/vmops.hpp\"" << "\n"
+                 << "#include \"base/json.hpp\"" << "\n"
+                 << "#include \"base/initialize.hpp\"" << "\n"
+                 << "#include <boost/smart_ptr/make_shared.hpp>" << "\n"
+                 << "\n"
+                 << "using namespace icinga;" << "\n"
+                 << "\n";
+
+       std::map<String, String> definitions;
+
+       String name = CodeGenExpression(definitions, expr);
+
+       BOOST_FOREACH(const DefinitionMap::value_type& kv, definitions) {
+               std::cout << "static Value " << kv.first << "(const Object::Ptr& context);" << "\n";
+       }
+
+       std::cout << "\n"
+                 << "static Dictionary::Ptr l_ModuleScope = new Dictionary();" << "\n"
+                 << "\n"
+                 << "static void RunCode(void)" << "\n"
+                 << "{" << "\n"
+                 << "  " << name << "(l_ModuleScope);" << "\n"
+                 << "}" << "\n"
+                 << "\n"
+                 << "INITIALIZE_ONCE(RunCode);" << "\n"
+                 << "\n"
+                 << "int main(int argc, char **argv)" << "\n"
+                 << "{" << "\n"
+                 << "  RunCode();" << "\n"
+                 << "  if (l_ModuleScope->Contains(\"__result\"))" << "\n"
+                 << "    std::cout << \"Result: \" << JsonEncode(l_ModuleScope->Get(\"__result\")) << \"\\n\";" << "\n"
+                 << "  else" << "\n"
+                 << "    std::cout << \"No result.\" << \"\\n\";" << "\n"
+                 << "}" << "\n"
+                 << "\n";
+
+       BOOST_FOREACH(const DefinitionMap::value_type& kv, definitions) {
+               std::cout << kv.second << "\n";
+       }
+
+       delete expr;
+
+       return 0;
+}
diff --git a/lib/cli/codegencommand.hpp b/lib/cli/codegencommand.hpp
new file mode 100644 (file)
index 0000000..813c393
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
+ *                                                                            *
+ * 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.             *
+ ******************************************************************************/
+
+#ifndef CODEGENCOMMAND_H
+#define CODEGENCOMMAND_H
+
+#include "base/dictionary.hpp"
+#include "base/array.hpp"
+#include "cli/clicommand.hpp"
+#include <ostream>
+
+namespace icinga
+{
+
+/**
+ * The "variable get" command.
+ *
+ * @ingroup cli
+ */
+class CodeGenCommand : public CLICommand
+{
+public:
+       DECLARE_PTR_TYPEDEFS(CodeGenCommand);
+
+       virtual String GetDescription(void) const;
+       virtual String GetShortDescription(void) const;
+       virtual bool IsHidden(void) const;
+       void InitParameters(boost::program_options::options_description& visibleDesc,
+           boost::program_options::options_description& hiddenDesc) const;
+       virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
+};
+
+}
+
+#endif /* CODEGENCOMMAND_H */
index a62e1fb864f69d5d32b8e0bd8d2cc3535674e966..966af8568cdbc8cc539919890a41807e749aa092 100644 (file)
@@ -65,7 +65,11 @@ static String LoadAppType(const String& typeSpec)
 static void IncludeZoneDirRecursive(const String& path)
 {
        String zoneName = Utility::BaseName(path);
-       Utility::GlobRecursive(path, "*.conf", boost::bind(&ConfigCompiler::CompileFile, _1, zoneName), GlobFile);
+
+       std::vector<Expression *> expressions;
+       Utility::GlobRecursive(path, "*.conf", boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zoneName), GlobFile);
+       Dictionary::Ptr context = new Dictionary();
+       DictExpression(expressions).Evaluate(context);
 }
 
 static void IncludeNonLocalZone(const String& zonePath)
@@ -88,10 +92,15 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con
 
        if (vm.count("config") > 0) {
                BOOST_FOREACH(const String& configPath, vm["config"].as<std::vector<std::string> >()) {
-                       ConfigCompiler::CompileFile(configPath);
+                       Expression *expression = ConfigCompiler::CompileFile(configPath);
+                       Dictionary::Ptr context = new Dictionary();
+                       expression->Evaluate(context);
                }
-       } else if (!vm.count("no-config"))
-               ConfigCompiler::CompileFile(Application::GetSysconfDir() + "/icinga2/icinga2.conf");
+       } else if (!vm.count("no-config")) {
+               Expression *expression = ConfigCompiler::CompileFile(Application::GetSysconfDir() + "/icinga2/icinga2.conf");
+               Dictionary::Ptr context = new Dictionary();
+               expression->Evaluate(context);
+       }
 
        /* Load cluster config files - this should probably be in libremote but
        * unfortunately moving it there is somewhat non-trivial. */
@@ -105,7 +114,9 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con
 
        String name, fragment;
        BOOST_FOREACH(boost::tie(name, fragment), ConfigFragmentRegistry::GetInstance()->GetItems()) {
-               ConfigCompiler::CompileText(name, fragment);
+               Expression *expression = ConfigCompiler::CompileText(name, fragment);
+               Dictionary::Ptr context = new Dictionary();
+               expression->Evaluate(context);
        }
 
        ConfigItemBuilder::Ptr builder = new ConfigItemBuilder();
index 596c70ccc10529c2fa3c94b0198547b3c46f3dc2..b09aaf848714592b59b687e166db21ba83dc1796 100644 (file)
@@ -34,7 +34,7 @@ set(config_SOURCES
   applyrule.cpp base-type.conf base-type.cpp
   configcompilercontext.cpp configcompiler.cpp configitembuilder.cpp
   configitem.cpp ${FLEX_config_lexer_OUTPUTS} ${BISON_config_parser_OUTPUTS}
-  configtype.cpp expression.cpp objectrule.cpp typerule.cpp typerulelist.cpp
+  configtype.cpp expression.cpp expression-codegen.cpp objectrule.cpp typerule.cpp typerulelist.cpp
 )
 
 if(ICINGA2_UNITY_BUILD)
index 54744819eeb432e318014bc81ec751c68f6dcc2a..79b0face37e8aab87ff2c391855648646c92c7ae 100644 (file)
@@ -227,8 +227,9 @@ static std::stack<Expression *> m_Ignore;
 static std::stack<String> m_FKVar;
 static std::stack<String> m_FVVar;
 static std::stack<Expression *> m_FTerm;
+static std::stack<std::vector<Expression *> > m_Expressions;
 
-void ConfigCompiler::Compile(void)
+Expression *ConfigCompiler::Compile(void)
 {
        m_ModuleScope = new Dictionary();
 
@@ -243,15 +244,25 @@ void ConfigCompiler::Compile(void)
        m_FKVar = std::stack<String>();
        m_FVVar = std::stack<String>();
        m_FTerm = std::stack<Expression *>();
+       m_Expressions.push(std::vector<Expression *>());
 
        try {
                yyparse(this);
+
+               DictExpression *expr = new DictExpression(m_Expressions.top());
+               m_Expressions.pop();
+               expr->MakeInline();
+               return expr;
        } catch (const ConfigError& ex) {
                const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(ex);
                ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo());
        } catch (const std::exception& ex) {
                ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
        }
+
+       m_Expressions.pop();
+
+       return NULL;
 }
 
 #define scanner (context->GetScanner())
@@ -263,39 +274,13 @@ statements: /* empty */
        | statements statement
        ;
 
-statement: type | include | include_recursive | library | constant
+statement: type | library | constant
        { }
        | newlines
        { }
        | lterm
        {
-               $1->Evaluate(m_ModuleScope);
-               delete $1;
-       }
-       ;
-
-include: T_INCLUDE rterm sep
-       {
-               context->HandleInclude($2->Evaluate(m_ModuleScope), false, DebugInfoRange(@1, @2));
-               delete $2;
-       }
-       | T_INCLUDE T_STRING_ANGLE
-       {
-               context->HandleInclude($2, true, DebugInfoRange(@1, @2));
-               free($2);
-       }
-       ;
-
-include_recursive: T_INCLUDE_RECURSIVE rterm
-       {
-               context->HandleIncludeRecursive($2->Evaluate(m_ModuleScope), "*.conf", DebugInfoRange(@1, @2));
-               delete $2;
-       }
-       | T_INCLUDE_RECURSIVE rterm ',' rterm
-       {
-               context->HandleIncludeRecursive($2->Evaluate(m_ModuleScope), $4->Evaluate(m_ModuleScope), DebugInfoRange(@1, @4));
-               delete $2;
-               delete $4;
+               m_Expressions.top().push_back($1);
        }
        ;
 
@@ -590,6 +575,27 @@ lterm: indexer combined_set_op rterm
                $$ = new SetExpression(*$1, $2, $3, DebugInfoRange(@1, @3));
                delete $1;
        }
+       | T_INCLUDE rterm sep
+       {
+               $$ = context->HandleInclude($2->Evaluate(m_ModuleScope), false, DebugInfoRange(@1, @2));
+               delete $2;
+       }
+       | T_INCLUDE T_STRING_ANGLE
+       {
+               $$ = context->HandleInclude($2, true, DebugInfoRange(@1, @2));
+               free($2);
+       }
+       | T_INCLUDE_RECURSIVE rterm
+       {
+               $$ = context->HandleIncludeRecursive($2->Evaluate(m_ModuleScope), "*.conf", DebugInfoRange(@1, @2));
+               delete $2;
+       }
+       | T_INCLUDE_RECURSIVE rterm ',' rterm
+       {
+               $$ = context->HandleIncludeRecursive($2->Evaluate(m_ModuleScope), $4->Evaluate(m_ModuleScope), DebugInfoRange(@1, @4));
+               delete $2;
+               delete $4;
+       }
        | T_IMPORT rterm
        {
                Expression *avar = new VariableExpression("type", DebugInfoRange(@1, @2));
index 19c78f4660f0ebf4af9cac5e9e32d4a5fc0d62f8..cd39617a0ae964b89236e8dbeab878d69afaadce 100644 (file)
@@ -97,6 +97,11 @@ String ConfigCompiler::GetZone(void) const
        return m_Zone;
 }
 
+void ConfigCompiler::CollectIncludes(std::vector<Expression *>& expressions, const String& file, const String& zone)
+{
+       expressions.push_back(CompileFile(file, zone));
+}
+
 /**
  * Handles an include directive.
  *
@@ -104,7 +109,7 @@ String ConfigCompiler::GetZone(void) const
  * @param search Whether to search global include dirs.
  * @param debuginfo Debug information.
  */
-void ConfigCompiler::HandleInclude(const String& include, bool search, const DebugInfo& debuginfo)
+Expression *ConfigCompiler::HandleInclude(const String& include, bool search, const DebugInfo& debuginfo)
 {
        String path;
 
@@ -126,32 +131,36 @@ void ConfigCompiler::HandleInclude(const String& include, bool search, const Deb
                }
        }
 
-       std::vector<ConfigItem::Ptr> items;
+       std::vector<Expression *> expressions;
 
-       if (!Utility::Glob(includePath, boost::bind(&ConfigCompiler::CompileFile, _1, m_Zone), GlobFile) && includePath.FindFirstOf("*?") == String::NPos) {
+       if (!Utility::Glob(includePath, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, m_Zone), GlobFile) && includePath.FindFirstOf("*?") == String::NPos) {
                std::ostringstream msgbuf;
                msgbuf << "Include file '" + include + "' does not exist: " << debuginfo;
                BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
        }
+
+       return new DictExpression(expressions);
 }
 
 /**
  * Handles recursive includes.
  *
- * @param include The directory path.
+ * @param path The directory path.
  * @param pattern The file pattern.
  * @param debuginfo Debug information.
  */
-void ConfigCompiler::HandleIncludeRecursive(const String& include, const String& pattern, const DebugInfo&)
+Expression *ConfigCompiler::HandleIncludeRecursive(const String& path, const String& pattern, const DebugInfo&)
 {
-       String path;
+       String ppath;
 
-       if (include.GetLength() > 0 && include[0] == '/')
-               path = include;
+       if (path.GetLength() > 0 && path[0] == '/')
+               ppath = path;
        else
-               path = Utility::DirName(GetPath()) + "/" + include;
+               ppath = Utility::DirName(GetPath()) + "/" + path;
 
-       Utility::GlobRecursive(path, pattern, boost::bind(&ConfigCompiler::CompileFile, _1, m_Zone), GlobFile);
+       std::vector<Expression *> expressions;
+       Utility::GlobRecursive(ppath, pattern, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, m_Zone), GlobFile);
+       return new DictExpression(expressions);
 }
 
 /**
@@ -171,14 +180,14 @@ void ConfigCompiler::HandleLibrary(const String& library)
  * @param stream The input stream.
  * @returns Configuration items.
  */
-void ConfigCompiler::CompileStream(const String& path, std::istream *stream, const String& zone)
+Expression *ConfigCompiler::CompileStream(const String& path, std::istream *stream, const String& zone)
 {
        CONTEXT("Compiling configuration stream with name '" + path + "'");
 
        stream->exceptions(std::istream::badbit);
 
        ConfigCompiler ctx(path, stream, zone);
-       ctx.Compile();
+       return ctx.Compile();
 }
 
 /**
@@ -187,7 +196,7 @@ void ConfigCompiler::CompileStream(const String& path, std::istream *stream, con
  * @param path The path.
  * @returns Configuration items.
  */
-void ConfigCompiler::CompileFile(const String& path, const String& zone)
+Expression *ConfigCompiler::CompileFile(const String& path, const String& zone)
 {
        CONTEXT("Compiling configuration file '" + path + "'");
 
@@ -213,7 +222,7 @@ void ConfigCompiler::CompileFile(const String& path, const String& zone)
  * @param text The text.
  * @returns Configuration items.
  */
-void ConfigCompiler::CompileText(const String& path, const String& text, const String& zone)
+Expression *ConfigCompiler::CompileText(const String& path, const String& text, const String& zone)
 {
        std::stringstream stream(text);
        return CompileStream(path, &stream, zone);
index 3c3dd0dd138fd2ee3602ac96ead31be3272857de..ee63c8061c1be0d8995969362617f4188aab3f0f 100644 (file)
@@ -21,6 +21,7 @@
 #define CONFIGCOMPILER_H
 
 #include "config/i2-config.hpp"
+#include "config/expression.hpp"
 #include "base/debuginfo.hpp"
 #include "base/registry.hpp"
 #include "base/initialize.hpp"
@@ -43,11 +44,11 @@ public:
        explicit ConfigCompiler(const String& path, std::istream *input, const String& zone = String());
        virtual ~ConfigCompiler(void);
 
-       void Compile(void);
+       Expression *Compile(void);
 
-       static void CompileStream(const String& path, std::istream *stream, const String& zone = String());
-       static void CompileFile(const String& path, const String& zone = String());
-       static void CompileText(const String& path, const String& text, const String& zone = String());
+       static Expression *CompileStream(const String& path, std::istream *stream, const String& zone = String());
+       static Expression *CompileFile(const String& path, const String& zone = String());
+       static Expression *CompileText(const String& path, const String& text, const String& zone = String());
 
        static void AddIncludeSearchDir(const String& dir);
 
@@ -56,9 +57,11 @@ public:
        void SetZone(const String& zone);
        String GetZone(void) const;
 
+       static void CollectIncludes(std::vector<Expression *>& expressions, const String& file, const String& zone);
+
        /* internally used methods */
-       void HandleInclude(const String& include, bool search, const DebugInfo& debuginfo);
-       void HandleIncludeRecursive(const String& include, const String& pattern, const DebugInfo& debuginfo);
+       Expression *HandleInclude(const String& include, bool search, const DebugInfo& debuginfo = DebugInfo());
+       Expression *HandleIncludeRecursive(const String& path, const String& pattern, const DebugInfo& debuginfo = DebugInfo());
        void HandleLibrary(const String& library);
 
        size_t ReadInput(char *buffer, size_t max_bytes);
index 9a5873339dd4596d6dfd63b815868deaba19a431..423ad7a1f2606ec37324e268ac97efdabfec13c3 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "config/configtype.hpp"
 #include "config/configcompilercontext.hpp"
-#include "config/expression.hpp"
+#include "config/vmops.hpp"
 #include "base/objectlock.hpp"
 #include "base/convert.hpp"
 #include "base/singleton.hpp"
@@ -162,7 +162,7 @@ void ConfigType::ValidateObject(const Object::Ptr& object,
                BOOST_FOREACH(const String& require, ruleList->GetRequires()) {
                        locations.push_back("Attribute '" + require + "'");
 
-                       Value value = Expression::GetField(object, require);
+                       Value value = VMOps::GetField(object, require);
 
                        if (value.IsEmpty() || (value.IsString() && static_cast<String>(value).IsEmpty())) {
                                ConfigCompilerContext::GetInstance()->AddMessage(true,
diff --git a/lib/config/expression-codegen.cpp b/lib/config/expression-codegen.cpp
new file mode 100644 (file)
index 0000000..c0e44c9
--- /dev/null
@@ -0,0 +1,565 @@
+/******************************************************************************
+ * Icinga 2                                                                   *
+ * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
+ *                                                                            *
+ * 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.             *
+ ******************************************************************************/
+
+#include "config/expression.hpp"
+#include "config/vmops.hpp"
+#include "base/object.hpp"
+#include <boost/foreach.hpp>
+
+using namespace icinga;
+
+void LiteralExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       if (m_Value.IsString())
+               fp << "String(\"" << m_Value << "\")";
+       else if (m_Value.IsNumber())
+               fp << m_Value;
+       else if (m_Value.IsEmpty())
+               fp << "Value()";
+       else
+               throw std::invalid_argument("Literal expression has invalid type: " + m_Value.GetTypeName());
+}
+
+void VariableExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "VMOps::Variable(context, \"" << m_Variable << "\")";
+}
+
+void NegateExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "~(long)(";
+       m_Operand->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void LogicalNegateExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "!(";
+       m_Operand->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void AddExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") + (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void SubtractExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") - (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void MultiplyExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") * (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void DivideExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") / (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void BinaryAndExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") & (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void BinaryOrExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") | (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void ShiftLeftExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") << (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void ShiftRightExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") >> (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void EqualExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") == (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void NotEqualExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") != (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void LessThanExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") < (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void GreaterThanExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") > (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void LessThanOrEqualExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") <= (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void GreaterThanOrEqualExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ") >= (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void InExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "!static_cast<Array::Ptr>(";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")->Contains(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void NotInExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "!static_cast<Array::Ptr>(";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ")->Contains(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void LogicalAndExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ").ToBool() && (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ").ToBool()";
+}
+
+void LogicalOrExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "(";
+       m_Operand1->GenerateCode(definitions, fp);
+       fp << ").ToBool() || (";
+       m_Operand2->GenerateCode(definitions, fp);
+       fp << ").ToBool()";
+}
+
+void FunctionCallExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       std::ostringstream namebuf, df;
+
+       namebuf << "native_fcall_" << reinterpret_cast<uintptr_t>(this);
+
+       df << "static Value " << namebuf.str() << "(const Object::Ptr& context)" << "\n"
+          << "{" << "\n"
+          << "  Value funcName = (";
+       m_FName->GenerateCode(definitions, df);
+       df << ");" << "\n"
+          << "  std::vector<Value> args;" << "\n";
+
+       BOOST_FOREACH(Expression *expr, m_Args) {
+               df << "  args.push_back(";
+               expr->GenerateCode(definitions, df);
+               df << ");" << "\n";
+       }
+
+       df << "  return VMOps::FunctionCall(context, funcName, args);" << "\n"
+          << "}" << "\n";
+
+       definitions[namebuf.str()] = df.str();
+
+       fp << namebuf.str() << "(context)";
+}
+
+void ArrayExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       std::ostringstream namebuf, df;
+
+       namebuf << "native_array_" << reinterpret_cast<uintptr_t>(this);
+
+       df << "static Value " << namebuf.str() << "(const Object::Ptr& context)" << "\n"
+          << "{" << "\n"
+          << "  Array::Ptr result = new Array();" << "\n";
+
+       BOOST_FOREACH(Expression *aexpr, m_Expressions) {
+               df << "  result->Add(";
+               aexpr->GenerateCode(definitions, df);
+               df << ");" << "\n";
+       }
+
+       df << "  return result;" << "\n"
+          << "}" << "\n";
+
+       definitions[namebuf.str()] = df.str();
+
+       fp << namebuf.str() << "(context)";
+}
+
+void DictExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       std::ostringstream namebuf, df;
+
+       namebuf << "native_dict_" << reinterpret_cast<uintptr_t>(this);
+
+       df << "static Value " << namebuf.str() << "(const Object::Ptr& ucontext)" << "\n"
+          << "{" << "\n";
+
+       if (!m_Inline) {
+               df << "  Dictionary::Ptr result = new Dictionary();" << "\n"
+                  << "  result->Set(\"__parent\", ucontext);" << "\n"
+                  << "  Object::Ptr context = result;" << "\n";
+       } else
+               df << "Object::Ptr context = ucontext;" << "\n";
+
+       df << "  do {" << "\n";
+
+       BOOST_FOREACH(Expression *expression, m_Expressions) {
+               df << "    ";
+               expression->GenerateCode(definitions, df);
+               df << ";" << "\n"
+                  << "    if (Expression::HasField(context, \"__result\"))" << "\n"
+                  << "      break;" << "\n";
+       }
+
+       df << "  } while (0);" << "\n"
+          << "\n";
+
+       if (!m_Inline) {
+               df << "  Dictionary::Ptr xresult = result->ShallowClone();" << "\n"
+                  << "  xresult->Remove(\"__parent\");" << "\n"
+                  << "  return xresult;" << "\n";
+       } else
+               df << "  return Empty;" << "\n";
+
+       df << "}" << "\n";
+
+       definitions[namebuf.str()] = df.str();
+
+       fp << namebuf.str() << "(context)";
+}
+
+void SetExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       std::ostringstream namebuf, df;
+
+       namebuf << "native_set_" << reinterpret_cast<uintptr_t>(this);
+
+       df << "static Value " << namebuf.str() << "(const Object::Ptr& context)" << "\n"
+          << "{" << "\n"
+          << "  Value parent, object;" << "\n"
+          << "  String tempindex, index;" << "\n";
+
+       for (Array::SizeType i = 0; i < m_Indexer.size(); i++) {
+               Expression *indexExpr = m_Indexer[i];
+               df << "  tempindex = (";
+               indexExpr->GenerateCode(definitions, df);
+               df << ");" << "\n";
+
+               if (i == 0)
+                       df << "  parent = context;" << "\n";
+               else
+                       df << "  parent = object;" << "\n";
+
+               if (i == m_Indexer.size() - 1) {
+                       df << "  index = tempindex" << ";" << "\n";
+
+                       /* No need to look up the last indexer's value if this is a direct set */
+                       if (m_Op == OpSetLiteral)
+                               break;
+               }
+
+               df << "  object = VMOps::Indexer(context, parent, tempindex);" << "\n";
+
+               if (i != m_Indexer.size() - 1) {
+                       df << "  if (object.IsEmpty()) {" << "\n"
+                          << "    object = new Dictionary();" << "\n"
+                          << "    Expression::SetField(parent, tempindex, object);" << "\n"
+                          << "  }" << "\n";
+               }
+       }
+
+       df << "  Value right = (";
+       m_Operand2->GenerateCode(definitions, df);
+       df << ");" << "\n";
+
+       if (m_Op != OpSetLiteral) {
+               String opcode;
+
+               switch (m_Op) {
+                       case OpSetAdd:
+                               opcode = "+";
+                               break;
+                       case OpSetSubtract:
+                               opcode = "-";
+                               break;
+                       case OpSetMultiply:
+                               opcode = "*";
+                               break;
+                       case OpSetDivide:
+                               opcode = "/";
+                               break;
+                       default:
+                               VERIFY(!"Invalid opcode.");
+               }
+
+               df << "  right = object " << opcode << " right;" << "\n";
+       }
+
+       df << "  Expression::SetField(parent, index, right);" << "\n"
+          << "  return right;" << "\n"
+          << "}" << "\n";
+
+       definitions[namebuf.str()] = df.str();
+
+       fp << namebuf.str() << "(context)";
+}
+
+void IndexerExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       std::ostringstream namebuf, df;
+
+       namebuf << "native_indexer_" << reinterpret_cast<uintptr_t>(this);
+
+       df << "static Value " << namebuf.str() << "(const Object::Ptr& context)" << "\n"
+          << "{" << "\n"
+          << "  return VMOps::Indexer(context, (";
+       m_Operand1->GenerateCode(definitions, df);
+       df << "), (";
+       m_Operand2->GenerateCode(definitions, df);
+       df << "));" << "\n"
+          << "}" << "\n";
+
+       definitions[namebuf.str()] = df.str();
+
+       fp << namebuf.str() << "(context)";
+}
+
+void ImportExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       std::ostringstream namebuf, df;
+
+       namebuf << "native_import_" << reinterpret_cast<uintptr_t>(this);
+
+       df << "static Value " << namebuf.str() << "(const Object::Ptr& context)" << "\n"
+          << "{" << "\n"
+          << "  String name = (";
+       m_Name->GenerateCode(definitions, df);
+       df << ");" << "\n"
+          << "  String type = (";
+       m_Type->GenerateCode(definitions, df);
+       df << ");" << "\n"
+          << "\n"
+          << "  ConfigItem::Ptr item = ConfigItem::GetObject(type, name);" << "\n"
+          << "\n"
+          << "  if (!item)" << "\n"
+          << "    BOOST_THROW_EXCEPTION(ConfigError(\"Import references unknown template: '\" + name + \"' of type '\" + type + \"'\"));" << "\n"
+          << "\n"
+          << "  item->GetExpression()->Evaluate(context);" << "\n"
+          << "\n"
+          << "  return Empty;" << "\n"
+          << "}" << "\n";
+
+       definitions[namebuf.str()] = df.str();
+
+       fp << namebuf.str() << "(context)";
+}
+
+void FunctionExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       std::ostringstream namebuf, df;
+
+       namebuf << "native_function_" << reinterpret_cast<uintptr_t>(this);
+
+       df << "static Value " << namebuf.str() << "(const Object::Ptr& context)" << "\n"
+          << "{" << "\n"
+          << "  std::vector<String> args;" << "\n";
+
+       BOOST_FOREACH(const String& arg, m_Args)
+               df << "  args.push_back(\"" << arg << "\");" << "\n";
+
+       df << "  return VMOps::NewFunction(context, \"" << m_Name << "\", args, boost::make_shared<NativeExpression>("
+          << CodeGenExpression(definitions, m_Expression.get()) << "));" << "\n"
+          << "}" << "\n";
+
+       definitions[namebuf.str()] = df.str();
+
+       fp << namebuf.str() << "(context)";
+}
+
+void SlotExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       fp << "VMOps::NewSlot(context, \"" << m_Signal << "\", ";
+       m_Slot->GenerateCode(definitions, fp);
+       fp << ")";
+}
+
+void ApplyExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       std::ostringstream namebuf, df;
+
+       namebuf << "native_apply_" << reinterpret_cast<uintptr_t>(this);
+
+       df << "static Value " << namebuf.str() << "(const Object::Ptr& context)" << "\n"
+          << "{" << "\n"
+          << "  boost::shared_ptr<Expression> fterm;" << "\n";
+
+       if (m_FTerm)
+               df << "  fterm = boost::make_shared<NativeExpression>(" << CodeGenExpression(definitions, m_FTerm.get()) << ");" << "\n";
+
+       df << "  boost::shared_ptr<Expression> filter = boost::make_shared<NativeExpression>(" << CodeGenExpression(definitions, m_Filter.get()) << ");" << "\n"
+          << "  boost::shared_ptr<Expression> expression = boost::make_shared<NativeExpression>(" << CodeGenExpression(definitions, m_Expression.get()) << ");" << "\n"
+          << "  return VMOps::NewApply(context, \"" << m_Type << "\", \"" << m_Target << "\", (";
+       m_Name->GenerateCode(definitions, df);
+       df << "), filter, "
+          << "\"" << m_FKVar << "\", \"" << m_FVVar << "\", fterm, expression);" << "\n"
+          << "}" << "\n";
+
+       definitions[namebuf.str()] = df.str();
+
+       fp << namebuf.str() << "(context)";
+}
+
+void ObjectExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       std::ostringstream namebuf, df;
+
+       namebuf << "native_object_" << reinterpret_cast<uintptr_t>(this);
+
+       df << "static Value " << namebuf.str() << "(const Object::Ptr& context)" << "\n"
+          << "{" << "\n"
+          << "  String name;" << "\n";
+
+       if (m_Name) {
+               df << "  name = (";
+               m_Name->GenerateCode(definitions, df);
+               df << ");" << "\n";
+       }
+
+       df << "  boost::shared_ptr<Expression> filter;" << "\n";
+
+       if (m_Filter)
+               df << "  filter = boost::make_shared<NativeExpression>("
+                  << CodeGenExpression(definitions, m_Filter.get()) << ");" << "\n";
+
+       df << "  boost::shared_ptr<Expression> expression = boost::make_shared<NativeExpression>("
+          << CodeGenExpression(definitions, m_Expression.get()) << ");" << "\n"
+          << "  return VMOps::NewObject(context, " << m_Abstract << ", \"" << m_Type << "\", name, filter, \"" << m_Zone << "\", expression);" << "\n"
+          << "}" << "\n";
+
+       definitions[namebuf.str()] = df.str();
+
+       fp << namebuf.str() << "(context)";
+}
+
+void ForExpression::GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+{
+       std::ostringstream namebuf, df;
+
+       namebuf << "native_for_" << reinterpret_cast<uintptr_t>(this);
+
+       df << "static Value " << namebuf.str() << "(const Object::Ptr& context)" << "\n"
+          << "{" << "\n"
+          << "  static NativeExpression expression("
+          << CodeGenExpression(definitions, m_Expression) << ");" << "\n"
+          << "  return VMOps::For(context, \"" << m_FKVar << "\", \"" << m_FVVar << "\", (";
+       m_Value->GenerateCode(definitions, df);
+       df << "), &expression);" << "\n"
+          << "}" << "\n";
+
+       definitions[namebuf.str()] = df.str();
+
+       fp << namebuf.str() << "(context)";
+}
+
+String icinga::CodeGenExpression(DefinitionMap& definitions, Expression *expression)
+{
+       std::ostringstream namebuf, definitionbuf;
+
+       namebuf << "native_expression_" << reinterpret_cast<uintptr_t>(expression);
+
+       definitionbuf << "static Value " << namebuf.str() << "(const Object::Ptr& context)" << "\n"
+                     << "{" << "\n"
+                     << "  return (";
+
+       expression->GenerateCode(definitions, definitionbuf);
+
+       definitionbuf << ");" << "\n"
+                     << "}" << "\n";
+
+       definitions[namebuf.str()] = definitionbuf.str();
+
+       return namebuf.str();
+}
index 5bc4ecc396f5bdd9c883a276c2511386823cd271..e3cbc3db34c8b39304379d372c0c75807a4d510d 100644 (file)
 
 #include "config/expression.hpp"
 #include "config/configitem.hpp"
-#include "config/configitembuilder.hpp"
-#include "config/applyrule.hpp"
-#include "config/objectrule.hpp"
+#include "config/vmops.hpp"
 #include "base/array.hpp"
 #include "base/json.hpp"
-#include "base/scriptfunction.hpp"
-#include "base/scriptvariable.hpp"
-#include "base/scriptsignal.hpp"
-#include "base/utility.hpp"
-#include "base/objectlock.hpp"
 #include "base/object.hpp"
 #include "base/logger.hpp"
 #include "base/configerror.hpp"
 #include <boost/foreach.hpp>
 #include <boost/exception_ptr.hpp>
-#include <boost/lexical_cast.hpp>
 #include <boost/exception/errinfo_nested_exception.hpp>
 
 using namespace icinga;
@@ -97,16 +89,7 @@ const DebugInfo& DebuggableExpression::GetDebugInfo(void) const
 
 Value VariableExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
 {
-       Object::Ptr scope = context;
-
-       while (scope) {
-               if (HasField(scope, m_Variable))
-                       return GetField(scope, m_Variable);
-
-               scope = GetField(scope, "__parent");
-       }
-
-       return ScriptVariable::Get(m_Variable);
+       return VMOps::Variable(context, m_Variable);
 }
 
 Value NegateExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
@@ -199,7 +182,7 @@ Value InExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) con
                BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonEncode(right)));
 
        Value left = m_Operand1->Evaluate(context);
-               
+
        Array::Ptr arr = right;
        return arr->Contains(left);
 }
@@ -233,22 +216,12 @@ Value FunctionCallExpression::DoEvaluate(const Object::Ptr& context, DebugHint *
 {
        Value funcName = m_FName->Evaluate(context);
 
-       ScriptFunction::Ptr func;
-
-       if (funcName.IsObjectType<ScriptFunction>())
-               func = funcName;
-       else
-               func = ScriptFunction::GetByName(funcName);
-
-       if (!func)
-               BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist."));
-
        std::vector<Value> arguments;
        BOOST_FOREACH(Expression *arg, m_Args) {
                arguments.push_back(arg->Evaluate(context));
        }
 
-       return func->Invoke(arguments);
+       return VMOps::FunctionCall(context, funcName, arguments);
 }
 
 Value ArrayExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
@@ -272,7 +245,7 @@ Value DictExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) c
                Object::Ptr acontext = m_Inline ? context : result;
                aexpr->Evaluate(acontext, dhint);
 
-               if (HasField(acontext, "__result"))
+               if (VMOps::HasField(acontext, "__result"))
                        break;
        }
 
@@ -311,16 +284,12 @@ Value SetExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) co
                                break;
                }
 
-               LiteralExpression *eparent = MakeLiteral(parent);
-               LiteralExpression *eindex = MakeLiteral(tempindex);
-
-               IndexerExpression eip(eparent, eindex, m_DebugInfo);
-               object = eip.Evaluate(context, psdhint);
+               object = VMOps::Indexer(context, parent, tempindex);
 
                if (i != m_Indexer.size() - 1 && object.IsEmpty()) {
                        object = new Dictionary();
 
-                       SetField(parent, tempindex, object);
+                       VMOps::SetField(parent, tempindex, object);
                }
        }
 
@@ -348,7 +317,7 @@ Value SetExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) co
                }
        }
 
-       SetField(parent, index, right);
+       VMOps::SetField(parent, index, right);
 
        if (psdhint)
                psdhint->AddMessage("=", m_DebugInfo);
@@ -358,33 +327,7 @@ Value SetExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) co
 
 Value IndexerExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
 {
-       Value value = m_Operand1->Evaluate(context);
-       Value index = m_Operand2->Evaluate(context);
-
-       if (value.IsObjectType<Dictionary>()) {
-               Dictionary::Ptr dict = value;
-               return dict->Get(index);
-       } else if (value.IsObjectType<Array>()) {
-               Array::Ptr arr = value;
-               return arr->Get(index);
-       } else if (value.IsObject()) {
-               Object::Ptr object = value;
-               Type::Ptr type = object->GetReflectionType();
-
-               if (!type)
-                       BOOST_THROW_EXCEPTION(ConfigError("Dot operator applied to object which does not support reflection"));
-
-               int field = type->GetFieldId(index);
-
-               if (field == -1)
-                       BOOST_THROW_EXCEPTION(ConfigError("Tried to access invalid property '" + index + "'"));
-
-               return object->GetField(field);
-       } else if (value.IsEmpty()) {
-               return Empty;
-       } else {
-               BOOST_THROW_EXCEPTION(ConfigError("Dot operator cannot be applied to type '" + value.GetTypeName() + "'"));
-       }
+       return VMOps::Indexer(context, m_Operand1->Evaluate(context), m_Operand2->Evaluate(context));
 }
 
 Value ImportExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
@@ -402,66 +345,19 @@ Value ImportExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint)
        return Empty;
 }
 
-Value Expression::FunctionWrapper(const std::vector<Value>& arguments,
-    const std::vector<String>& funcargs, const boost::shared_ptr<Expression>& expr, const Object::Ptr& scope)
-{
-       if (arguments.size() < funcargs.size())
-               BOOST_THROW_EXCEPTION(ConfigError("Too few arguments for function"));
-
-       Dictionary::Ptr context = new Dictionary();
-       context->Set("__parent", scope);
-
-       for (std::vector<Value>::size_type i = 0; i < std::min(arguments.size(), funcargs.size()); i++)
-               context->Set(funcargs[i], arguments[i]);
-
-       expr->Evaluate(context);
-       return context->Get("__result");
-}
-
 Value FunctionExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
 {
-       ScriptFunction::Ptr func = new ScriptFunction(boost::bind(&Expression::FunctionWrapper, _1, m_Args, m_Expression, context));
-
-       if (!m_Name.IsEmpty())
-               ScriptFunction::Register(m_Name, func);
-
-       return func;
-}
-
-static void InvokeSlot(const Value& funcName, const std::vector<Value>& arguments)
-{
-       ScriptFunction::Ptr func;
-
-       if (funcName.IsObjectType<ScriptFunction>())
-               func = funcName;
-       else
-               func = ScriptFunction::GetByName(funcName);
-
-       if (!func)
-               BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist."));
-
-       func->Invoke(arguments);
+       return VMOps::NewFunction(context, m_Name, m_Args, m_Expression);
 }
 
 Value SlotExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
 {
-       ScriptSignal::Ptr sig = ScriptSignal::GetByName(m_Signal);
-
-       if (!sig)
-               BOOST_THROW_EXCEPTION(ConfigError("Signal '" + m_Signal + "' does not exist."));
-
-       sig->AddSlot(boost::bind(InvokeSlot, m_Slot->Evaluate(context), _1));
-
-       return Empty;
+       return VMOps::NewSlot(context, m_Signal, m_Slot->Evaluate(context));
 }
 
 Value ApplyExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
 {
-       String name = m_Name->Evaluate(context, dhint);
-
-       ApplyRule::AddRule(m_Type, m_Target, name, m_Expression, m_Filter, m_FKVar, m_FVVar, m_FTerm, m_DebugInfo, context);
-
-       return Empty;
+       return VMOps::NewApply(context, m_Type, m_Target, m_Name->Evaluate(context), m_Filter, m_FKVar, m_FVVar, m_FTerm, m_Expression, m_DebugInfo);
 }
 
 Value ObjectExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
@@ -471,150 +367,14 @@ Value ObjectExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint)
        if (m_Name)
                name = m_Name->Evaluate(context, dhint);
 
-       ConfigItemBuilder::Ptr item = new ConfigItemBuilder(m_DebugInfo);
-
-       String checkName = name;
-
-       if (!m_Abstract) {
-               Type::Ptr ptype = Type::GetByName(m_Type);
-
-               NameComposer *nc = dynamic_cast<NameComposer *>(ptype.get());
-
-               if (nc)
-                       checkName = nc->MakeName(name, Dictionary::Ptr());
-       }
-
-       if (!checkName.IsEmpty()) {
-               ConfigItem::Ptr oldItem = ConfigItem::GetObject(m_Type, checkName);
-
-               if (oldItem) {
-                       std::ostringstream msgbuf;
-                       msgbuf << "Object '" << name << "' of type '" << m_Type << "' re-defined: " << m_DebugInfo << "; previous definition: " << oldItem->GetDebugInfo();
-                       BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str()) << errinfo_debuginfo(m_DebugInfo));
-               }
-       }
-
-       item->SetType(m_Type);
-
-       if (name.FindFirstOf("!") != String::NPos) {
-               std::ostringstream msgbuf;
-               msgbuf << "Name for object '" << name << "' of type '" << m_Type << "' is invalid: Object names may not contain '!'";
-               BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str()) << errinfo_debuginfo(m_DebugInfo));
-       }
-
-       item->SetName(name);
-
-       item->AddExpression(new OwnedExpression(m_Expression));
-       item->SetAbstract(m_Abstract);
-       item->SetScope(context);
-       item->SetZone(m_Zone);
-       item->SetFilter(m_Filter);
-
-       item->Compile()->Register();
-
-       return Empty;
+       return VMOps::NewObject(context, m_Abstract, m_Type, name, m_Filter, m_Zone,
+           m_Expression, m_DebugInfo);
 }
 
 Value ForExpression::DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
 {
        Value value = m_Value->Evaluate(context, dhint);
 
-       if (value.IsObjectType<Array>()) {
-               if (!m_FVVar.IsEmpty())
-                       BOOST_THROW_EXCEPTION(ConfigError("Cannot use dictionary iterator for array.") << errinfo_debuginfo(m_DebugInfo));
-
-               Array::Ptr arr = value;
-
-               ObjectLock olock(arr);
-               BOOST_FOREACH(const Value& value, arr) {
-                       Dictionary::Ptr xcontext = new Dictionary();
-                       xcontext->Set("__parent", context);
-                       xcontext->Set(m_FKVar, value);
-
-                       m_Expression->Evaluate(xcontext, dhint);
-               }
-       } else if (value.IsObjectType<Dictionary>()) {
-               if (m_FVVar.IsEmpty())
-                       BOOST_THROW_EXCEPTION(ConfigError("Cannot use array iterator for dictionary.") << errinfo_debuginfo(m_DebugInfo));
-
-               Dictionary::Ptr dict = value;
-
-               ObjectLock olock(dict);
-               BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
-                       Dictionary::Ptr xcontext = new Dictionary();
-                       xcontext->Set("__parent", context);
-                       xcontext->Set(m_FKVar, kv.first);
-                       xcontext->Set(m_FVVar, kv.second);
-
-                       m_Expression->Evaluate(xcontext, dhint);
-               }
-       } else
-               BOOST_THROW_EXCEPTION(ConfigError("Invalid type in __for expression: " + value.GetTypeName()) << errinfo_debuginfo(m_DebugInfo));
-
-       return Empty;
-}
-
-bool Expression::HasField(const Object::Ptr& context, const String& field)
-{
-       Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(context);
-
-       if (dict)
-               return dict->Contains(field);
-       else {
-               Type::Ptr type = context->GetReflectionType();
-
-               if (!type)
-                       return false;
-
-               return type->GetFieldId(field) != -1;
-       }
-}
-
-Value Expression::GetField(const Object::Ptr& context, const String& field)
-{
-       Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(context);
-
-       if (dict)
-               return dict->Get(field);
-       else {
-               Type::Ptr type = context->GetReflectionType();
-
-               if (!type)
-                       return Empty;
-
-               int fid = type->GetFieldId(field);
-
-               if (fid == -1)
-                       return Empty;
-
-               return context->GetField(fid);
-       }
-}
-
-void Expression::SetField(const Object::Ptr& context, const String& field, const Value& value)
-{
-       Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(context);
-
-       if (dict)
-               dict->Set(field, value);
-       else {
-               Type::Ptr type = context->GetReflectionType();
-
-               if (!type)
-                       BOOST_THROW_EXCEPTION(ConfigError("Cannot set field on object."));
-
-               int fid = type->GetFieldId(field);
-
-               if (fid == -1)
-                       BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' does not exist."));
-
-               try {
-                       context->SetField(fid, value);
-               } catch (const boost::bad_lexical_cast&) {
-                       BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'"));
-               } catch (const std::bad_cast&) {
-                       BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'"));
-               }
-       }
+       return VMOps::For(context, m_FKVar, m_FVVar, m_Value->Evaluate(context), m_Expression, m_DebugInfo);
 }
 
index 1411b070db283ffac0d1de6cede922bb35f8d6b7..709acc9c86ca9b6878cc2388bf6279d920aac605 100644 (file)
 #include "base/debuginfo.hpp"
 #include "base/array.hpp"
 #include "base/dictionary.hpp"
+#include "base/scriptfunction.hpp"
+#include "base/configerror.hpp"
+#include "base/convert.hpp"
 #include <boost/foreach.hpp>
+#include <map>
 
 namespace icinga
 {
@@ -96,6 +100,8 @@ enum CombinedSetOp
        OpSetDivide
 };
 
+typedef std::map<String, String> DefinitionMap;
+
 /**
  * @ingroup config
  */
@@ -107,16 +113,8 @@ public:
        Value Evaluate(const Object::Ptr& context, DebugHint *dhint = NULL) const;
 
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const = 0;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fp) const = 0;
        virtual const DebugInfo& GetDebugInfo(void) const;
-
-public:
-       static Value FunctionWrapper(const std::vector<Value>& arguments,
-           const std::vector<String>& funcargs,
-           const boost::shared_ptr<Expression>& expr, const Object::Ptr& scope);
-
-       static bool HasField(const Object::Ptr& context, const String& field);
-       static Value GetField(const Object::Ptr& context, const String& field);
-       static void SetField(const Object::Ptr& context, const String& field, const Value& value);
 };
 
 I2_CONFIG_API std::vector<Expression *> MakeIndexer(const String& index1);
@@ -134,6 +132,11 @@ protected:
                return m_Expression->DoEvaluate(context, dhint);
        }
 
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+       {
+               return m_Expression->GenerateCode(definitions, fp);
+       }
+
        virtual const DebugInfo& GetDebugInfo(void) const
        {
                return m_Expression->GetDebugInfo();
@@ -143,6 +146,30 @@ private:
        boost::shared_ptr<Expression> m_Expression;
 };
 
+class I2_CONFIG_API NativeExpression : public Expression
+{
+public:
+       typedef Value (*Callback)(const Object::Ptr& context);
+
+       NativeExpression(Callback callback)
+               : m_Callback(callback)
+       { }
+
+protected:
+       virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const
+       {
+               return m_Callback(context);
+       }
+
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fp) const
+       {
+               throw std::runtime_error("Native expression does not support codegen.");
+       }
+
+private:
+       Callback m_Callback;
+};
+
 class I2_CONFIG_API LiteralExpression : public Expression
 {
 public:
@@ -150,6 +177,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fp) const;
 
 private:
        Value m_Value;
@@ -217,6 +245,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 private:
        String m_Variable;
@@ -231,6 +260,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API LogicalNegateExpression : public UnaryExpression
@@ -242,6 +272,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
 
 class I2_CONFIG_API AddExpression : public BinaryExpression
@@ -253,6 +284,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API SubtractExpression : public BinaryExpression
@@ -264,6 +296,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API MultiplyExpression : public BinaryExpression
@@ -275,6 +308,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API DivideExpression : public BinaryExpression
@@ -286,6 +320,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API BinaryAndExpression : public BinaryExpression
@@ -297,6 +332,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API BinaryOrExpression : public BinaryExpression
@@ -308,6 +344,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API ShiftLeftExpression : public BinaryExpression
@@ -319,6 +356,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API ShiftRightExpression : public BinaryExpression
@@ -330,6 +368,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API EqualExpression : public BinaryExpression
@@ -341,6 +380,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API NotEqualExpression : public BinaryExpression
@@ -352,6 +392,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API LessThanExpression : public BinaryExpression
@@ -363,6 +404,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API GreaterThanExpression : public BinaryExpression
@@ -374,6 +416,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API LessThanOrEqualExpression : public BinaryExpression
@@ -385,6 +428,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API GreaterThanOrEqualExpression : public BinaryExpression
@@ -396,6 +440,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API InExpression : public BinaryExpression
@@ -407,6 +452,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API NotInExpression : public BinaryExpression
@@ -418,6 +464,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API LogicalAndExpression : public BinaryExpression
@@ -429,6 +476,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API LogicalOrExpression : public BinaryExpression
@@ -440,6 +488,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
        
 class I2_CONFIG_API FunctionCallExpression : public DebuggableExpression
@@ -459,6 +508,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 public:
        Expression *m_FName;
@@ -480,6 +530,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 private:
        std::vector<Expression *> m_Expressions;
@@ -502,6 +553,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 private:
        std::vector<Expression *> m_Expressions;
@@ -525,6 +577,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 private:
        CombinedSetOp m_Op;
@@ -532,7 +585,7 @@ private:
        Expression *m_Operand2;
 
 };
-       
+
 class I2_CONFIG_API IndexerExpression : public BinaryExpression
 {
 public:
@@ -542,8 +595,9 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 };
-       
+
 class I2_CONFIG_API ImportExpression : public DebuggableExpression
 {
 public:
@@ -559,12 +613,15 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 private:
        Expression *m_Type;
        Expression *m_Name;
 };
 
+I2_CONFIG_API String CodeGenExpression(DefinitionMap& definitions, Expression *expression);
+
 class I2_CONFIG_API FunctionExpression : public DebuggableExpression
 {
 public:
@@ -574,6 +631,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 private:
        String m_Name;
@@ -590,6 +648,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 private:
        String m_Signal;
@@ -614,6 +673,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 private:
        String m_Type;
@@ -640,6 +700,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 private:
        bool m_Abstract;
@@ -665,6 +726,7 @@ public:
 
 protected:
        virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+       virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
 
 private:
        String m_FKVar;
diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp
new file mode 100644 (file)
index 0000000..3db6b65
--- /dev/null
@@ -0,0 +1,320 @@
+/******************************************************************************
+* Icinga 2                                                                   *
+* Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
+*                                                                            *
+* 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.             *
+******************************************************************************/
+
+#ifndef VMOPS_H
+#define VMOPS_H
+
+#include "config/i2-config.hpp"
+#include "config/expression.hpp"
+#include "config/configitembuilder.hpp"
+#include "config/applyrule.hpp"
+#include "config/objectrule.hpp"
+#include "base/debuginfo.hpp"
+#include "base/array.hpp"
+#include "base/dictionary.hpp"
+#include "base/scriptfunction.hpp"
+#include "base/scriptsignal.hpp"
+#include "base/scriptvariable.hpp"
+#include "base/configerror.hpp"
+#include "base/convert.hpp"
+#include <boost/foreach.hpp>
+#include <map>
+#include <vector>
+
+namespace icinga
+{
+
+class VMOps
+{
+public:
+       static inline Value Variable(const Object::Ptr& context, const String& name)
+       {
+               Object::Ptr scope = context;
+
+               while (scope) {
+                       if (HasField(scope, name))
+                               return GetField(scope, name);
+
+                       scope = GetField(scope, "__parent");
+               }
+
+               return ScriptVariable::Get(name);
+       }
+
+       static inline Value FunctionCall(const Object::Ptr& context, const Value& funcName, const std::vector<Value>& arguments)
+       {
+               ScriptFunction::Ptr func;
+
+               if (funcName.IsObjectType<ScriptFunction>())
+                       func = funcName;
+               else
+                       func = ScriptFunction::GetByName(funcName);
+
+               if (!func)
+                       BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist."));
+
+               return func->Invoke(arguments);
+       }
+
+       static inline Value Indexer(const Object::Ptr& context, const Value& value, const String& index)
+       {
+               if (value.IsObjectType<Dictionary>()) {
+                       Dictionary::Ptr dict = value;
+                       return dict->Get(index);
+               } else if (value.IsObjectType<Array>()) {
+                       Array::Ptr arr = value;
+                       return arr->Get(Convert::ToLong(index));
+               } else if (value.IsObject()) {
+                       Object::Ptr object = value;
+                       Type::Ptr type = object->GetReflectionType();
+
+                       if (!type)
+                               BOOST_THROW_EXCEPTION(ConfigError("Dot operator applied to object which does not support reflection"));
+
+                       int field = type->GetFieldId(index);
+
+                       if (field == -1)
+                               BOOST_THROW_EXCEPTION(ConfigError("Tried to access invalid property '" + index + "'"));
+
+                       return object->GetField(field);
+               } else if (value.IsEmpty()) {
+                       return Empty;
+               } else {
+                       BOOST_THROW_EXCEPTION(ConfigError("Dot operator cannot be applied to type '" + value.GetTypeName() + "'"));
+               }
+       }
+
+       static inline Value NewFunction(const Object::Ptr& context, const String& name, const std::vector<String>& args, const boost::shared_ptr<Expression>& expression)
+       {
+               ScriptFunction::Ptr func = new ScriptFunction(boost::bind(&FunctionWrapper, _1, args, expression, context));
+
+               if (!name.IsEmpty())
+                       ScriptFunction::Register(name, func);
+
+               return func;
+       }
+
+       static inline Value NewSlot(const Object::Ptr& context, const String& signal, const Value& slot)
+       {
+               ScriptSignal::Ptr sig = ScriptSignal::GetByName(signal);
+
+               if (!sig)
+                       BOOST_THROW_EXCEPTION(ConfigError("Signal '" + signal + "' does not exist."));
+
+               sig->AddSlot(boost::bind(SlotWrapper, slot, _1));
+
+               return Empty;
+       }
+
+       static inline Value NewApply(const Object::Ptr& context, const String& type, const String& target, const String& name, const boost::shared_ptr<Expression>& filter,
+               const String& fkvar, const String& fvvar, const boost::shared_ptr<Expression>& fterm,
+               const boost::shared_ptr<Expression>& expression, const DebugInfo& debugInfo = DebugInfo())
+       {
+               ApplyRule::AddRule(type, target, name, expression, filter, fkvar, fvvar, fterm, debugInfo, context);
+
+               return Empty;
+       }
+
+       static inline Value NewObject(const Object::Ptr& context, bool abstract, const String& type, const String& name, const boost::shared_ptr<Expression>& filter,
+               const String& zone, const boost::shared_ptr<Expression>& expression, const DebugInfo& debugInfo = DebugInfo())
+       {
+               ConfigItemBuilder::Ptr item = new ConfigItemBuilder(debugInfo);
+
+               String checkName = name;
+
+               if (!abstract) {
+                       Type::Ptr ptype = Type::GetByName(type);
+
+                       NameComposer *nc = dynamic_cast<NameComposer *>(ptype.get());
+
+                       if (nc)
+                               checkName = nc->MakeName(name, Dictionary::Ptr());
+               }
+
+               if (!checkName.IsEmpty()) {
+                       ConfigItem::Ptr oldItem = ConfigItem::GetObject(type, checkName);
+
+                       if (oldItem) {
+                               std::ostringstream msgbuf;
+                               msgbuf << "Object '" << name << "' of type '" << type << "' re-defined: " << debugInfo << "; previous definition: " << oldItem->GetDebugInfo();
+                               BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str()) << errinfo_debuginfo(debugInfo));
+                       }
+               }
+
+               item->SetType(type);
+
+               if (name.FindFirstOf("!") != String::NPos) {
+                       std::ostringstream msgbuf;
+                       msgbuf << "Name for object '" << name << "' of type '" << type << "' is invalid: Object names may not contain '!'";
+                       BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str()) << errinfo_debuginfo(debugInfo));
+               }
+
+               item->SetName(name);
+
+               item->AddExpression(new OwnedExpression(expression));
+               item->SetAbstract(abstract);
+               item->SetScope(context);
+               item->SetZone(zone);
+               item->Compile()->Register();
+
+               if (filter)
+                       ObjectRule::AddRule(type, name, filter, debugInfo, context);
+
+               return Empty;
+       }
+
+       static inline Value For(const Object::Ptr& context, const String& fkvar, const String& fvvar, const Value& value, Expression *expression, const DebugInfo& debugInfo = DebugInfo())
+       {
+               if (value.IsObjectType<Array>()) {
+                       if (!fvvar.IsEmpty())
+                               BOOST_THROW_EXCEPTION(ConfigError("Cannot use dictionary iterator for array.") << errinfo_debuginfo(debugInfo));
+
+                       Array::Ptr arr = value;
+
+                       ObjectLock olock(arr);
+                       BOOST_FOREACH(const Value& value, arr) {
+                               Dictionary::Ptr xcontext = new Dictionary();
+                               xcontext->Set("__parent", context);
+                               xcontext->Set(fkvar, value);
+
+                               expression->Evaluate(xcontext);
+                       }
+               }
+               else if (value.IsObjectType<Dictionary>()) {
+                       if (fvvar.IsEmpty())
+                               BOOST_THROW_EXCEPTION(ConfigError("Cannot use array iterator for dictionary.") << errinfo_debuginfo(debugInfo));
+
+                       Dictionary::Ptr dict = value;
+
+                       ObjectLock olock(dict);
+                       BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
+                               Dictionary::Ptr xcontext = new Dictionary();
+                               xcontext->Set("__parent", context);
+                               xcontext->Set(fkvar, kv.first);
+                               xcontext->Set(fvvar, kv.second);
+
+                               expression->Evaluate(xcontext);
+                       }
+               }
+               else
+                       BOOST_THROW_EXCEPTION(ConfigError("Invalid type in __for expression: " + value.GetTypeName()) << errinfo_debuginfo(debugInfo));
+
+               return Empty;
+       }
+
+       static inline bool HasField(const Object::Ptr& context, const String& field)
+       {
+               Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(context);
+
+               if (dict)
+                       return dict->Contains(field);
+               else {
+                       Type::Ptr type = context->GetReflectionType();
+
+                       if (!type)
+                               return false;
+
+                       return type->GetFieldId(field) != -1;
+               }
+       }
+
+       static inline Value GetField(const Object::Ptr& context, const String& field)
+       {
+               Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(context);
+
+               if (dict)
+                       return dict->Get(field);
+               else {
+                       Type::Ptr type = context->GetReflectionType();
+
+                       if (!type)
+                               return Empty;
+
+                       int fid = type->GetFieldId(field);
+
+                       if (fid == -1)
+                               return Empty;
+
+                       return context->GetField(fid);
+               }
+       }
+
+       static inline void SetField(const Object::Ptr& context, const String& field, const Value& value)
+       {
+               Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(context);
+
+               if (dict)
+                       dict->Set(field, value);
+               else {
+                       Type::Ptr type = context->GetReflectionType();
+
+                       if (!type)
+                               BOOST_THROW_EXCEPTION(ConfigError("Cannot set field on object."));
+
+                       int fid = type->GetFieldId(field);
+
+                       if (fid == -1)
+                               BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' does not exist."));
+
+                       try {
+                               context->SetField(fid, value);
+                       } catch (const boost::bad_lexical_cast&) {
+                               BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'"));
+                       } catch (const std::bad_cast&) {
+                               BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'"));
+                       }
+               }
+       }
+
+private:
+       static inline Value FunctionWrapper(const std::vector<Value>& arguments,
+           const std::vector<String>& funcargs, const boost::shared_ptr<Expression>& expr, const Object::Ptr& scope)
+       {
+               if (arguments.size() < funcargs.size())
+                       BOOST_THROW_EXCEPTION(ConfigError("Too few arguments for function"));
+
+               Dictionary::Ptr context = new Dictionary();
+               context->Set("__parent", scope);
+
+               for (std::vector<Value>::size_type i = 0; i < std::min(arguments.size(), funcargs.size()); i++)
+                       context->Set(funcargs[i], arguments[i]);
+
+               expr->Evaluate(context);
+               return context->Get("__result");
+       }
+
+       static void SlotWrapper(const Value& funcName, const std::vector<Value>& arguments)
+       {
+               ScriptFunction::Ptr func;
+
+               if (funcName.IsObjectType<ScriptFunction>())
+                       func = funcName;
+               else
+                       func = ScriptFunction::GetByName(funcName);
+
+               if (!func)
+                       BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist."));
+
+               func->Invoke(arguments);
+       }
+};
+
+}
+
+#endif /* VMOPS_H */