Move checking of valid object names to parse time
This commit is contained in:
parent
52a191df9e
commit
c31ebb5665
@ -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)
|
||||
|
@ -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)();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<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,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<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() + "'");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user