Merge branch 'master' of github.com:ChaiScript/ChaiScript
This commit is contained in:
@@ -377,6 +377,7 @@ namespace chaiscript
|
||||
struct State
|
||||
{
|
||||
std::map<std::string, std::vector<Proxy_Function> > m_functions;
|
||||
std::map<std::string, Proxy_Function> m_function_objects;
|
||||
std::map<std::string, Boxed_Value> m_global_objects;
|
||||
Type_Name_Map m_types;
|
||||
std::set<std::string> m_reserved_words;
|
||||
@@ -414,7 +415,6 @@ namespace chaiscript
|
||||
* Set the value of an object, by name. If the object
|
||||
* is not available in the current scope it is created
|
||||
*/
|
||||
/*
|
||||
void add(const Boxed_Value &obj, const std::string &name)
|
||||
{
|
||||
validate_object_name(name);
|
||||
@@ -432,7 +432,7 @@ namespace chaiscript
|
||||
|
||||
add_object(name, obj);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Adds a named object to the current scope
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -557,21 +553,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
// If all that failed, then check to see if it's a function
|
||||
std::vector<Proxy_Function> funcs = get_function(name);
|
||||
|
||||
if (funcs.empty())
|
||||
{
|
||||
throw std::range_error("Object not known: " + name);
|
||||
} else {
|
||||
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());
|
||||
} else {
|
||||
return Boxed_Value(Const_Proxy_Function(new Dispatch_Function(funcs)));
|
||||
}
|
||||
}
|
||||
return get_function_object(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -654,9 +636,26 @@ namespace chaiscript
|
||||
} else {
|
||||
return std::vector<Proxy_Function>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// \returns a function object (Boxed_Value wrapper) if it exists
|
||||
/// \throws std::range_error if it does not
|
||||
Boxed_Value get_function_object(const std::string &t_name) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const std::map<std::string, Proxy_Function> &funs = get_function_objects_int();
|
||||
|
||||
std::map<std::string, Proxy_Function>::const_iterator itr = funs.find(t_name);
|
||||
|
||||
if (itr != funs.end())
|
||||
{
|
||||
return const_var(itr->second);
|
||||
} else {
|
||||
throw std::range_error("Object not found: " + t_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a function exists
|
||||
*/
|
||||
@@ -668,6 +667,57 @@ 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<std::string, Boxed_Value> 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<std::string, Boxed_Value> 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<chaiscript::detail::threading::shared_mutex> 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<std::string, Boxed_Value> get_function_objects() const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const std::map<std::string, Proxy_Function> &funs = get_function_objects_int();
|
||||
|
||||
std::map<std::string, Boxed_Value> objs;
|
||||
|
||||
for (std::map<std::string, Proxy_Function>::const_iterator itr = funs.begin();
|
||||
itr != funs.end();
|
||||
++itr)
|
||||
{
|
||||
objs.insert(std::make_pair(itr->first, const_var(itr->second)));
|
||||
}
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a vector of all registered functions
|
||||
*/
|
||||
@@ -855,7 +905,17 @@ namespace chaiscript
|
||||
*/
|
||||
StackData &get_stack_data() const
|
||||
{
|
||||
return *(m_stack_holder->stack);
|
||||
return *(m_stack_holder->stacks.back());
|
||||
}
|
||||
|
||||
const std::map<std::string, Proxy_Function> &get_function_objects_int() const
|
||||
{
|
||||
return m_state.m_function_objects;
|
||||
}
|
||||
|
||||
std::map<std::string, Proxy_Function> &get_function_objects_int()
|
||||
{
|
||||
return m_state.m_function_objects;
|
||||
}
|
||||
|
||||
const std::map<std::string, std::vector<Proxy_Function> > &get_functions_int() const
|
||||
@@ -989,6 +1049,8 @@ namespace chaiscript
|
||||
std::map<std::string, std::vector<Proxy_Function> >::iterator itr
|
||||
= funcs.find(t_name);
|
||||
|
||||
std::map<std::string, Proxy_Function> &func_objs = get_function_objects_int();
|
||||
|
||||
if (itr != funcs.end())
|
||||
{
|
||||
std::vector<Proxy_Function> &vec = itr->second;
|
||||
@@ -1004,11 +1066,15 @@ namespace chaiscript
|
||||
|
||||
vec.push_back(t_f);
|
||||
std::stable_sort(vec.begin(), vec.end(), &function_less_than);
|
||||
func_objs[t_name] = Proxy_Function(new Dispatch_Function(vec));
|
||||
} else {
|
||||
std::vector<Proxy_Function> vec;
|
||||
vec.push_back(t_f);
|
||||
funcs.insert(std::make_pair(t_name, vec));
|
||||
func_objs[t_name] = t_f;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
@@ -1017,12 +1083,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<Stack> stacks;
|
||||
};
|
||||
|
||||
std::vector<Dynamic_Cast_Conversion> m_conversions;
|
||||
|
@@ -213,6 +213,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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -322,6 +322,8 @@ namespace chaiscript
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::is_type, boost::ref(m_engine)), "is_type");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::type_name, boost::ref(m_engine)), "type_name");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, boost::ref(m_engine)), "function_exists");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, boost::ref(m_engine)), "get_functions");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, boost::ref(m_engine)), "get_objects");
|
||||
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name");
|
||||
|
||||
|
@@ -190,36 +190,19 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
chaiscript::detail::Dispatch_Engine::Stack prev_stack = t_ss.get_stack();
|
||||
chaiscript::detail::Dispatch_Engine::Stack new_stack = t_ss.new_stack();
|
||||
Boxed_Value fn = this->children[0]->eval(t_ss);
|
||||
|
||||
try {
|
||||
Boxed_Value fn = this->children[0]->eval(t_ss);
|
||||
|
||||
try {
|
||||
t_ss.set_stack(new_stack);
|
||||
const Boxed_Value &retval = (*boxed_cast<const Const_Proxy_Function &>(fn))(plb);
|
||||
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 + "'");
|
||||
}
|
||||
catch(detail::Return_Value &rv) {
|
||||
t_ss.set_stack(prev_stack);
|
||||
return rv.retval;
|
||||
}
|
||||
catch(...) {
|
||||
t_ss.set_stack(prev_stack);
|
||||
throw;
|
||||
}
|
||||
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||
const Boxed_Value &retval = (*boxed_cast<const Const_Proxy_Function &>(fn))(plb);
|
||||
return retval;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
@@ -466,26 +449,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, plb);
|
||||
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);
|
||||
}
|
||||
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 {
|
||||
|
@@ -1465,12 +1465,9 @@ namespace chaiscript
|
||||
* Reads a switch statement from input
|
||||
*/
|
||||
bool Switch() {
|
||||
bool retval = false;
|
||||
|
||||
size_t prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Keyword("switch")) {
|
||||
retval = true;
|
||||
|
||||
if (!Char('(')) {
|
||||
throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename);
|
||||
@@ -1483,8 +1480,6 @@ namespace chaiscript
|
||||
while (Eol()) {}
|
||||
|
||||
if (Char('{')) {
|
||||
retval = true;
|
||||
|
||||
while (Eol()) {}
|
||||
|
||||
while (Case()) {
|
||||
@@ -1502,9 +1497,12 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
build_match(AST_NodePtr(new eval::Switch_AST_Node()), prev_stack_top);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1994,7 +1992,6 @@ namespace chaiscript
|
||||
bool saw_eol = true;
|
||||
|
||||
while (has_more) {
|
||||
has_more = false;
|
||||
int prev_line = m_line;
|
||||
int prev_col = m_col;
|
||||
if (Def()) {
|
||||
|
19
unittests/pass_by_reference.chai
Normal file
19
unittests/pass_by_reference.chai
Normal file
@@ -0,0 +1,19 @@
|
||||
def f(x) { x+= 2; }
|
||||
|
||||
var i = 1;
|
||||
|
||||
assert_equal(i, 1);
|
||||
|
||||
f(i);
|
||||
|
||||
assert_equal(i, 3);
|
||||
|
||||
def g(x) { x+= " World"; }
|
||||
|
||||
var s = "Hello";
|
||||
|
||||
assert_equal(s, "Hello");
|
||||
|
||||
g(s);
|
||||
|
||||
assert_equal(s, "Hello World");
|
18
unittests/system_introspection.chai
Normal file
18
unittests/system_introspection.chai
Normal file
@@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
|
3
unittests/temporary_lifetime.chai
Normal file
3
unittests/temporary_lifetime.chai
Normal file
@@ -0,0 +1,3 @@
|
||||
for_each(range([1..10]), fun(x) {print(x);} );
|
||||
|
||||
assert_true(true);
|
@@ -23,7 +23,7 @@ def assert_true(f)
|
||||
{
|
||||
if (!f)
|
||||
{
|
||||
print("assert_false failure");
|
||||
print("assert_true failure");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user