diff --git a/cheatsheet.md b/cheatsheet.md index 027b91e..d25b744 100644 --- a/cheatsheet.md +++ b/cheatsheet.md @@ -167,6 +167,12 @@ auto j; // equiv to var var k = 5; // initialized to 5 (integer) var l := k; // reference to k auto &m = k; // reference to k + +GLOBAL g = 5; // creates a global variable. If global already exists, it is not re-added +GLOBAL g = 2; // global 'g' now equals 2 + +GLOBAL g2; +if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if GLOBAL decl hit more than once ``` ## Built in Types diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index e1cb285..5e7d18d 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -487,6 +487,23 @@ namespace chaiscript } } + /// Adds a new global (non-const) shared object, between all the threads + Boxed_Value add_global_no_throw(const Boxed_Value &obj, const std::string &name) + { + validate_object_name(name); + + chaiscript::detail::threading::unique_lock l(m_global_object_mutex); + + const auto itr = m_state.m_global_objects.find(name); + if (itr == m_state.m_global_objects.end()) + { + m_state.m_global_objects.insert(std::make_pair(name, obj)); + return obj; + } else { + return itr->second; + } + } + /// Adds a new global (non-const) shared object, between all the threads void add_global(const Boxed_Value &obj, const std::string &name) diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 66fae5e..d2a5e6f 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -38,7 +38,7 @@ namespace chaiscript Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String, Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range, Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or, - Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg + Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg, Global_Decl }; }; diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index e617562..0592ec9 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -346,6 +346,9 @@ namespace chaiscript m_engine.add_reserved_word("true"); m_engine.add_reserved_word("false"); m_engine.add_reserved_word("class"); + m_engine.add_reserved_word("attr"); + m_engine.add_reserved_word("var"); + m_engine.add_reserved_word("GLOBAL"); m_engine.add_reserved_word("_"); if (t_lib) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index bb131c3..2e8a922 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -539,6 +539,33 @@ namespace chaiscript } }; + struct Global_Decl_AST_Node : public AST_Node { + public: + Global_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : + AST_Node(std::move(t_ast_node_text), AST_Node_Type::Global_Decl, std::move(t_loc), std::move(t_children)) { } + virtual ~Global_Decl_AST_Node() {} + virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE { + + const std::string &idname = + [&]()->const std::string &{ + if (children[0]->identifier == AST_Node_Type::Reference) { + return children[0]->children[0]->text; + } else { + return children[0]->text; + } + }(); + + try { + return t_ss.add_global_no_throw(Boxed_Value(), idname); + } + catch (const exception::reserved_word_error &) { + throw exception::eval_error("Reserved word used as global '" + idname + "'"); + } + + } + }; + + struct Var_Decl_AST_Node : public AST_Node { public: Var_Decl_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, std::vector t_children) : diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 071a724..5936713 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -323,8 +323,6 @@ namespace chaiscript if (is_deep) { new_children.assign(std::make_move_iterator(m_match_stack.begin() + static_cast(t_match_start)), std::make_move_iterator(m_match_stack.end())); -// new_children = std::vector(std::make_move_iterator(m_match_stack.begin() + static_cast(t_match_start)), -// std::make_move_iterator(m_match_stack.end())); m_match_stack.erase(m_match_stack.begin() + static_cast(t_match_start), m_match_stack.end()); } @@ -1970,7 +1968,7 @@ namespace chaiscript } build_match(prev_stack_top); - } else if (Keyword("auto") || Keyword("var")) { + } else if (Keyword("auto") || Keyword("var") ) { retval = true; if (!(Reference() || Id())) { @@ -1978,6 +1976,14 @@ namespace chaiscript } build_match(prev_stack_top); + } else if (Keyword("GLOBAL")) { + retval = true; + + if (!(Reference() || Id())) { + throw exception::eval_error("Incomplete global declaration", File_Position(m_line, m_col), *m_filename); + } + + build_match(prev_stack_top); } else if (Keyword("attr")) { retval = true; diff --git a/unittests/global.chai b/unittests/global.chai new file mode 100644 index 0000000..0374e6d --- /dev/null +++ b/unittests/global.chai @@ -0,0 +1,18 @@ +// Test global + +GLOBAL g = 3; +assert_true(g == 3); + +var v := g; +assert_true(v == 3); + +GLOBAL g = 2; +assert_true(g == 2); +assert_true(v == 2); + +def f() { + assert_true(g == 2); +} + +f(); +