Move checking of valid object names to parse time

This commit is contained in:
Jason Turner 2016-06-23 10:23:40 -06:00
parent 52a191df9e
commit c31ebb5665
5 changed files with 58 additions and 67 deletions

View File

@ -410,9 +410,6 @@ namespace chaiscript
std::vector<std::pair<std::string, Boxed_Value>> m_boxed_functions;
std::map<std::string, Boxed_Value> m_global_objects;
Type_Name_Map m_types;
std::set<std::string> 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<chaiscript::detail::threading::shared_mutex> 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<chaiscript::detail::threading::shared_mutex> 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<chaiscript::detail::threading::shared_mutex> 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<chaiscript::detail::threading::shared_mutex> 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<typename Container, typename Key, typename Value>
static void add_keyed_value(Container &t_c, const Key &t_key, Value &&t_value)

View File

@ -26,6 +26,30 @@ struct AST_Node;
namespace chaiscript
{
static bool is_reserved_word(const std::string &name)
{
static const std::set<std::string> 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)();

View File

@ -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<typename T>
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;
}

View File

@ -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 + "'");
}
}
};
@ -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<int>(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,15 +1058,10 @@ 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 + "'");
}
}
};
template<typename T>
@ -1377,9 +1361,6 @@ namespace chaiscript
static_cast<int>(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<size_t>(1 + class_offset)]->text);
}
catch (const exception::reserved_word_error &) {
throw exception::eval_error("Reserved word used as attribute '" + this->children[static_cast<size_t>(1 + class_offset)]->text + "'");
} catch (const exception::name_conflict_error &e) {
throw exception::eval_error("Attribute redefined '" + e.name() + "'");
}

View File

@ -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<eval::Constant_AST_Node<Tracer>>(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<eval::Arg_AST_Node<Tracer>>(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<eval::Var_Decl_AST_Node<Tracer>>(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);
}