Change scoping mechanism for the __using keyword

refs #12408
This commit is contained in:
Gunnar Beutner 2016-08-12 13:13:01 +02:00
parent 3980cf04a0
commit 2a40a71ffa
5 changed files with 47 additions and 34 deletions

View File

@ -24,6 +24,7 @@
using namespace icinga; using namespace icinga;
boost::thread_specific_ptr<std::stack<ScriptFrame *> > ScriptFrame::m_ScriptFrames; boost::thread_specific_ptr<std::stack<ScriptFrame *> > ScriptFrame::m_ScriptFrames;
Array::Ptr ScriptFrame::m_Imports;
ScriptFrame::ScriptFrame(void) ScriptFrame::ScriptFrame(void)
: Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals()), Sandboxed(false), Depth(0) : Locals(new Dictionary()), Self(ScriptGlobal::GetGlobals()), Sandboxed(false), Depth(0)
@ -45,12 +46,6 @@ void ScriptFrame::InitializeFrame(void)
ScriptFrame *frame = frames->top(); ScriptFrame *frame = frames->top();
Sandboxed = frame->Sandboxed; Sandboxed = frame->Sandboxed;
Imports = frame->Imports;
}
if (!Imports) {
Imports = new Array();
Imports->Add(ScriptGlobal::Get("System"));
} }
PushFrame(this); PushFrame(this);
@ -111,3 +106,21 @@ void ScriptFrame::PushFrame(ScriptFrame *frame)
frames->push(frame); frames->push(frame);
} }
Array::Ptr ScriptFrame::GetImports(void)
{
if (!m_Imports) {
m_Imports = new Array();
m_Imports->Add(ScriptGlobal::Get("System"));
}
return m_Imports;
}
void ScriptFrame::AddImport(const Object::Ptr& import)
{
Array::Ptr imports = m_Imports->ShallowClone();
imports->Add(import);
m_Imports = imports;
}

View File

@ -32,7 +32,6 @@ namespace icinga
struct I2_BASE_API ScriptFrame struct I2_BASE_API ScriptFrame
{ {
Dictionary::Ptr Locals; Dictionary::Ptr Locals;
Array::Ptr Imports;
Value Self; Value Self;
bool Sandboxed; bool Sandboxed;
int Depth; int Depth;
@ -46,8 +45,12 @@ struct I2_BASE_API ScriptFrame
static ScriptFrame *GetCurrentFrame(void); static ScriptFrame *GetCurrentFrame(void);
static Array::Ptr GetImports(void);
static void AddImport(const Object::Ptr& import);
private: private:
static boost::thread_specific_ptr<std::stack<ScriptFrame *> > m_ScriptFrames; static boost::thread_specific_ptr<std::stack<ScriptFrame *> > m_ScriptFrames;
static Array::Ptr m_Imports;
inline static void PushFrame(ScriptFrame *frame); inline static void PushFrame(ScriptFrame *frame);
inline static ScriptFrame *PopFrame(void); inline static ScriptFrame *PopFrame(void);

View File

@ -904,15 +904,10 @@ ExpressionResult UsingExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhin
CHECK_RESULT(importres); CHECK_RESULT(importres);
Value import = importres.GetValue(); Value import = importres.GetValue();
if (!import.IsObject()) if (!import.IsObjectType<Dictionary>())
BOOST_THROW_EXCEPTION(ScriptError("The parameter does not resolve to an object", m_DebugInfo)); BOOST_THROW_EXCEPTION(ScriptError("The parameter must resolve to an object of type 'Dictionary'", m_DebugInfo));
if (!frame.Imports) ScriptFrame::AddImport(import);
frame.Imports = new Array();
else
frame.Imports = static_pointer_cast<Array>(frame.Imports->ShallowClone());
frame.Imports->Add(import);
return Empty; return Empty;
} }

View File

@ -46,11 +46,10 @@ class VMOps
public: public:
static inline bool FindVarImportRef(ScriptFrame& frame, const String& name, Value *result, const DebugInfo& debugInfo = DebugInfo()) static inline bool FindVarImportRef(ScriptFrame& frame, const String& name, Value *result, const DebugInfo& debugInfo = DebugInfo())
{ {
if (!frame.Imports) Array::Ptr imports = ScriptFrame::GetImports();
return false;
ObjectLock olock(frame.Imports); ObjectLock olock(imports);
BOOST_FOREACH(const Value& import, frame.Imports) { BOOST_FOREACH(const Value& import, imports) {
Object::Ptr obj = import; Object::Ptr obj = import;
if (obj->HasOwnField(name)) { if (obj->HasOwnField(name)) {
*result = import; *result = import;

View File

@ -215,7 +215,7 @@ static void AddSuggestion(std::vector<String>& matches, const String& word, cons
matches.push_back(suggestion); matches.push_back(suggestion);
} }
static void AddSuggestions(std::vector<String>& matches, const String& word, const String& pword, const Value& value) static void AddSuggestions(std::vector<String>& matches, const String& word, const String& pword, bool withPrototype, const Value& value)
{ {
String prefix; String prefix;
@ -239,18 +239,20 @@ static void AddSuggestions(std::vector<String>& matches, const String& word, con
AddSuggestion(matches, word, prefix + field.Name); AddSuggestion(matches, word, prefix + field.Name);
} }
while (type) { if (withPrototype) {
Object::Ptr prototype = type->GetPrototype(); while (type) {
Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(prototype); Object::Ptr prototype = type->GetPrototype();
Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(prototype);
if (dict) { if (dict) {
ObjectLock olock(dict); ObjectLock olock(dict);
BOOST_FOREACH(const Dictionary::Pair& kv, dict) { BOOST_FOREACH(const Dictionary::Pair& kv, dict) {
AddSuggestion(matches, word, prefix + kv.first); AddSuggestion(matches, word, prefix + kv.first);
}
} }
}
type = type->GetBaseType(); type = type->GetBaseType();
}
} }
} }
@ -276,10 +278,11 @@ std::vector<String> ConsoleHandler::GetAutocompletionSuggestions(const String& w
} }
} }
if (frame.Imports) { {
ObjectLock olock(frame.Imports); Array::Ptr imports = ScriptFrame::GetImports();
BOOST_FOREACH(const Value& import, frame.Imports) { ObjectLock olock(imports);
AddSuggestions(matches, word, "", import); BOOST_FOREACH(const Value& import, imports) {
AddSuggestions(matches, word, "", false, import);
} }
} }
@ -296,7 +299,7 @@ std::vector<String> ConsoleHandler::GetAutocompletionSuggestions(const String& w
if (expr) if (expr)
value = expr->Evaluate(frame); value = expr->Evaluate(frame);
AddSuggestions(matches, word, pword, value); AddSuggestions(matches, word, pword, true, value);
} catch (...) { /* Ignore the exception */ } } catch (...) { /* Ignore the exception */ }
} }