# 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
--- /dev/null
+/******************************************************************************
+ * 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;
+}
--- /dev/null
+/******************************************************************************
+ * 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 */
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)
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. */
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();
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)
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();
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())
| 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);
}
;
$$ = 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));
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.
*
* @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;
}
}
- 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);
}
/**
* @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();
}
/**
* @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 + "'");
* @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);
#define CONFIGCOMPILER_H
#include "config/i2-config.hpp"
+#include "config/expression.hpp"
#include "base/debuginfo.hpp"
#include "base/registry.hpp"
#include "base/initialize.hpp"
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);
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);
#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"
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,
--- /dev/null
+/******************************************************************************
+ * 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();
+}
#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;
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
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);
}
{
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
Object::Ptr acontext = m_Inline ? context : result;
aexpr->Evaluate(acontext, dhint);
- if (HasField(acontext, "__result"))
+ if (VMOps::HasField(acontext, "__result"))
break;
}
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);
}
}
}
}
- SetField(parent, index, right);
+ VMOps::SetField(parent, index, right);
if (psdhint)
psdhint->AddMessage("=", m_DebugInfo);
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
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
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);
}
#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
{
OpSetDivide
};
+typedef std::map<String, String> DefinitionMap;
+
/**
* @ingroup config
*/
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);
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();
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:
protected:
virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+ virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fp) const;
private:
Value m_Value;
protected:
virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+ virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
private:
String m_Variable;
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
protected:
virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+ virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
public:
Expression *m_FName;
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;
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;
protected:
virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+ virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
private:
CombinedSetOp m_Op;
Expression *m_Operand2;
};
-
+
class I2_CONFIG_API IndexerExpression : public BinaryExpression
{
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:
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:
protected:
virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+ virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
private:
String m_Name;
protected:
virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+ virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
private:
String m_Signal;
protected:
virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+ virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
private:
String m_Type;
protected:
virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+ virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
private:
bool m_Abstract;
protected:
virtual Value DoEvaluate(const Object::Ptr& context, DebugHint *dhint) const;
+ virtual void GenerateCode(DefinitionMap& definitions, std::ostream& fpg) const;
private:
String m_FKVar;
--- /dev/null
+/******************************************************************************
+* 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 */