mirror of https://github.com/Icinga/icinga2.git
Implement a C++ code generator for libconfig
fixes #7699 fixes #7704 fixes #7706
This commit is contained in:
parent
0078e00c13
commit
8e265b7b7f
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -19,22 +19,14 @@
|
|||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,11 @@
|
|||
#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;
|
||||
|
|
|
@ -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 */
|
Loading…
Reference in New Issue