diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 111e3c1..1556f21 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -496,28 +496,24 @@ namespace chaiscript } } - /** - * Swaps out the stack with a new stack - * \returns the old stack - * \param[in] s The new stack - */ - Stack set_stack(const Stack &s) - { - Stack old = m_stack_holder->stack; - m_stack_holder->stack = s; - return old; - } - Stack new_stack() const + /// Pushes a new stack on to the list of stacks + void new_stack() { Stack s(new Stack::element_type()); s->push_back(Scope()); - return s; + m_stack_holder->stacks.push_back(s); } + void pop_stack() + { + m_stack_holder->stacks.pop_back(); + } + + /// \returns the current stack Stack get_stack() const { - return m_stack_holder->stack; + return m_stack_holder->stacks.back(); } /** @@ -566,8 +562,8 @@ namespace chaiscript if (funcs.size() == 1) { // Return the first item if there is only one, - // no reason to take the cast of the extra level of dispatch - return const_var(*funcs.begin()); + // no reason to take the cost of the extra level of dispatch + return const_var(funcs.front()); } else { return Boxed_Value(Const_Proxy_Function(new Dispatch_Function(funcs))); } @@ -668,6 +664,66 @@ namespace chaiscript return functions.find(name) != functions.end(); } + + /// + /// Get a map of all objects that can be seen from the current scope in a scripting context + /// + std::map get_scripting_objects() const + { + // We don't want the current context, but one up if it exists + StackData &stack = (m_stack_holder->stacks.size()==1)?(*(m_stack_holder->stacks.back())):(*m_stack_holder->stacks[m_stack_holder->stacks.size()-2]); + + std::map retval; + + // note: map insert doesn't overwrite existing values, which is why this works + + for (StackData::reverse_iterator itr = stack.rbegin(); itr != stack.rend(); ++itr) + { + retval.insert(itr->begin(), itr->end()); + } + + // add the global values + { + chaiscript::detail::threading::shared_lock l(m_global_object_mutex); + + retval.insert(m_state.m_global_objects.begin(), m_state.m_global_objects.end()); + } + + return retval; + } + + + /// + /// Get a map of all functions that can be seen from a scripting context + /// + std::map get_scripting_functions() const + { + chaiscript::detail::threading::shared_lock l(m_mutex); + + std::vector > rets; + + const std::map > &functions = get_functions_int(); + + std::map retval; + + for (std::map >::const_iterator itr = functions.begin(); + itr != functions.end(); + ++itr) + { + if (itr->second.size() == 1) + { + // Return the first item if there is only one, + // no reason to take the cost of the extra level of dispatch + retval.insert(std::make_pair(itr->first, const_var(itr->second.front()))); + } else { + retval.insert(std::make_pair(itr->first, Boxed_Value(Const_Proxy_Function(new Dispatch_Function(itr->second))))); + } + } + + return retval; + } + + /** * Get a vector of all registered functions */ @@ -854,7 +910,7 @@ namespace chaiscript */ StackData &get_stack_data() const { - return *(m_stack_holder->stack); + return *(m_stack_holder->stacks.back()); } const std::map > &get_functions_int() const @@ -1016,12 +1072,13 @@ namespace chaiscript struct Stack_Holder { Stack_Holder() - : stack(new StackData()) { - stack->push_back(Scope()); + Stack s(new StackData()); + s->push_back(Scope()); + stacks.push_back(s); } - Stack stack; + std::deque stacks; }; std::vector m_conversions; diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 02b79cf..23f3b9c 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -322,6 +322,29 @@ namespace chaiscript chaiscript::detail::Dispatch_Engine &m_de; }; + + /// Creates a new scope then pops it on destruction + struct Stack_Push_Pop + { + Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de) + : m_de(t_de) + { + m_de.new_stack(); + } + + ~Stack_Push_Pop() + { + m_de.pop_stack(); + } + + + private: + // explicitly unimplemented copy and assignment + Stack_Push_Pop(const Scope_Push_Pop &); + Stack_Push_Pop& operator=(const Scope_Push_Pop &); + + chaiscript::detail::Dispatch_Engine &m_de; + }; } } } diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index b4a5708..db3254e 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -324,6 +324,8 @@ namespace chaiscript m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::is_type, std::ref(m_engine)), "is_type"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::type_name, std::ref(m_engine)), "type_name"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists"); + m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_functions, std::ref(m_engine)), "get_functions"); + m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects"); m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name"); diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index f2e908d..3775c2d 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -191,36 +191,28 @@ namespace chaiscript } } - chaiscript::detail::Dispatch_Engine::Stack prev_stack = t_ss.get_stack(); - chaiscript::detail::Dispatch_Engine::Stack new_stack = t_ss.new_stack(); try { Boxed_Value fn = this->children[0]->eval(t_ss); try { - t_ss.set_stack(new_stack); + chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); const Boxed_Value &retval = (*boxed_cast(fn))(params); - t_ss.set_stack(prev_stack); return retval; } catch(const exception::dispatch_error &e){ - t_ss.set_stack(prev_stack); throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, t_ss); } catch(detail::Return_Value &rv) { - t_ss.set_stack(prev_stack); return rv.retval; } - catch(...) { - t_ss.set_stack(prev_stack); - throw; - } } - catch(exception::eval_error &) { - t_ss.set_stack(prev_stack); - throw; + catch(const exception::dispatch_error &e){ + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + } + catch(detail::Return_Value &rv) { + return rv.retval; } - } }; @@ -485,26 +477,17 @@ namespace chaiscript fun_name = this->children[i]->text; } - chaiscript::detail::Dispatch_Engine::Stack prev_stack = t_ss.get_stack(); - chaiscript::detail::Dispatch_Engine::Stack new_stack = t_ss.new_stack(); - try { - t_ss.set_stack(new_stack); + chaiscript::eval::detail::Stack_Push_Pop spp(t_ss); retval = t_ss.call_function(fun_name, params); - t_ss.set_stack(prev_stack); } catch(const exception::dispatch_error &e){ - t_ss.set_stack(prev_stack); throw exception::eval_error(std::string(e.what()) + " for function: " + fun_name, e.parameters, t_ss); } catch(detail::Return_Value &rv) { - t_ss.set_stack(prev_stack); retval = rv.retval; } - catch(...) { - t_ss.set_stack(prev_stack); - throw; - } + if (this->children[i]->identifier == AST_Node_Type::Array_Call) { for (size_t j = 1; j < this->children[i]->children.size(); ++j) { try { diff --git a/unittests/system_introspection.chai b/unittests/system_introspection.chai new file mode 100644 index 0000000..fc7350e --- /dev/null +++ b/unittests/system_introspection.chai @@ -0,0 +1,18 @@ + +var funcs = get_functions(); + +assert_true(funcs.size() > 0); +assert_true(funcs["to_string"].get_type_info().bare_equal(Function_type)); + + +var i = 1; +var objs = get_objects(); + +assert_true(objs.size() > 0); +assert_true(objs["i"].get_type_info().bare_equal(int_type)); +assert_true(objs.count("j") == 0); + + + + +