From c31ebb5665fc3cf6511d46b50f9ce45f948ddfd6 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 23 Jun 2016 10:23:40 -0600 Subject: [PATCH] Move checking of valid object names to parse time --- .../chaiscript/dispatchkit/dispatchkit.hpp | 26 ------------ .../chaiscript/language/chaiscript_common.hpp | 24 +++++++++++ .../chaiscript/language/chaiscript_engine.hpp | 4 ++ .../chaiscript/language/chaiscript_eval.hpp | 31 ++------------ .../chaiscript/language/chaiscript_parser.hpp | 40 ++++++++++++------- 5 files changed, 58 insertions(+), 67 deletions(-) diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index f9159d6..3b3bf3b 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -410,9 +410,6 @@ namespace chaiscript std::vector> m_boxed_functions; std::map m_global_objects; Type_Name_Map m_types; - std::set m_reserved_words - = {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto", - "return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_"}; }; Dispatch_Engine(chaiscript::parser::ChaiScript_Parser_Base &parser) @@ -439,7 +436,6 @@ namespace chaiscript /// Add a new named Proxy_Function to the system void add(const Proxy_Function &f, const std::string &name) { - validate_object_name(name); add_function(f, name); } @@ -447,7 +443,6 @@ namespace chaiscript /// is not available in the current scope it is created void add(Boxed_Value obj, const std::string &name) { - validate_object_name(name); auto &stack = get_stack_data(); for (auto stack_elem = stack.rbegin(); stack_elem != stack.rend(); ++stack_elem) @@ -497,7 +492,6 @@ namespace chaiscript /// Adds a new global shared object, between all the threads void add_global_const(const Boxed_Value &obj, const std::string &name) { - validate_object_name(name); if (!obj.is_const()) { throw chaiscript::exception::global_non_const(); @@ -516,8 +510,6 @@ 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_mutex); const auto itr = m_state.m_global_objects.find(name); @@ -534,8 +526,6 @@ namespace chaiscript /// Adds a new global (non-const) shared object, between all the threads void add_global(const Boxed_Value &obj, const std::string &name) { - validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_mutex); if (m_state.m_global_objects.find(name) != m_state.m_global_objects.end()) @@ -549,8 +539,6 @@ namespace chaiscript /// Updates an existing global shared object or adds a new global shared object if not found void set_global(const Boxed_Value &obj, const std::string &name) { - validate_object_name(name); - chaiscript::detail::threading::unique_lock l(m_mutex); const auto itr = m_state.m_global_objects.find(name); @@ -1359,20 +1347,6 @@ namespace chaiscript } - /// Throw a reserved_word exception if the name is not allowed - void validate_object_name(const std::string &name) const - { - if (name.find("::") != std::string::npos) { - throw chaiscript::exception::illegal_name_error(name); - } - - chaiscript::detail::threading::shared_lock l(m_mutex); - - if (m_state.m_reserved_words.find(name) != m_state.m_reserved_words.end()) - { - throw chaiscript::exception::reserved_word_error(name); - } - } template static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value) diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 2745373..3f093da 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -26,6 +26,30 @@ struct AST_Node; namespace chaiscript { + static bool is_reserved_word(const std::string &name) + { + static const std::set m_reserved_words + = {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto", + "return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_"}; + return m_reserved_words.count(name) > 0; + } + + static bool valid_object_name(const std::string &name) + { + return name.find("::") == std::string::npos && !is_reserved_word(name); + } + + static void validate_object_name(const std::string &name) + { + if (is_reserved_word(name)) { + throw exception::reserved_word_error(name); + } + + if (name.find("::") != std::string::npos) { + throw exception::illegal_name_error(name); + } + } + /// Signature of module entry point that all binary loadable modules must implement. typedef ModulePtr (*Create_Module_Func)(); diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 779d13d..73e0784 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -387,6 +387,7 @@ namespace chaiscript /// \sa Boxed_Value::is_const ChaiScript &add_global_const(const Boxed_Value &t_bv, const std::string &t_name) { + validate_object_name(t_name); m_engine.add_global_const(t_bv, t_name); return *this; } @@ -398,12 +399,14 @@ namespace chaiscript /// ChaiScript is thread-safe but provides no threading locking mechanism to the script ChaiScript &add_global(const Boxed_Value &t_bv, const std::string &t_name) { + validate_object_name(t_name); m_engine.add_global(t_bv, t_name); return *this; } ChaiScript &set_global(const Boxed_Value &t_bv, const std::string &t_name) { + validate_object_name(t_name); m_engine.set_global(t_bv, t_name); return *this; } @@ -503,6 +506,7 @@ namespace chaiscript template ChaiScript &add(const T &t_t, const std::string &t_name) { + validate_object_name(t_name); m_engine.add(t_t, t_name); return *this; } diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index be37c65..463f40a 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -527,12 +527,7 @@ namespace chaiscript } }(); - 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 + "'"); - } + return t_ss->add_global_no_throw(Boxed_Value(), idname); } }; @@ -550,9 +545,6 @@ namespace chaiscript Boxed_Value bv; t_ss.add_object(idname, bv); return bv; - } - catch (const exception::reserved_word_error &) { - throw exception::eval_error("Reserved word used as variable '" + idname + "'"); } catch (const exception::name_conflict_error &e) { throw exception::eval_error("Variable redefined '" + e.name() + "'"); } @@ -763,9 +755,6 @@ namespace chaiscript }, static_cast(numparams), this->children.back(), param_types, guard), l_function_name); - } - catch (const exception::reserved_word_error &e) { - throw exception::eval_error("Reserved word used as function name '" + e.word() + "'"); } catch (const exception::name_conflict_error &e) { throw exception::eval_error("Function redefined '" + e.name() + "'"); } @@ -1069,14 +1058,9 @@ namespace chaiscript { assert(children.size() == 1); } Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ - try { - Boxed_Value bv; - t_ss.add_object(this->children[0]->text, bv); - return bv; - } - catch (const exception::reserved_word_error &) { - throw exception::eval_error("Reserved word used as variable '" + this->children[0]->text + "'"); - } + Boxed_Value bv; + t_ss.add_object(this->children[0]->text, bv); + return bv; } }; @@ -1377,9 +1361,6 @@ namespace chaiscript static_cast(numparams), node, param_types, guard), type), function_name); } - } - catch (const exception::reserved_word_error &e) { - throw exception::eval_error("Reserved word used as method name '" + e.word() + "'"); } catch (const exception::name_conflict_error &e) { throw exception::eval_error("Method redefined '" + e.name() + "'"); } @@ -1412,10 +1393,6 @@ namespace chaiscript true ), this->children[static_cast(1 + class_offset)]->text); - - } - catch (const exception::reserved_word_error &) { - throw exception::eval_error("Reserved word used as attribute '" + this->children[static_cast(1 + class_offset)]->text + "'"); } catch (const exception::name_conflict_error &e) { throw exception::eval_error("Attribute redefined '" + e.name() + "'"); } diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 5262b64..2f13630 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -285,6 +285,13 @@ namespace chaiscript Tracer m_tracer; Optimizer m_optimizer; + void validate_object_name(const std::string &name) const + { + if (!valid_object_name(name)) { + throw exception::eval_error("Invalid Object Name: " + name, File_Position(m_position.line, m_position.col), *m_filename); + } + } + public: explicit ChaiScript_Parser(Tracer tracer = Tracer(), Optimizer optimizer=Optimizer()) : m_tracer(std::move(tracer)), @@ -756,13 +763,18 @@ namespace chaiscript } /// Reads (and potentially captures) an identifier from input - bool Id() { + bool Id(const bool validate) { SkipWS(); const auto start = m_position; if (Id_()) { const auto text = Position::str(start, m_position); + + if (validate) { + validate_object_name(text); + } + if (text == "true") { m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(true))); } else if (text == "false") { @@ -801,14 +813,14 @@ namespace chaiscript const auto prev_stack_top = m_match_stack.size(); SkipWS(); - if (!Id()) { + if (!Id(true)) { return false; } SkipWS(); if (t_type_allowed) { - Id(); + Id(true); } build_match>(prev_stack_top); @@ -1427,7 +1439,7 @@ namespace chaiscript if (Keyword("def")) { retval = true; - if (!Id()) { + if (!Id(true)) { throw exception::eval_error("Missing function name in definition", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1437,7 +1449,7 @@ namespace chaiscript //We're now a method is_method = true; - if (!Id()) { + if (!Id(true)) { throw exception::eval_error("Missing method name in definition", File_Position(m_position.line, m_position.col), *m_filename); } } @@ -1588,7 +1600,7 @@ namespace chaiscript if (Keyword("class")) { retval = true; - if (!Id()) { + if (!Id(true)) { throw exception::eval_error("Missing class name in definition", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1871,7 +1883,7 @@ namespace chaiscript const auto prev_stack_top = m_match_stack.size(); if (Lambda() || Num(true) || Quoted_String(true) || Single_Quoted_String(true) || - Paren_Expression() || Inline_Container() || Id()) + Paren_Expression() || Inline_Container() || Id(false)) { retval = true; bool has_more = true; @@ -1916,7 +1928,7 @@ namespace chaiscript } else if (Symbol(".")) { has_more = true; - if (!(Id())) { + if (!(Id(true))) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1940,7 +1952,7 @@ namespace chaiscript if (t_class_context && (Keyword("attr") || Keyword("auto") || Keyword("var"))) { retval = true; - if (!Id()) { + if (!Id(true)) { throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1950,7 +1962,7 @@ namespace chaiscript if (Reference()) { // we built a reference node - continue - } else if (Id()) { + } else if (Id(true)) { build_match>(prev_stack_top); } else { throw exception::eval_error("Incomplete variable declaration", File_Position(m_position.line, m_position.col), *m_filename); @@ -1959,7 +1971,7 @@ namespace chaiscript } else if (Keyword("GLOBAL") || Keyword("global")) { retval = true; - if (!(Reference() || Id())) { + if (!(Reference() || Id(true))) { throw exception::eval_error("Incomplete global declaration", File_Position(m_position.line, m_position.col), *m_filename); } @@ -1967,13 +1979,13 @@ namespace chaiscript } else if (Keyword("attr")) { retval = true; - if (!Id()) { + if (!Id(true)) { throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename); } if (!Symbol("::")) { throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename); } - if (!Id()) { + if (!Id(true)) { throw exception::eval_error("Missing attribute name in definition", File_Position(m_position.line, m_position.col), *m_filename); } @@ -2035,7 +2047,7 @@ namespace chaiscript const auto prev_stack_top = m_match_stack.size(); if (Symbol("&")) { - if (!Id()) { + if (!Id(true)) { throw exception::eval_error("Incomplete '&' expression", File_Position(m_position.line, m_position.col), *m_filename); }