]> granicus.if.org Git - icinga2/commitdiff
Implement support for the namespace and using keywords
authorGunnar Beutner <gunnar.beutner@icinga.com>
Tue, 7 Aug 2018 11:55:41 +0000 (13:55 +0200)
committerGunnar Beutner <gunnar.beutner@icinga.com>
Mon, 13 Aug 2018 11:44:31 +0000 (13:44 +0200)
lib/base/configwriter.cpp
lib/base/scriptframe.cpp
lib/base/scriptframe.hpp
lib/config/config_lexer.ll
lib/config/config_parser.yy
lib/config/configcompiler.cpp
lib/config/configcompiler.hpp
lib/config/expression.cpp
lib/config/expression.hpp
lib/config/vmops.hpp
lib/remote/consolehandler.cpp

index 58851c2cfcc6f5192d97a4ed7d49b45b7889ef8b..a085be915c71d0d184dcd5eae06ca87668d538ee 100644 (file)
@@ -239,7 +239,8 @@ const std::vector<String>& ConfigWriter::GetKeywords()
                keywords.emplace_back("globals");
                keywords.emplace_back("locals");
                keywords.emplace_back("use");
-               keywords.emplace_back("__using");
+               keywords.emplace_back("using");
+               keywords.emplace_back("namespace");
                keywords.emplace_back("default");
                keywords.emplace_back("ignore_on_error");
                keywords.emplace_back("current_filename");
index 65597a7835658cd39546669f411b153edc0c0cc5..01f871ec4d73b1b0576672a450d7485e4c58ff99 100644 (file)
 
 #include "base/scriptframe.hpp"
 #include "base/scriptglobal.hpp"
+#include "base/namespace.hpp"
 #include "base/exception.hpp"
 
 using namespace icinga;
 
 boost::thread_specific_ptr<std::stack<ScriptFrame *> > ScriptFrame::m_ScriptFrames;
-Array::Ptr ScriptFrame::m_Imports;
+
+static auto l_InternalNSBehavior = new ConstNamespaceBehavior();
 
 INITIALIZE_ONCE_WITH_PRIORITY([]() {
-       Dictionary::Ptr systemNS = new Dictionary();
-       ScriptGlobal::Set("System", systemNS);
-       ScriptFrame::AddImport(systemNS);
+       Namespace::Ptr globalNS = ScriptGlobal::GetGlobals();
+
+       auto systemNSBehavior = new ConstNamespaceBehavior();
+       systemNSBehavior->Freeze();
+       Namespace::Ptr systemNS = new Namespace(systemNSBehavior);
+       globalNS->SetAttribute("System", std::make_shared<ConstEmbeddedNamespaceValue>(systemNS));
 
-       Dictionary::Ptr typesNS = new Dictionary();
-       ScriptGlobal::Set("Types", typesNS);
-       ScriptFrame::AddImport(typesNS);
+       auto typesNSBehavior = new ConstNamespaceBehavior();
+       typesNSBehavior->Freeze();
+       Namespace::Ptr typesNS = new Namespace(typesNSBehavior);
+       globalNS->SetAttribute("Types", std::make_shared<ConstEmbeddedNamespaceValue>(typesNS));
 
-       Dictionary::Ptr deprecatedNS = new Dictionary();
-       ScriptGlobal::Set("Deprecated", deprecatedNS);
-       ScriptFrame::AddImport(deprecatedNS);
+       auto statsNSBehavior = new ConstNamespaceBehavior();
+       statsNSBehavior->Freeze();
+       Namespace::Ptr statsNS = new Namespace(statsNSBehavior);
+       globalNS->SetAttribute("StatsFunctions", std::make_shared<ConstEmbeddedNamespaceValue>(statsNS));
+
+       Namespace::Ptr internalNS = new Namespace(l_InternalNSBehavior);
+       globalNS->SetAttribute("Internal", std::make_shared<ConstEmbeddedNamespaceValue>(internalNS));
 }, 50);
 
+INITIALIZE_ONCE_WITH_PRIORITY([]() {
+       l_InternalNSBehavior->Freeze();
+}, 0);
+
 ScriptFrame::ScriptFrame(bool allocLocals)
        : Locals(allocLocals ? new Dictionary() : nullptr), Self(ScriptGlobal::GetGlobals()), Sandboxed(false), Depth(0)
 {
@@ -120,23 +134,3 @@ void ScriptFrame::PushFrame(ScriptFrame *frame)
 
        frames->push(frame);
 }
-
-Array::Ptr ScriptFrame::GetImports()
-{
-       return m_Imports;
-}
-
-void ScriptFrame::AddImport(const Object::Ptr& import)
-{
-       Array::Ptr imports;
-
-       if (!m_Imports)
-               imports = new Array();
-       else
-               imports = m_Imports->ShallowClone();
-
-       imports->Add(import);
-
-       m_Imports = imports;
-}
-
index 16a6592f503212a5f214c857d03ec07d6a83cec7..56ff4f9223bfda4c0c25346f4d614fdc7cca9790 100644 (file)
@@ -45,12 +45,8 @@ struct ScriptFrame
 
        static ScriptFrame *GetCurrentFrame();
 
-       static Array::Ptr GetImports();
-       static void AddImport(const Object::Ptr& import);
-
 private:
        static boost::thread_specific_ptr<std::stack<ScriptFrame *> > m_ScriptFrames;
-       static Array::Ptr m_Imports;
 
        static void PushFrame(ScriptFrame *frame);
        static ScriptFrame *PopFrame();
index 6a2d8402723ace1a0eb5677ec06466fc8d7a7312..899280ff77338c114c290571c474927e15a53f3d 100644 (file)
@@ -180,7 +180,7 @@ this                                return T_THIS;
 globals                                return T_GLOBALS;
 locals                         return T_LOCALS;
 use                            return T_USE;
-__using                                return T_USING;
+using                          return T_USING;
 apply                          return T_APPLY;
 default                                return T_DEFAULT;
 to                             return T_TO;
@@ -203,6 +203,7 @@ ignore_on_error                     return T_IGNORE_ON_ERROR;
 current_filename               return T_CURRENT_FILENAME;
 current_line                   return T_CURRENT_LINE;
 debugger                       return T_DEBUGGER;
+namespace                      return T_NAMESPACE;
 =\>                            return T_FOLLOWS;
 \<\<                           return T_SHIFT_LEFT;
 \>\>                           return T_SHIFT_RIGHT;
index 889d144d3429bb24d8695f48f6cee0ce12ddc88b..5db8f5598e3878d5227c9dd3f5f7d4c8650956a2 100644 (file)
@@ -149,8 +149,9 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
 %token T_CURRENT_FILENAME "current_filename (T_CURRENT_FILENAME)"
 %token T_CURRENT_LINE "current_line (T_CURRENT_LINE)"
 %token T_DEBUGGER "debugger (T_DEBUGGER)"
+%token T_NAMESPACE "namespace (T_NAMESPACE)"
 %token T_USE "use (T_USE)"
-%token T_USING "__using (T_USING)"
+%token T_USING "using (T_USING)"
 %token T_OBJECT "object (T_OBJECT)"
 %token T_TEMPLATE "template (T_TEMPLATE)"
 %token T_INCLUDE "include (T_INCLUDE)"
@@ -602,9 +603,23 @@ lterm: T_LIBRARY rterm
        {
                $$ = new BreakpointExpression(@$);
        }
+       | T_NAMESPACE rterm
+       {
+               BeginFlowControlBlock(context, FlowControlReturn, false);
+       }
+       rterm_scope_require_side_effect
+       {
+               EndFlowControlBlock(context);
+
+               std::unique_ptr<Expression> expr{$2};
+               BindToScope(expr, ScopeGlobal);
+               $$ = new SetExpression(std::move(expr), OpSetLiteral, std::unique_ptr<Expression>(new NamespaceExpression(std::unique_ptr<Expression>($4), @$)), @$);
+       }
        | T_USING rterm
        {
-               $$ = new UsingExpression(std::unique_ptr<Expression>($2), @$);
+               std::shared_ptr<Expression> expr{$2};
+               context->AddImport(expr);
+               $$ = MakeLiteralRaw();
        }
        | apply
        | object
@@ -879,7 +894,7 @@ rterm_no_side_effect_no_dict: T_STRING
        }
        | T_IDENTIFIER
        {
-               $$ = new VariableExpression(*$1, @1);
+               $$ = new VariableExpression(*$1, context->GetImports(), @1);
                delete $1;
        }
        | T_MULTIPLY rterm %prec DEREF_OP
@@ -1105,7 +1120,7 @@ use_specifier_items: use_specifier_item
 
 use_specifier_item: identifier
        {
-               $$ = new std::pair<String, std::unique_ptr<Expression> >(*$1, std::unique_ptr<Expression>(new VariableExpression(*$1, @1)));
+               $$ = new std::pair<String, std::unique_ptr<Expression> >(*$1, std::unique_ptr<Expression>(new VariableExpression(*$1, context->GetImports(), @1)));
                delete $1;
        }
        | identifier T_SET rterm
index f8b754bb9f250017d37ef7515fd748f395620ab1..05db34e027cbc92bffd60250d2665ebfe0099e7f 100644 (file)
@@ -361,3 +361,12 @@ bool ConfigCompiler::IsAbsolutePath(const String& path)
 #endif /* _WIN32 */
 }
 
+void ConfigCompiler::AddImport(const std::shared_ptr<Expression>& import)
+{
+       m_Imports.push_back(import);
+}
+
+std::vector<std::shared_ptr<Expression> > ConfigCompiler::GetImports() const
+{
+       return m_Imports;
+}
index d4a03681efa413679d83e06f22036b850faa8073..4bbc5c0835c1c2ac8df2b278cccd86b344ed31c5 100644 (file)
@@ -109,6 +109,9 @@ public:
        void SetPackage(const String& package);
        String GetPackage() const;
 
+       void AddImport(const std::shared_ptr<Expression>& import);
+       std::vector<std::shared_ptr<Expression> > GetImports() const;
+
        static void CollectIncludes(std::vector<std::unique_ptr<Expression> >& expressions,
                const String& file, const String& zone, const String& package);
 
@@ -134,6 +137,7 @@ private:
        std::istream *m_Input;
        String m_Zone;
        String m_Package;
+       std::vector<std::shared_ptr<Expression> > m_Imports;
 
        void *m_Scanner;
 
index 9cfc44a22c4838ba9f85cf7a891011ffc95912d9..7600b130e586547ceb1b03e758734c324ef974a7 100644 (file)
@@ -117,6 +117,14 @@ const DebugInfo& DebuggableExpression::GetDebugInfo() const
        return m_DebugInfo;
 }
 
+VariableExpression::VariableExpression(String variable, std::vector<std::shared_ptr<Expression> > imports, const DebugInfo& debugInfo)
+       : DebuggableExpression(debugInfo), m_Variable(std::move(variable)), m_Imports(std::move(imports))
+{
+       m_Imports.push_back(MakeIndexer(ScopeGlobal, "System"));
+       m_Imports.push_back(MakeIndexer(ScopeGlobal, "Types"));
+       m_Imports.push_back(MakeIndexer(ScopeGlobal, "Icinga"));
+}
+
 ExpressionResult VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
 {
        Value value;
@@ -125,7 +133,7 @@ ExpressionResult VariableExpression::DoEvaluate(ScriptFrame& frame, DebugHint *d
                return value;
        else if (frame.Self.IsObject() && frame.Locals != frame.Self.Get<Object::Ptr>() && frame.Self.Get<Object::Ptr>()->GetOwnField(m_Variable, &value))
                return value;
-       else if (VMOps::FindVarImport(frame, m_Variable, &value, m_DebugInfo))
+       else if (VMOps::FindVarImport(frame, m_Imports, m_Variable, &value, m_DebugInfo))
                return value;
        else
                return ScriptGlobal::Get(m_Variable);
@@ -145,7 +153,7 @@ bool VariableExpression::GetReference(ScriptFrame& frame, bool init_dict, Value
 
                if (dhint && *dhint)
                        *dhint = new DebugHint((*dhint)->GetChild(m_Variable));
-       } else if (VMOps::FindVarImportRef(frame, m_Variable, parent, m_DebugInfo)) {
+       } else if (VMOps::FindVarImportRef(frame, m_Imports, m_Variable, parent, m_DebugInfo)) {
                return true;
        } else if (ScriptGlobal::Exists(m_Variable)) {
                *parent = ScriptGlobal::GetGlobals();
@@ -883,6 +891,17 @@ ExpressionResult ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhin
                m_Package, m_FKVar, m_FVVar, m_FTerm, m_ClosedVars, m_IgnoreOnError, m_Expression, m_DebugInfo);
 }
 
+ExpressionResult NamespaceExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
+{
+       Namespace::Ptr ns = new Namespace(new ConstNamespaceBehavior());
+
+       ScriptFrame innerFrame(true, ns);
+       ExpressionResult result = m_Expression->Evaluate(innerFrame);
+       CHECK_RESULT(result);
+
+       return ns;
+}
+
 ExpressionResult ObjectExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
 {
        if (frame.Sandboxed)
@@ -1006,23 +1025,6 @@ ExpressionResult BreakpointExpression::DoEvaluate(ScriptFrame& frame, DebugHint
        return Empty;
 }
 
-ExpressionResult UsingExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
-{
-       if (frame.Sandboxed)
-               BOOST_THROW_EXCEPTION(ScriptError("Using directives are not allowed in sandbox mode.", m_DebugInfo));
-
-       ExpressionResult importres = m_Name->Evaluate(frame);
-       CHECK_RESULT(importres);
-       Value import = importres.GetValue();
-
-       if (!import.IsObjectType<Dictionary>())
-               BOOST_THROW_EXCEPTION(ScriptError("The parameter must resolve to an object of type 'Dictionary'", m_DebugInfo));
-
-       ScriptFrame::AddImport(import);
-
-       return Empty;
-}
-
 ExpressionResult TryExceptExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
 {
        try {
index 865ded4a757641e575fe568f5d266afa5054be5e..c0fab4096fd0a2d546797ab5da1e7c88ceaed556 100644 (file)
@@ -305,9 +305,7 @@ protected:
 class VariableExpression final : public DebuggableExpression
 {
 public:
-       VariableExpression(String variable, const DebugInfo& debugInfo = DebugInfo())
-               : DebuggableExpression(debugInfo), m_Variable(std::move(variable))
-       { }
+       VariableExpression(String variable, std::vector<std::shared_ptr<Expression> > imports, const DebugInfo& debugInfo = DebugInfo());
 
        String GetVariable() const
        {
@@ -320,6 +318,7 @@ protected:
 
 private:
        String m_Variable;
+       std::vector<std::shared_ptr<Expression> > m_Imports;
 
        friend void BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec);
 };
@@ -856,6 +855,20 @@ private:
        std::shared_ptr<Expression> m_Expression;
 };
 
+class NamespaceExpression final : public DebuggableExpression
+{
+public:
+       NamespaceExpression(std::unique_ptr<Expression> expression, const DebugInfo& debugInfo = DebugInfo())
+               : DebuggableExpression(debugInfo), m_Expression(std::move(expression))
+       { }
+
+protected:
+       ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
+
+private:
+       std::shared_ptr<Expression> m_Expression;
+};
+
 class ObjectExpression final : public DebuggableExpression
 {
 public:
@@ -952,20 +965,6 @@ protected:
        ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
 };
 
-class UsingExpression final : public DebuggableExpression
-{
-public:
-       UsingExpression(std::unique_ptr<Expression> name, const DebugInfo& debugInfo = DebugInfo())
-               : DebuggableExpression(debugInfo), m_Name(std::move(name))
-       { }
-
-protected:
-       ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
-
-private:
-       std::unique_ptr<Expression> m_Name;
-};
-
 class TryExceptExpression final : public DebuggableExpression
 {
 public:
index 7bfa5628d74431da4b506d6e2f4ab601b218817a..38f8507a7624781c24f13daadbb897cddaa7e493 100644 (file)
@@ -43,15 +43,13 @@ namespace icinga
 class VMOps
 {
 public:
-       static inline bool FindVarImportRef(ScriptFrame& frame, const String& name, Value *result, const DebugInfo& debugInfo = DebugInfo())
+       static inline bool FindVarImportRef(ScriptFrame& frame, const std::vector<std::shared_ptr<Expression> >& imports, const String& name, Value *result, const DebugInfo& debugInfo = DebugInfo())
        {
-               Array::Ptr imports = ScriptFrame::GetImports();
-
-               ObjectLock olock(imports);
-               for (const Value& import : imports) {
-                       Object::Ptr obj = import;
+               for (const auto& import : imports) {
+                       ExpressionResult res = import->Evaluate(frame);
+                       Object::Ptr obj = res.GetValue();
                        if (obj->HasOwnField(name)) {
-                               *result = import;
+                               *result = obj;
                                return true;
                        }
                }
@@ -59,11 +57,11 @@ public:
                return false;
        }
 
-       static inline bool FindVarImport(ScriptFrame& frame, const String& name, Value *result, const DebugInfo& debugInfo = DebugInfo())
+       static inline bool FindVarImport(ScriptFrame& frame, const std::vector<std::shared_ptr<Expression> >& imports, const String& name, Value *result, const DebugInfo& debugInfo = DebugInfo())
        {
                Value parent;
 
-               if (FindVarImportRef(frame, name, &parent, debugInfo)) {
+               if (FindVarImportRef(frame, imports, name, &parent, debugInfo)) {
                        *result = GetField(parent, name, frame.Sandboxed, debugInfo);
                        return true;
                }
index 045cb59d5c423b51e59a830dbe0f11a85ae10bfa..aff47a9a91ec84976f14e52fdf8ea89ed715919b 100644 (file)
@@ -290,13 +290,9 @@ std::vector<String> ConsoleHandler::GetAutocompletionSuggestions(const String& w
                }
        }
 
-       {
-               Array::Ptr imports = ScriptFrame::GetImports();
-               ObjectLock olock(imports);
-               for (const Value& import : imports) {
-                       AddSuggestions(matches, word, "", false, import);
-               }
-       }
+       AddSuggestions(matches, word, "", false, ScriptGlobal::Get("System"));
+       AddSuggestions(matches, word, "", false, ScriptGlobal::Get("Types"));
+       AddSuggestions(matches, word, "", false, ScriptGlobal::Get("Icinga"));
 
        String::SizeType cperiod = word.RFind(".");