diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 0abfcff..242771b 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -49,7 +49,7 @@ namespace chaiscript try { // We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it // either way, we are not responsible if it doesn't work - return detail::Cast_Helper::cast(boxed_dynamic_cast(bv)); + return detail::Cast_Helper::cast(detail::boxed_dynamic_cast(bv)); } catch (const boost::bad_any_cast &) { throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type)); } diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 88e097b..9467b58 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -201,7 +201,7 @@ namespace chaiscript protected: virtual Boxed_Value do_call(const std::vector ¶ms) const { - return dispatch(m_funcs.begin(), m_funcs.end(), params); + return detail::dispatch(m_funcs.begin(), m_funcs.end(), params); } private: @@ -647,7 +647,7 @@ namespace chaiscript { std::vector functions = get_function(t_name); - return dispatch(functions.begin(), functions.end(), params); + return detail::dispatch(functions.begin(), functions.end(), params); } Boxed_Value call_function(const std::string &t_name) const diff --git a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp index 0425286..15ef49e 100644 --- a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp +++ b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp @@ -254,29 +254,31 @@ namespace chaiscript return detail::Dynamic_Conversions::create(); } - template - bool dynamic_cast_converts() + namespace detail { - return dynamic_cast_converts(user_type(), user_type()); - } + template + bool dynamic_cast_converts() + { + return dynamic_cast_converts(user_type(), user_type()); + } - static bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) - { - return detail::Dynamic_Conversions::get().has_conversion(base, derived); - } - - template - Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) - { - try { - return detail::Dynamic_Conversions::get().get_conversion(user_type(), derived.get_type_info())->convert(derived); - } catch (const std::out_of_range &) { - throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion"); - } catch (const std::bad_cast &) { - throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation"); + static bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) + { + return detail::Dynamic_Conversions::get().has_conversion(base, derived); } - } + template + Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) + { + try { + return detail::Dynamic_Conversions::get().get_conversion(user_type(), derived.get_type_info())->convert(derived); + } catch (const std::out_of_range &) { + throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion"); + } catch (const std::bad_cast &) { + throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation"); + } + } + } } diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 825b097..4ec0bc9 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -139,7 +139,7 @@ namespace chaiscript || (!bv.get_type_info().is_undef() && (ti.bare_equal(user_type()) || ti.bare_equal(bv.get_type_info()) - || dynamic_cast_converts(ti, bv.get_type_info()) + || detail::dynamic_cast_converts(ti, bv.get_type_info()) || bv.get_type_info().bare_equal(user_type >()) ) ) @@ -594,46 +594,49 @@ namespace chaiscript }; } - /** - * Take a vector of functions and a vector of parameters. Attempt to execute - * each function against the set of parameters, in order, until a matching - * function is found or throw dispatch_error if no matching function is found - */ - template - Boxed_Value dispatch(InItr begin, InItr end, - const std::vector &plist) + namespace detail { - while (begin != end) - { - try { - if ((*begin)->filter(plist)) + /** + * Take a vector of functions and a vector of parameters. Attempt to execute + * each function against the set of parameters, in order, until a matching + * function is found or throw dispatch_error if no matching function is found + */ + template + Boxed_Value dispatch(InItr begin, InItr end, + const std::vector &plist) + { + while (begin != end) { - return (*(*begin))(plist); + try { + if ((*begin)->filter(plist)) + { + return (*(*begin))(plist); + } + } catch (const exception::bad_boxed_cast &) { + //parameter failed to cast, try again + } catch (const exception::arity_error &) { + //invalid num params, try again + } catch (const exception::guard_error &) { + //guard failed to allow the function to execute, + //try again + } + ++begin; } - } catch (const exception::bad_boxed_cast &) { - //parameter failed to cast, try again - } catch (const exception::arity_error &) { - //invalid num params, try again - } catch (const exception::guard_error &) { - //guard failed to allow the function to execute, - //try again + + throw exception::dispatch_error(plist.empty()?false:plist[0].is_const()); } - ++begin; - } - throw exception::dispatch_error(plist.empty()?false:plist[0].is_const()); - } - - /** - * Take a vector of functions and a vector of parameters. Attempt to execute - * each function against the set of parameters, in order, until a matching - * function is found or throw dispatch_error if no matching function is found - */ - template - Boxed_Value dispatch(const Funcs &funcs, - const std::vector &plist) - { - return dispatch(funcs.begin(), funcs.end(), plist); + /** + * Take a vector of functions and a vector of parameters. Attempt to execute + * each function against the set of parameters, in order, until a matching + * function is found or throw dispatch_error if no matching function is found + */ + template + Boxed_Value dispatch(const Funcs &funcs, + const std::vector &plist) + { + return dispatch(funcs.begin(), funcs.end(), plist); + } } } diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 1dfb947..f2730e3 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -108,59 +108,65 @@ namespace chaiscript - /** - * Errors generated during parsing or evaluation - */ - struct Eval_Error : public std::runtime_error { - std::string reason; - File_Position start_position; - File_Position end_position; - std::string filename; - std::vector call_stack; + namespace exception + { + /** + * Errors generated during parsing or evaluation + */ + struct eval_error : public std::runtime_error { + std::string reason; + File_Position start_position; + File_Position end_position; + std::string filename; + std::vector call_stack; - Eval_Error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) : - std::runtime_error("Error: \"" + t_why + "\" " + - (t_fname != "__EVAL__" ? ("in '" + t_fname + "' ") : "during evaluation ") + - + "at (" + boost::lexical_cast(t_where.line) + ", " + - boost::lexical_cast(t_where.column) + ")"), - reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname) - { } + eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) throw() : + std::runtime_error("Error: \"" + t_why + "\" " + + (t_fname != "__EVAL__" ? ("in '" + t_fname + "' ") : "during evaluation ") + + + "at (" + boost::lexical_cast(t_where.line) + ", " + + boost::lexical_cast(t_where.column) + ")"), + reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname) + { } - Eval_Error(const std::string &t_why) - : std::runtime_error("Error: \"" + t_why + "\" "), + eval_error(const std::string &t_why) throw() + : std::runtime_error("Error: \"" + t_why + "\" "), reason(t_why) - {} + {} - virtual ~Eval_Error() throw() {} - }; + virtual ~eval_error() throw() {} + }; - /** - * Errors generated when loading a file - */ - struct File_Not_Found_Error : public std::runtime_error { - File_Not_Found_Error(const std::string &t_filename) - : std::runtime_error("File Not Found: " + t_filename) - { } + /** + * Errors generated when loading a file + */ + struct file_not_found_error : public std::runtime_error { + file_not_found_error(const std::string &t_filename) throw() + : std::runtime_error("File Not Found: " + t_filename) + { } - virtual ~File_Not_Found_Error() throw() {} - }; + virtual ~file_not_found_error() throw() {} + }; + } - /** - * Special type for returned values - */ - struct Return_Value { - Boxed_Value retval; + namespace detail + { + /** + * Special type for returned values + */ + struct Return_Value { + Boxed_Value retval; - Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { } - }; + Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { } + }; - /** - * Special type indicating a call to 'break' - */ - struct Break_Loop { - Break_Loop() { } - }; + /** + * Special type indicating a call to 'break' + */ + struct Break_Loop { + Break_Loop() { } + }; + } } #endif /* _CHAISCRIPT_COMMON_HPP */ diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 5526f56..af7ca14 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -28,193 +28,199 @@ namespace chaiscript { - struct load_module_error : std::runtime_error + namespace exception { - load_module_error(const std::string &t_reason) throw() - : std::runtime_error(t_reason) + struct load_module_error : std::runtime_error { - } + load_module_error(const std::string &t_reason) throw() + : std::runtime_error(t_reason) + { + } - virtual ~load_module_error() throw() - { - } - }; + virtual ~load_module_error() throw() + { + } + }; + } + namespace detail + { #ifdef _POSIX_VERSION - struct Loadable_Module - { - struct DLModule + struct Loadable_Module { - DLModule(const std::string &t_filename) - : m_data(dlopen(t_filename.c_str(), RTLD_NOW)) + struct DLModule { - if (!m_data) + DLModule(const std::string &t_filename) + : m_data(dlopen(t_filename.c_str(), RTLD_NOW)) + { + if (!m_data) { - throw load_module_error(dlerror()); + throw exception::load_module_error(dlerror()); } - } + } - DLModule(const DLModule &); // Explicitly unimplemented copy constructor - DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator + DLModule(const DLModule &); // Explicitly unimplemented copy constructor + DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator - ~DLModule() - { - dlclose(m_data); - } + ~DLModule() + { + dlclose(m_data); + } - void *m_data; - }; + void *m_data; + }; - template - struct DLSym - { - DLSym(DLModule &t_mod, const std::string &t_symbol) - : m_symbol(reinterpret_cast(dlsym(t_mod.m_data, t_symbol.c_str()))) - { - if (!m_symbol) + template + struct DLSym + { + DLSym(DLModule &t_mod, const std::string &t_symbol) + : m_symbol(reinterpret_cast(dlsym(t_mod.m_data, t_symbol.c_str()))) { - throw load_module_error(dlerror()); + if (!m_symbol) + { + throw exception::load_module_error(dlerror()); + } } - } - T m_symbol; - }; + T m_symbol; + }; - Loadable_Module(const std::string &t_module_name, const std::string &t_filename) - : m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name), + Loadable_Module(const std::string &t_module_name, const std::string &t_filename) + : m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name), m_moduleptr(m_func.m_symbol()) - { - } + { + } - DLModule m_dlmodule; - DLSym m_func; - ModulePtr m_moduleptr; - }; + DLModule m_dlmodule; + DLSym m_func; + ModulePtr m_moduleptr; + }; #else #ifdef WIN32 - struct Loadable_Module - { - template - static std::wstring towstring(const T &t_str) + struct Loadable_Module { - return std::wstring(t_str.begin(), t_str.end()); - } + template + static std::wstring towstring(const T &t_str) + { + return std::wstring(t_str.begin(), t_str.end()); + } - template - static std::string tostring(const T &t_str) - { - return std::string(t_str.begin(), t_str.end()); - } + template + static std::string tostring(const T &t_str) + { + return std::string(t_str.begin(), t_str.end()); + } #ifdef _UNICODE - template - static std::wstring toproperstring(const T &t_str) - { - return towstring(t_str); - } + template + static std::wstring toproperstring(const T &t_str) + { + return towstring(t_str); + } #else - template - static std::string toproperstring(const T &t_str) - { - return tostring(t_str); - } + template + static std::string toproperstring(const T &t_str) + { + return tostring(t_str); + } #endif - static std::string GetErrorMessage(DWORD t_err) - { + static std::string GetErrorMessage(DWORD t_err) + { #ifdef _UNICODE - typedef LPWSTR StringType; - std::wstring retval = L"Unknown Error"; + typedef LPWSTR StringType; + std::wstring retval = L"Unknown Error"; #else - typedef LPSTR StringType; - std::string retval = "Unknown Error"; + typedef LPSTR StringType; + std::string retval = "Unknown Error"; #endif - StringType lpMsgBuf = 0; + StringType lpMsgBuf = 0; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - t_err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (StringType)&lpMsgBuf, - 0, NULL ); + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + t_err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (StringType)&lpMsgBuf, + 0, NULL ); - if (lpMsgBuf) - { - retval = lpMsgBuf; + if (lpMsgBuf) + { + retval = lpMsgBuf; + } + + LocalFree(lpMsgBuf); + return tostring(retval); } - LocalFree(lpMsgBuf); - return tostring(retval); - } - - struct DLModule - { - DLModule(const std::string &t_filename) - : m_data(LoadLibrary(toproperstring(t_filename).c_str())) + struct DLModule { - if (!m_data) + DLModule(const std::string &t_filename) + : m_data(LoadLibrary(toproperstring(t_filename).c_str())) + { + if (!m_data) { - throw load_module_error(GetErrorMessage(GetLastError())); + throw exception::load_module_error(GetErrorMessage(GetLastError())); } - } + } - ~DLModule() - { - FreeLibrary(m_data); - } + ~DLModule() + { + FreeLibrary(m_data); + } - HMODULE m_data; - }; + HMODULE m_data; + }; - template - struct DLSym - { - DLSym(DLModule &t_mod, const std::string &t_symbol) - : m_symbol(reinterpret_cast(GetProcAddress(t_mod.m_data, t_symbol.c_str()))) - { - if (!m_symbol) + template + struct DLSym + { + DLSym(DLModule &t_mod, const std::string &t_symbol) + : m_symbol(reinterpret_cast(GetProcAddress(t_mod.m_data, t_symbol.c_str()))) { - throw load_module_error(GetErrorMessage(GetLastError())); + if (!m_symbol) + { + throw exception::load_module_error(GetErrorMessage(GetLastError())); + } } - } - T m_symbol; - }; + T m_symbol; + }; - Loadable_Module(const std::string &t_module_name, const std::string &t_filename) - : m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name), + Loadable_Module(const std::string &t_module_name, const std::string &t_filename) + : m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name), m_moduleptr(m_func.m_symbol()) - { - } + { + } - DLModule m_dlmodule; - DLSym m_func; - ModulePtr m_moduleptr; - }; + DLModule m_dlmodule; + DLSym m_func; + ModulePtr m_moduleptr; + }; #else - struct Loadable_Module - { - Loadable_Module(const std::string &, const std::string &) + struct Loadable_Module { - throw load_module_error("Loadable module support not available for your platform"); - } + Loadable_Module(const std::string &, const std::string &) + { + throw exception::load_module_error("Loadable module support not available for your platform"); + } - ModulePtr get() - { - throw load_module_error("Loadable module support not available for your platform"); - } - }; + ModulePtr get() + { + throw exception::load_module_error("Loadable module support not available for your platform"); + } + }; #endif #endif - typedef boost::shared_ptr Loadable_Module_Ptr; + typedef boost::shared_ptr Loadable_Module_Ptr; + } class ChaiScript { #ifndef CHAISCRIPT_NO_THREADS @@ -223,7 +229,7 @@ namespace chaiscript #endif std::set m_used_files; - std::map m_loaded_modules; + std::map m_loaded_modules; std::set m_active_loaded_modules; std::vector m_modulepaths; @@ -238,7 +244,7 @@ namespace chaiscript Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false) { try { - ChaiScript_Parser parser; + parser::ChaiScript_Parser parser; if (parser.parse(t_input, t_filename)) { //parser.show_match_stack(); return parser.ast()->eval(m_engine); @@ -246,7 +252,7 @@ namespace chaiscript return Boxed_Value(); } } - catch (const Return_Value &rv) { + catch (const detail::Return_Value &rv) { return rv.retval; } } @@ -287,10 +293,10 @@ namespace chaiscript #endif eval_file(appendedpath); } - } catch (const File_Not_Found_Error &) { + } catch (const exception::file_not_found_error &) { if (i == m_usepaths.size() - 1) { - throw File_Not_Found_Error(t_filename); + throw exception::file_not_found_error(t_filename); } // failed to load, try the next path @@ -305,6 +311,56 @@ namespace chaiscript return m_engine; } + /** + * Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude. + */ + void build_eval_system() { + using namespace bootstrap; + m_engine.add_reserved_word("def"); + m_engine.add_reserved_word("fun"); + m_engine.add_reserved_word("while"); + m_engine.add_reserved_word("for"); + m_engine.add_reserved_word("if"); + m_engine.add_reserved_word("else"); + m_engine.add_reserved_word("&&"); + m_engine.add_reserved_word("||"); + m_engine.add_reserved_word(","); + m_engine.add_reserved_word(":="); + m_engine.add_reserved_word("var"); + m_engine.add_reserved_word("return"); + m_engine.add_reserved_word("break"); + m_engine.add_reserved_word("true"); + m_engine.add_reserved_word("false"); + m_engine.add_reserved_word("_"); + + add(Bootstrap::bootstrap()); + + m_engine.add(fun(&Dispatch_Engine::dump_system, boost::ref(m_engine)), "dump_system"); + m_engine.add(fun(&Dispatch_Engine::dump_object, boost::ref(m_engine)), "dump_object"); + m_engine.add(fun(&Dispatch_Engine::is_type, boost::ref(m_engine)), "is_type"); + m_engine.add(fun(&Dispatch_Engine::type_name, boost::ref(m_engine)), "type_name"); + m_engine.add(fun(&Dispatch_Engine::function_exists, boost::ref(m_engine)), "function_exists"); + + m_engine.add(fun(&Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name"); + + + typedef void (ChaiScript::*load_mod_1)(const std::string&); + typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&); + + m_engine.add(fun(static_cast(&ChaiScript::load_module), this), "load_module"); + m_engine.add(fun(static_cast(&ChaiScript::load_module), this), "load_module"); + + add(standard_library::vector_type >("Vector")); + add(standard_library::string_type("string")); + add(standard_library::map_type >("Map")); + add(standard_library::pair_type >("Pair")); + + m_engine.add(fun(&ChaiScript::use, this), "use"); + m_engine.add(fun(&ChaiScript::internal_eval, this), "eval"); + m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval"); + + do_eval(chaiscript_prelude, "standard prelude"); + } public: ChaiScript(const std::vector &t_modulepaths = std::vector(), @@ -398,7 +454,7 @@ namespace chaiscript */ void load_module(const std::string &t_module_name) { - std::vector errors; + std::vector errors; std::vector prefixes; prefixes.push_back("lib"); @@ -419,7 +475,7 @@ namespace chaiscript std::string name = m_modulepaths[i] + prefixes[j] + t_module_name + postfixes[k]; load_module(t_module_name, name); return; - } catch (const load_module_error &e) { + } catch (const exception::load_module_error &e) { errors.push_back(e); // Try next set } @@ -429,7 +485,7 @@ namespace chaiscript std::string errstring; - for (std::vector::const_iterator itr = errors.begin(); + for (std::vector::const_iterator itr = errors.begin(); itr != errors.end(); ++itr) { @@ -441,7 +497,7 @@ namespace chaiscript errstring += itr->what(); } - throw load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring); + throw exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring); } /** @@ -455,7 +511,7 @@ namespace chaiscript if (m_loaded_modules.count(t_module_name) == 0) { - Loadable_Module_Ptr lm(new Loadable_Module(t_module_name, t_filename)); + detail::Loadable_Module_Ptr lm(new detail::Loadable_Module(t_module_name, t_filename)); m_loaded_modules[t_module_name] = lm; m_active_loaded_modules.insert(t_module_name); add(lm->m_moduleptr); @@ -495,7 +551,7 @@ namespace chaiscript std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary ); if (!infile.is_open()) { - throw File_Not_Found_Error(t_filename); + throw exception::file_not_found_error(t_filename); } std::streampos size = infile.tellg(); @@ -513,56 +569,6 @@ namespace chaiscript } } - /** - * Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude. - */ - void build_eval_system() { - using namespace bootstrap; - m_engine.add_reserved_word("def"); - m_engine.add_reserved_word("fun"); - m_engine.add_reserved_word("while"); - m_engine.add_reserved_word("for"); - m_engine.add_reserved_word("if"); - m_engine.add_reserved_word("else"); - m_engine.add_reserved_word("&&"); - m_engine.add_reserved_word("||"); - m_engine.add_reserved_word(","); - m_engine.add_reserved_word(":="); - m_engine.add_reserved_word("var"); - m_engine.add_reserved_word("return"); - m_engine.add_reserved_word("break"); - m_engine.add_reserved_word("true"); - m_engine.add_reserved_word("false"); - m_engine.add_reserved_word("_"); - - add(Bootstrap::bootstrap()); - - m_engine.add(fun(&Dispatch_Engine::dump_system, boost::ref(m_engine)), "dump_system"); - m_engine.add(fun(&Dispatch_Engine::dump_object, boost::ref(m_engine)), "dump_object"); - m_engine.add(fun(&Dispatch_Engine::is_type, boost::ref(m_engine)), "is_type"); - m_engine.add(fun(&Dispatch_Engine::type_name, boost::ref(m_engine)), "type_name"); - m_engine.add(fun(&Dispatch_Engine::function_exists, boost::ref(m_engine)), "function_exists"); - - m_engine.add(fun(&Dispatch_Engine::get_type_name, boost::ref(m_engine)), "name"); - - - typedef void (ChaiScript::*load_mod_1)(const std::string&); - typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&); - - m_engine.add(fun(static_cast(&ChaiScript::load_module), this), "load_module"); - m_engine.add(fun(static_cast(&ChaiScript::load_module), this), "load_module"); - - add(standard_library::vector_type >("Vector")); - add(standard_library::string_type("string")); - add(standard_library::map_type >("Map")); - add(standard_library::pair_type >("Pair")); - - m_engine.add(fun(&ChaiScript::use, this), "use"); - m_engine.add(fun(&ChaiScript::internal_eval, this), "eval"); - m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval"); - - do_eval(chaiscript_prelude, "standard prelude"); - } template T eval(const std::string &t_input) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 1382c60..2718c23 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -28,10 +28,10 @@ namespace chaiscript Boxed_Value retval(t_node->eval(t_ss)); t_ss.pop_scope(); return retval; - } catch (const Return_Value &rv) { + } catch (const detail::Return_Value &rv) { t_ss.pop_scope(); return rv.retval; - } catch (Eval_Error &ee) { + } catch (exception::eval_error &ee) { ee.call_stack.push_back(t_node); t_ss.pop_scope(); throw; @@ -55,7 +55,7 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -65,9 +65,9 @@ namespace chaiscript retval = t_ss.call_function(this->children[i]->text, retval, this->children[i+1]->eval(t_ss)); } catch(const exception::dispatch_error &){ - throw Eval_Error("Can not find appropriate '" + this->children[i]->text + "'"); + throw exception::eval_error("Can not find appropriate '" + this->children[i]->text + "'"); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+1]); throw; } @@ -131,7 +131,7 @@ namespace chaiscript return t_ss.get_object(this->text); } catch (std::exception &) { - throw Eval_Error("Can not find object: " + this->text); + throw exception::eval_error("Can not find object: " + this->text); } } } @@ -171,7 +171,7 @@ namespace chaiscript try { plb << this->children[1]->children[i]->eval(t_ss); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]->children[i]); throw; } @@ -192,9 +192,9 @@ namespace chaiscript } catch(const exception::dispatch_error &e){ t_ss.set_stack(prev_stack); - throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); } - catch(Return_Value &rv) { + catch(detail::Return_Value &rv) { t_ss.set_stack(prev_stack); return rv.retval; } @@ -203,10 +203,10 @@ namespace chaiscript throw; } } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); t_ss.set_stack(prev_stack); - throw Eval_Error(ee.reason); + throw exception::eval_error(ee.reason); } } @@ -226,7 +226,7 @@ namespace chaiscript try { plb << this->children[1]->children[i]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]->children[i]); throw; } @@ -240,18 +240,18 @@ namespace chaiscript return (*boxed_cast(fn))(plb); } catch(const exception::dispatch_error &e){ - throw Eval_Error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); + throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'"); } - catch(Return_Value &rv) { + catch(detail::Return_Value &rv) { return rv.retval; } catch(...) { throw; } } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); - throw Eval_Error(ee.reason); + throw exception::eval_error(ee.reason); } } @@ -282,7 +282,7 @@ namespace chaiscript try { retval = this->children.back()->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()); throw; } @@ -303,14 +303,14 @@ namespace chaiscript retval = t_ss.call_function(this->children[i+1]->text, lhs, retval); } catch(const exception::dispatch_error &){ - throw Eval_Error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); + throw exception::eval_error(std::string("Mismatched types in equation") + (lhs.is_const()?", lhs is const.":".")); } } catch(const exception::dispatch_error &){ - throw Eval_Error("Can not clone right hand side of equation"); + throw exception::eval_error("Can not clone right hand side of equation"); } } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); throw; } @@ -322,10 +322,10 @@ namespace chaiscript lhs.assign(retval); } else { - throw Eval_Error("Mismatched types in equation"); + throw exception::eval_error("Mismatched types in equation"); } } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); throw; } @@ -335,9 +335,9 @@ namespace chaiscript retval = t_ss.call_function(this->children[i+1]->text, this->children[i]->eval(t_ss), retval); } catch(const exception::dispatch_error &){ - throw Eval_Error("Can not find appropriate '" + this->children[i+1]->text + "'"); + throw exception::eval_error("Can not find appropriate '" + this->children[i+1]->text + "'"); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); throw; } @@ -358,7 +358,7 @@ namespace chaiscript t_ss.add_object(this->children[0]->text, Boxed_Value()); } catch (const exception::reserved_word_error &) { - throw Eval_Error("Reserved word used as variable '" + this->children[0]->text + "'"); + throw exception::eval_error("Reserved word used as variable '" + this->children[0]->text + "'"); } return t_ss.get_object(this->children[0]->text); } @@ -397,7 +397,7 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -407,12 +407,12 @@ namespace chaiscript retval = t_ss.call_function("[]", retval, this->children[i]->eval(t_ss)); } catch(std::out_of_range &) { - throw Eval_Error("Out of bounds exception"); + throw exception::eval_error("Out of bounds exception"); } catch(const exception::dispatch_error &){ - throw Eval_Error("Can not find appropriate array lookup '[]' "); + throw exception::eval_error("Can not find appropriate array lookup '[]' "); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); throw; } @@ -432,7 +432,7 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -447,7 +447,7 @@ namespace chaiscript try { plb << this->children[i]->children[1]->children[j]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]->children[1]->children[j]); throw; } @@ -472,9 +472,9 @@ namespace chaiscript } catch(const exception::dispatch_error &e){ t_ss.set_stack(prev_stack); - throw Eval_Error(std::string(e.what())); + throw exception::eval_error(std::string(e.what())); } - catch(Return_Value &rv) { + catch(detail::Return_Value &rv) { t_ss.set_stack(prev_stack); retval = rv.retval; } @@ -488,12 +488,12 @@ namespace chaiscript retval = t_ss.call_function("[]", retval, this->children[i]->children[j]->eval(t_ss)); } catch(std::out_of_range &) { - throw Eval_Error("Out of bounds exception"); + throw exception::eval_error("Out of bounds exception"); } catch(const exception::dispatch_error &){ - throw Eval_Error("Can not find appropriate array lookup '[]' "); + throw exception::eval_error("Can not find appropriate array lookup '[]' "); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]->children[j]); throw; } @@ -576,11 +576,11 @@ namespace chaiscript return retval; } } - catch (const chaiscript::Return_Value &) { + catch (const chaiscript::detail::Return_Value &) { t_ss.pop_scope(); throw; } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); t_ss.pop_scope(); throw; @@ -644,7 +644,7 @@ namespace chaiscript l_annotation, guard)), l_function_name); } catch (const exception::reserved_word_error &e) { - throw Eval_Error("Reserved word used as function name '" + e.word() + "'"); + throw exception::eval_error("Reserved word used as function name '" + e.word() + "'"); } return Boxed_Value(); } @@ -666,9 +666,9 @@ namespace chaiscript } catch (const exception::bad_boxed_cast &) { t_ss.pop_scope(); - throw Eval_Error("While condition not boolean"); + throw exception::eval_error("While condition not boolean"); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); t_ss.pop_scope(); throw; @@ -678,7 +678,7 @@ namespace chaiscript try { this->children[1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]); throw; } @@ -688,15 +688,15 @@ namespace chaiscript } catch (const exception::bad_boxed_cast &) { t_ss.pop_scope(); - throw Eval_Error("While condition not boolean"); + throw exception::eval_error("While condition not boolean"); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); t_ss.pop_scope(); throw; } } - catch (Break_Loop &) { + catch (detail::Break_Loop &) { cond = false; } } @@ -717,9 +717,9 @@ namespace chaiscript cond = boxed_cast(this->children[0]->eval(t_ss)); } catch (const exception::bad_boxed_cast &) { - throw Eval_Error("If condition not boolean"); + throw exception::eval_error("If condition not boolean"); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -728,7 +728,7 @@ namespace chaiscript try { return this->children[1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]); throw; } @@ -741,7 +741,7 @@ namespace chaiscript try { return this->children[i+1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+1]); throw; } @@ -751,9 +751,9 @@ namespace chaiscript cond = boxed_cast(this->children[i+1]->eval(t_ss)); } catch (const exception::bad_boxed_cast &) { - throw Eval_Error("'else if' condition not boolean"); + throw exception::eval_error("'else if' condition not boolean"); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+1]); throw; } @@ -761,7 +761,7 @@ namespace chaiscript try { return this->children[i+2]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+2]); throw; } @@ -792,7 +792,7 @@ namespace chaiscript try { this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -800,7 +800,7 @@ namespace chaiscript try { cond = boxed_cast(this->children[1]->eval(t_ss)); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]); throw; } @@ -809,7 +809,7 @@ namespace chaiscript try { cond = boxed_cast(this->children[0]->eval(t_ss)); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); t_ss.pop_scope(); throw; @@ -818,7 +818,7 @@ namespace chaiscript } catch (const exception::bad_boxed_cast &) { t_ss.pop_scope(); - throw Eval_Error("For condition not boolean"); + throw exception::eval_error("For condition not boolean"); } while (cond) { try { @@ -826,7 +826,7 @@ namespace chaiscript try { this->children[3]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[3]); throw; } @@ -834,7 +834,7 @@ namespace chaiscript try { this->children[2]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[2]); throw; } @@ -842,7 +842,7 @@ namespace chaiscript try { cond = boxed_cast(this->children[1]->eval(t_ss)); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]); throw; } @@ -851,7 +851,7 @@ namespace chaiscript try { this->children[2]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[2]); throw; } @@ -859,7 +859,7 @@ namespace chaiscript try { this->children[1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[1]); throw; } @@ -867,7 +867,7 @@ namespace chaiscript try { cond = boxed_cast(this->children[0]->eval(t_ss)); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); t_ss.pop_scope(); throw; @@ -876,9 +876,9 @@ namespace chaiscript } catch (const exception::bad_boxed_cast &) { t_ss.pop_scope(); - throw Eval_Error("For condition not boolean"); + throw exception::eval_error("For condition not boolean"); } - catch (Break_Loop &) { + catch (detail::Break_Loop &) { cond = false; } } @@ -900,7 +900,7 @@ namespace chaiscript try { vec.push_back(this->children[0]->children[i]->eval(t_ss)); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]->children[i]); throw; } @@ -925,7 +925,7 @@ namespace chaiscript retval[boxed_cast(this->children[0]->children[i]->children[0]->eval(t_ss))] = t_ss.call_function("clone", this->children[0]->children[i]->children[1]->eval(t_ss)); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]->children[i]); throw; } @@ -933,7 +933,7 @@ namespace chaiscript return const_var(retval); } catch (const exception::dispatch_error &) { - throw Eval_Error("Can not find appropriate 'Map()'"); + throw exception::eval_error("Can not find appropriate 'Map()'"); } } @@ -947,15 +947,15 @@ namespace chaiscript virtual Boxed_Value eval(Dispatch_Engine &t_ss){ if (this->children.size() > 0) { try { - throw Return_Value(this->children[0]->eval(t_ss)); + throw detail::Return_Value(this->children[0]->eval(t_ss)); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } } else { - throw Return_Value(Boxed_Value()); + throw detail::Return_Value(Boxed_Value()); } } @@ -975,7 +975,7 @@ namespace chaiscript return retval; } } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i]); throw; } @@ -994,7 +994,7 @@ namespace chaiscript return t_ss.call_function(this->children[0]->text, this->children[1]->eval(t_ss)); } catch(std::exception &){ - throw Eval_Error("Can not find appropriate unary '" + this->children[0]->text + "'"); + throw exception::eval_error("Can not find appropriate unary '" + this->children[0]->text + "'"); } } @@ -1006,7 +1006,7 @@ namespace chaiscript AST_Node(t_ast_node_text, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { } virtual ~Break_AST_Node() {} virtual Boxed_Value eval(Dispatch_Engine &){ - throw Break_Loop(); + throw detail::Break_Loop(); } }; @@ -1036,9 +1036,9 @@ namespace chaiscript this->children[0]->children[0]->children[1]->eval(t_ss)); } catch (const exception::dispatch_error &) { - throw Eval_Error("Unable to generate range vector"); + throw exception::eval_error("Unable to generate range vector"); } - catch(Eval_Error &ee) { + catch(exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]->children[0]); throw; } @@ -1065,13 +1065,13 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); if (this->children.back()->identifier == AST_Node_Type::Finally) { try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee2) { + catch (exception::eval_error &ee2) { ee2.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; @@ -1096,7 +1096,7 @@ namespace chaiscript try { retval = catch_block->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[0]); throw; } @@ -1108,7 +1108,7 @@ namespace chaiscript try { retval = catch_block->children[1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[1]); throw; } @@ -1127,20 +1127,20 @@ namespace chaiscript try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; } } t_ss.pop_scope(); - throw Eval_Error("Guard condition not boolean"); + throw exception::eval_error("Guard condition not boolean"); } if (guard) { try { retval = catch_block->children[2]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[2]); throw; } @@ -1153,14 +1153,14 @@ namespace chaiscript try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; } } t_ss.pop_scope(); - throw Eval_Error("Internal error: catch block size unrecognized"); + throw exception::eval_error("Internal error: catch block size unrecognized"); } } } @@ -1174,7 +1174,7 @@ namespace chaiscript try { retval = catch_block->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[0]); throw; } @@ -1187,7 +1187,7 @@ namespace chaiscript try { retval = catch_block->children[1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[1]); throw; } @@ -1207,7 +1207,7 @@ namespace chaiscript try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; @@ -1215,9 +1215,9 @@ namespace chaiscript } t_ss.pop_scope(); - throw Eval_Error("Guard condition not boolean"); + throw exception::eval_error("Guard condition not boolean"); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[1]); throw; } @@ -1225,7 +1225,7 @@ namespace chaiscript try { retval = catch_block->children[2]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(catch_block->children[2]); throw; } @@ -1237,14 +1237,14 @@ namespace chaiscript try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; } } t_ss.pop_scope(); - throw Eval_Error("Internal error: catch block size unrecognized"); + throw exception::eval_error("Internal error: catch block size unrecognized"); } } } @@ -1253,7 +1253,7 @@ namespace chaiscript try { this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; @@ -1267,7 +1267,7 @@ namespace chaiscript try { retval = this->children.back()->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children.back()->children[0]); t_ss.pop_scope(); throw; @@ -1365,7 +1365,7 @@ namespace chaiscript } } catch (const exception::reserved_word_error &e) { - throw Eval_Error("Reserved word used as method name '" + e.word() + "'"); + throw exception::eval_error("Reserved word used as method name '" + e.word() + "'"); } return Boxed_Value(); } @@ -1384,7 +1384,7 @@ namespace chaiscript } catch (const exception::reserved_word_error &) { - throw Eval_Error("Reserved word used as attribute '" + this->children[1]->text + "'"); + throw exception::eval_error("Reserved word used as attribute '" + this->children[1]->text + "'"); } return Boxed_Value(); } @@ -1436,7 +1436,7 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -1448,13 +1448,13 @@ namespace chaiscript lhs = boxed_cast(retval); } catch (const exception::bad_boxed_cast &) { - throw Eval_Error("Condition not boolean"); + throw exception::eval_error("Condition not boolean"); } if (lhs) { try { retval = this->children[i+1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+1]); throw; } @@ -1479,7 +1479,7 @@ namespace chaiscript try { retval = this->children[0]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[0]); throw; } @@ -1491,7 +1491,7 @@ namespace chaiscript lhs = boxed_cast(retval); } catch (const exception::bad_boxed_cast &) { - throw Eval_Error("Condition not boolean"); + throw exception::eval_error("Condition not boolean"); } if (lhs) { retval = Boxed_Value(true); @@ -1500,7 +1500,7 @@ namespace chaiscript try { retval = this->children[i+1]->eval(t_ss); } - catch (Eval_Error &ee) { + catch (exception::eval_error &ee) { ee.call_stack.push_back(this->children[i+1]); throw; } diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index de8b393..1a574d6 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -16,566 +16,275 @@ namespace chaiscript { - namespace detail + namespace parser { - enum Alphabet - { symbol_alphabet = 0 + namespace detail + { + enum Alphabet + { symbol_alphabet = 0 , keyword_alphabet - , int_alphabet - , float_alphabet - , x_alphabet - , hex_alphabet - , b_alphabet - , bin_alphabet - , id_alphabet - , white_alphabet - , max_alphabet - , lengthof_alphabet = 256 - }; - } - - class ChaiScript_Parser { - - std::string::const_iterator m_input_pos, m_input_end; - int m_line, m_col; - std::string m_multiline_comment_begin; - std::string m_multiline_comment_end; - std::string m_singleline_comment; - boost::shared_ptr m_filename; - std::vector m_match_stack; - bool m_alphabet[detail::max_alphabet][detail::lengthof_alphabet]; - - std::vector > m_operator_matches; - std::vector m_operators; - - public: - ChaiScript_Parser() - : m_multiline_comment_begin("/*"), - m_multiline_comment_end("*/"), - m_singleline_comment("//") - { - setup_operators(); + , int_alphabet + , float_alphabet + , x_alphabet + , hex_alphabet + , b_alphabet + , bin_alphabet + , id_alphabet + , white_alphabet + , max_alphabet + , lengthof_alphabet = 256 + }; } - ChaiScript_Parser(const ChaiScript_Parser &); // explicitly unimplemented copy constructor - ChaiScript_Parser &operator=(const ChaiScript_Parser &); // explicitly unimplemented assignment operator + class ChaiScript_Parser { - void setup_operators() - { - m_operators.push_back(AST_Node_Type::Logical_Or); - std::vector logical_or; - logical_or.push_back("||"); - m_operator_matches.push_back(logical_or); + std::string::const_iterator m_input_pos, m_input_end; + int m_line, m_col; + std::string m_multiline_comment_begin; + std::string m_multiline_comment_end; + std::string m_singleline_comment; + boost::shared_ptr m_filename; + std::vector m_match_stack; + bool m_alphabet[detail::max_alphabet][detail::lengthof_alphabet]; - m_operators.push_back(AST_Node_Type::Logical_And); - std::vector logical_and; - logical_and.push_back("&&"); - m_operator_matches.push_back(logical_and); + std::vector > m_operator_matches; + std::vector m_operators; - m_operators.push_back(AST_Node_Type::Bitwise_Or); - std::vector bitwise_or; - bitwise_or.push_back("|"); - m_operator_matches.push_back(bitwise_or); - - m_operators.push_back(AST_Node_Type::Bitwise_Xor); - std::vector bitwise_xor; - bitwise_xor.push_back("^"); - m_operator_matches.push_back(bitwise_xor); - - m_operators.push_back(AST_Node_Type::Bitwise_And); - std::vector bitwise_and; - bitwise_and.push_back("&"); - m_operator_matches.push_back(bitwise_and); - - m_operators.push_back(AST_Node_Type::Equality); - std::vector equality; - equality.push_back("=="); - equality.push_back("!="); - m_operator_matches.push_back(equality); - - m_operators.push_back(AST_Node_Type::Comparison); - std::vector comparison; - comparison.push_back("<"); - comparison.push_back("<="); - comparison.push_back(">"); - comparison.push_back(">="); - m_operator_matches.push_back(comparison); - - m_operators.push_back(AST_Node_Type::Shift); - std::vector shift; - shift.push_back("<<"); - shift.push_back(">>"); - m_operator_matches.push_back(shift); - - m_operators.push_back(AST_Node_Type::Additive); - std::vector additive; - additive.push_back("+"); - additive.push_back("-"); - m_operator_matches.push_back(additive); - - m_operators.push_back(AST_Node_Type::Multiplicative); - std::vector multiplicative; - multiplicative.push_back("*"); - multiplicative.push_back("/"); - multiplicative.push_back("%"); - m_operator_matches.push_back(multiplicative); - - m_operators.push_back(AST_Node_Type::Dot_Access); - std::vector dot_access; - dot_access.push_back("."); - m_operator_matches.push_back(dot_access); - - for ( int c = 0 ; c < detail::lengthof_alphabet ; ++c ) { - for ( int a = 0 ; a < detail::max_alphabet ; a ++ ) { - m_alphabet[a][c]=false; - } - } - m_alphabet[detail::symbol_alphabet][static_cast('+')]=true; - m_alphabet[detail::symbol_alphabet][static_cast('-')]=true; - m_alphabet[detail::symbol_alphabet][static_cast('*')]=true; - m_alphabet[detail::symbol_alphabet][static_cast('/')]=true; - m_alphabet[detail::symbol_alphabet][static_cast('|')]=true; - m_alphabet[detail::symbol_alphabet][static_cast('&')]=true; - m_alphabet[detail::symbol_alphabet][static_cast('^')]=true; - m_alphabet[detail::symbol_alphabet][static_cast('=')]=true; - m_alphabet[detail::symbol_alphabet][static_cast('.')]=true; - m_alphabet[detail::symbol_alphabet][static_cast('<')]=true; - m_alphabet[detail::symbol_alphabet][static_cast('>')]=true; - - for ( int c = 'a' ; c <= 'z' ; ++c ) { m_alphabet[detail::keyword_alphabet][c]=true; } - for ( int c = 'A' ; c <= 'Z' ; ++c ) { m_alphabet[detail::keyword_alphabet][c]=true; } - for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::keyword_alphabet][c]=true; } - m_alphabet[detail::keyword_alphabet][static_cast('_')]=true; - - for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::int_alphabet][c]=true; } - for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::float_alphabet][c]=true; } - m_alphabet[detail::float_alphabet][static_cast('.')]=true; - - for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::hex_alphabet][c]=true; } - for ( int c = 'a' ; c <= 'f' ; ++c ) { m_alphabet[detail::hex_alphabet][c]=true; } - for ( int c = 'A' ; c <= 'F' ; ++c ) { m_alphabet[detail::hex_alphabet][c]=true; } - - m_alphabet[detail::x_alphabet][static_cast('x')]=true; - m_alphabet[detail::x_alphabet][static_cast('X')]=true; - - for ( int c = '0' ; c <= '1' ; ++c ) { m_alphabet[detail::bin_alphabet][c]=true; } - m_alphabet[detail::b_alphabet][static_cast('b')]=true; - m_alphabet[detail::b_alphabet][static_cast('B')]=true; - - for ( int c = 'a' ; c <= 'z' ; ++c ) { m_alphabet[detail::id_alphabet][c]=true; } - for ( int c = 'A' ; c <= 'Z' ; ++c ) { m_alphabet[detail::id_alphabet][c]=true; } - m_alphabet[detail::id_alphabet][static_cast('_')] = true; - - m_alphabet[detail::white_alphabet][static_cast(' ')]=true; - m_alphabet[detail::white_alphabet][static_cast('\t')]=true; - } - - /** - * test a char in an m_alphabet - */ - bool char_in_alphabet(unsigned char c, detail::Alphabet a) { return m_alphabet[a][c]; } - - /** - * Prints the parsed ast_nodes as a tree - */ - /* - void debug_print(AST_NodePtr t, std::string prepend = "") { - std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << std::endl; - for (unsigned int j = 0; j < t->children.size(); ++j) { - debug_print(t->children[j], prepend + " "); - } - } - */ - - /** - * Shows the current stack of matched ast_nodes - */ - void show_match_stack() { - for (unsigned int i = 0; i < m_match_stack.size(); ++i) { - //debug_print(match_stack[i]); - std::cout << m_match_stack[i]->to_string(); - } - } - - /** - * Clears the stack of matched ast_nodes - */ - void clear_match_stack() { - m_match_stack.clear(); - } - - /** - * Returns the front-most AST node - */ - AST_NodePtr ast() { - return m_match_stack.front(); - } - - /** - * Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node - */ - void build_match(AST_NodePtr t_t, size_t t_match_start) { - int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop; - int is_deep = false; - - //so we want to take everything to the right of this and make them children - if (t_match_start != m_match_stack.size()) { - pos_line_start = m_match_stack[t_match_start]->start.line; - pos_col_start = m_match_stack[t_match_start]->start.column; - pos_line_stop = m_line; - pos_col_stop = m_col; - is_deep = true; - } - else { - pos_line_start = m_line; - pos_col_start = m_col; - pos_line_stop = m_line; - pos_col_stop = m_col; + public: + ChaiScript_Parser() + : m_multiline_comment_begin("/*"), + m_multiline_comment_end("*/"), + m_singleline_comment("//") + { + setup_operators(); } - t_t->filename = m_filename; - t_t->start.line = pos_line_start; - t_t->start.column = pos_col_start; - t_t->end.line = pos_line_stop; - t_t->end.column = pos_col_stop; + ChaiScript_Parser(const ChaiScript_Parser &); // explicitly unimplemented copy constructor + ChaiScript_Parser &operator=(const ChaiScript_Parser &); // explicitly unimplemented assignment operator - if (is_deep) { - t_t->children.assign(m_match_stack.begin() + t_match_start, m_match_stack.end()); - m_match_stack.erase(m_match_stack.begin() + t_match_start, m_match_stack.end()); - m_match_stack.push_back(t_t); - } - else { - //todo: fix the fact that a successful match that captured no ast_nodes doesn't have any real start position - m_match_stack.push_back(t_t); - } - } + void setup_operators() + { + m_operators.push_back(AST_Node_Type::Logical_Or); + std::vector logical_or; + logical_or.push_back("||"); + m_operator_matches.push_back(logical_or); - /** - * Check to see if there is more text parse - */ - inline bool has_more_input() { - return (m_input_pos != m_input_end); - } + m_operators.push_back(AST_Node_Type::Logical_And); + std::vector logical_and; + logical_and.push_back("&&"); + m_operator_matches.push_back(logical_and); - /** - * Skips any multi-line or single-line comment - */ - bool SkipComment() { - bool retval = false; + m_operators.push_back(AST_Node_Type::Bitwise_Or); + std::vector bitwise_or; + bitwise_or.push_back("|"); + m_operator_matches.push_back(bitwise_or); - if (Symbol_(m_multiline_comment_begin.c_str())) { - while (m_input_pos != m_input_end) { - if (Symbol_(m_multiline_comment_end.c_str())) { - break; - } - else if (!Eol_()) { - ++m_col; - ++m_input_pos; + m_operators.push_back(AST_Node_Type::Bitwise_Xor); + std::vector bitwise_xor; + bitwise_xor.push_back("^"); + m_operator_matches.push_back(bitwise_xor); + + m_operators.push_back(AST_Node_Type::Bitwise_And); + std::vector bitwise_and; + bitwise_and.push_back("&"); + m_operator_matches.push_back(bitwise_and); + + m_operators.push_back(AST_Node_Type::Equality); + std::vector equality; + equality.push_back("=="); + equality.push_back("!="); + m_operator_matches.push_back(equality); + + m_operators.push_back(AST_Node_Type::Comparison); + std::vector comparison; + comparison.push_back("<"); + comparison.push_back("<="); + comparison.push_back(">"); + comparison.push_back(">="); + m_operator_matches.push_back(comparison); + + m_operators.push_back(AST_Node_Type::Shift); + std::vector shift; + shift.push_back("<<"); + shift.push_back(">>"); + m_operator_matches.push_back(shift); + + m_operators.push_back(AST_Node_Type::Additive); + std::vector additive; + additive.push_back("+"); + additive.push_back("-"); + m_operator_matches.push_back(additive); + + m_operators.push_back(AST_Node_Type::Multiplicative); + std::vector multiplicative; + multiplicative.push_back("*"); + multiplicative.push_back("/"); + multiplicative.push_back("%"); + m_operator_matches.push_back(multiplicative); + + m_operators.push_back(AST_Node_Type::Dot_Access); + std::vector dot_access; + dot_access.push_back("."); + m_operator_matches.push_back(dot_access); + + for ( int c = 0 ; c < detail::lengthof_alphabet ; ++c ) { + for ( int a = 0 ; a < detail::max_alphabet ; a ++ ) { + m_alphabet[a][c]=false; } } - retval = true; - } - else if (Symbol_(m_singleline_comment.c_str())) { - while (m_input_pos != m_input_end) { - if (Symbol_("\r\n")) { - m_input_pos -= 2; - break; - } - else if (Char_('\n')) { - --m_input_pos; - break; - } - else { - ++m_col; - ++m_input_pos; - } - } - retval = true; - } - return retval; - } + m_alphabet[detail::symbol_alphabet][static_cast('+')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('-')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('*')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('/')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('|')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('&')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('^')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('=')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('.')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('<')]=true; + m_alphabet[detail::symbol_alphabet][static_cast('>')]=true; - /** - * Skips ChaiScript whitespace, which means space and tab, but not cr/lf - */ - bool SkipWS() { - bool retval = false; - while (has_more_input()) { - if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) ) { - ++m_input_pos; - ++m_col; - retval = true; + for ( int c = 'a' ; c <= 'z' ; ++c ) { m_alphabet[detail::keyword_alphabet][c]=true; } + for ( int c = 'A' ; c <= 'Z' ; ++c ) { m_alphabet[detail::keyword_alphabet][c]=true; } + for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::keyword_alphabet][c]=true; } + m_alphabet[detail::keyword_alphabet][static_cast('_')]=true; + + for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::int_alphabet][c]=true; } + for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::float_alphabet][c]=true; } + m_alphabet[detail::float_alphabet][static_cast('.')]=true; + + for ( int c = '0' ; c <= '9' ; ++c ) { m_alphabet[detail::hex_alphabet][c]=true; } + for ( int c = 'a' ; c <= 'f' ; ++c ) { m_alphabet[detail::hex_alphabet][c]=true; } + for ( int c = 'A' ; c <= 'F' ; ++c ) { m_alphabet[detail::hex_alphabet][c]=true; } + + m_alphabet[detail::x_alphabet][static_cast('x')]=true; + m_alphabet[detail::x_alphabet][static_cast('X')]=true; + + for ( int c = '0' ; c <= '1' ; ++c ) { m_alphabet[detail::bin_alphabet][c]=true; } + m_alphabet[detail::b_alphabet][static_cast('b')]=true; + m_alphabet[detail::b_alphabet][static_cast('B')]=true; + + for ( int c = 'a' ; c <= 'z' ; ++c ) { m_alphabet[detail::id_alphabet][c]=true; } + for ( int c = 'A' ; c <= 'Z' ; ++c ) { m_alphabet[detail::id_alphabet][c]=true; } + m_alphabet[detail::id_alphabet][static_cast('_')] = true; + + m_alphabet[detail::white_alphabet][static_cast(' ')]=true; + m_alphabet[detail::white_alphabet][static_cast('\t')]=true; + } + + /** + * test a char in an m_alphabet + */ + bool char_in_alphabet(unsigned char c, detail::Alphabet a) { return m_alphabet[a][c]; } + + /** + * Prints the parsed ast_nodes as a tree + */ + /* + void debug_print(AST_NodePtr t, std::string prepend = "") { + std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << std::endl; + for (unsigned int j = 0; j < t->children.size(); ++j) { + debug_print(t->children[j], prepend + " "); + } + } + */ + + /** + * Shows the current stack of matched ast_nodes + */ + void show_match_stack() { + for (unsigned int i = 0; i < m_match_stack.size(); ++i) { + //debug_print(match_stack[i]); + std::cout << m_match_stack[i]->to_string(); } - else if (SkipComment()) { - retval = true; + } + + /** + * Clears the stack of matched ast_nodes + */ + void clear_match_stack() { + m_match_stack.clear(); + } + + /** + * Returns the front-most AST node + */ + AST_NodePtr ast() { + return m_match_stack.front(); + } + + /** + * Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node + */ + void build_match(AST_NodePtr t_t, size_t t_match_start) { + int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop; + int is_deep = false; + + //so we want to take everything to the right of this and make them children + if (t_match_start != m_match_stack.size()) { + pos_line_start = m_match_stack[t_match_start]->start.line; + pos_col_start = m_match_stack[t_match_start]->start.column; + pos_line_stop = m_line; + pos_col_stop = m_col; + is_deep = true; } else { - break; + pos_line_start = m_line; + pos_col_start = m_col; + pos_line_stop = m_line; + pos_col_stop = m_col; } - } - return retval; - } - /** - * Reads a floating point value from input, without skipping initial whitespace - */ - bool Float_() { - bool retval = false; - std::string::const_iterator start = m_input_pos; + t_t->filename = m_filename; + t_t->start.line = pos_line_start; + t_t->start.column = pos_col_start; + t_t->end.line = pos_line_stop; + t_t->end.column = pos_col_stop; - if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) { - while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { - ++m_input_pos; - ++m_col; - } - if (has_more_input() && (*m_input_pos == '.')) { - ++m_input_pos; - ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet)) { - retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { - ++m_input_pos; - ++m_col; - } - } - else { - --m_input_pos; - --m_col; - } - } - } - return retval; - } - - /** - * Reads a floating point value from input, without skipping initial whitespace - */ - bool Hex_() { - bool retval = false; - if (has_more_input() && (*m_input_pos == '0')) { - ++m_input_pos; - ++m_col; - - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::x_alphabet) ) { - ++m_input_pos; - ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet)) { - retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet) ) { - ++m_input_pos; - ++m_col; - } - } - else { - --m_input_pos; - --m_col; - } + if (is_deep) { + t_t->children.assign(m_match_stack.begin() + t_match_start, m_match_stack.end()); + m_match_stack.erase(m_match_stack.begin() + t_match_start, m_match_stack.end()); + m_match_stack.push_back(t_t); } else { - --m_input_pos; - --m_col; + //todo: fix the fact that a successful match that captured no ast_nodes doesn't have any real start position + m_match_stack.push_back(t_t); } } - return retval; - } - - /** - * Reads a floating point value from input, without skipping initial whitespace - */ - bool Binary_() { - bool retval = false; - if (has_more_input() && (*m_input_pos == '0')) { - ++m_input_pos; - ++m_col; - - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::b_alphabet) ) { - ++m_input_pos; - ++m_col; - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { - retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { - ++m_input_pos; - ++m_col; - } - } - else { - --m_input_pos; - --m_col; - } - } - else { - --m_input_pos; - --m_col; - } + /** + * Check to see if there is more text parse + */ + inline bool has_more_input() { + return (m_input_pos != m_input_end); } - return retval; - } + /** + * Skips any multi-line or single-line comment + */ + bool SkipComment() { + bool retval = false; - /** - * Reads a number from the input, detecting if it's an integer or floating point - */ - bool Num(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Hex_() || Float_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) { - if (Hex_()) { - std::string match(start, m_input_pos); - std::stringstream ss(match); - unsigned int temp_int; - ss >> std::hex >> temp_int; - - std::ostringstream out_int; - out_int << static_cast(temp_int); - AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - if (Binary_()) { - std::string match(start, m_input_pos); - int temp_int = 0; - size_t pos = 0, end = match.length(); - - while ((pos < end) && (pos < (2 + sizeof(int) * 8))) { - temp_int <<= 1; - if (match[pos] == '1') { - temp_int += 1; - } - ++pos; - } - - std::ostringstream out_int; - out_int << temp_int; - AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - if (Float_()) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Float_AST_Node(match, AST_Node_Type::Float, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - std::string match(start, m_input_pos); - if ((match.size() > 0) && (match[0] == '0')) { - std::stringstream ss(match); - unsigned int temp_int; - ss >> std::oct >> temp_int; - - std::ostringstream out_int; - out_int << int(temp_int); - AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - else { - AST_NodePtr t(new eval::Int_AST_Node(match, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - return true; - } - } - else { - return false; - } - } - } - - /** - * Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace - */ - bool Id_() { - bool retval = false; - if (has_more_input() && char_in_alphabet(*m_input_pos, detail::id_alphabet)) { - retval = true; - while (has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { - ++m_input_pos; - ++m_col; - } - } - else if (has_more_input() && (*m_input_pos == '`')) { - retval = true; - ++m_col; - ++m_input_pos; - std::string::const_iterator start = m_input_pos; - - while (has_more_input() && (*m_input_pos != '`')) { - if (Eol()) { - throw Eval_Error("Carriage return in identifier literal", File_Position(m_line, m_col), *m_filename); - } - else { - ++m_input_pos; - ++m_col; - } - } - - if (start == m_input_pos) { - throw Eval_Error("Missing contents of identifier literal", File_Position(m_line, m_col), *m_filename); - } - else if (m_input_pos == m_input_end) { - throw Eval_Error("Incomplete identifier literal", File_Position(m_line, m_col), *m_filename); - } - - ++m_col; - ++m_input_pos; - } - return retval; - } - - /** - * Reads (and potentially captures) an identifier from input - */ - bool Id(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Id_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Id_()) { - if (*start == '`') { - //Id Literal - std::string match(start+1, m_input_pos-1); - AST_NodePtr t(new eval::Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - } - else { - return false; - } - } - } - - /** - * Checks for a node annotation of the form "#" - */ - bool Annotation() { - SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Symbol_("#")) { - do { + if (Symbol_(m_multiline_comment_begin.c_str())) { while (m_input_pos != m_input_end) { - if (Eol_()) { + if (Symbol_(m_multiline_comment_end.c_str())) { + break; + } + else if (!Eol_()) { + ++m_col; + ++m_input_pos; + } + } + retval = true; + } + else if (Symbol_(m_singleline_comment.c_str())) { + while (m_input_pos != m_input_end) { + if (Symbol_("\r\n")) { + m_input_pos -= 2; + break; + } + else if (Char_('\n')) { + --m_input_pos; break; } else { @@ -583,1392 +292,1686 @@ namespace chaiscript ++m_input_pos; } } - } while (Symbol("#")); - - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Annotation_AST_Node(match, AST_Node_Type::Annotation, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; + retval = true; + } + return retval; } - else { - return false; + + /** + * Skips ChaiScript whitespace, which means space and tab, but not cr/lf + */ + bool SkipWS() { + bool retval = false; + while (has_more_input()) { + if ( char_in_alphabet(*m_input_pos,detail::white_alphabet) ) { + ++m_input_pos; + ++m_col; + retval = true; + } + else if (SkipComment()) { + retval = true; + } + else { + break; + } + } + return retval; } - } - /** - * Reads a quoted string from input, without skipping initial whitespace - */ - bool Quoted_String_() { - bool retval = false; - char prev_char = 0; - if (has_more_input() && (*m_input_pos == '\"')) { - retval = true; - prev_char = *m_input_pos; - ++m_input_pos; - ++m_col; + /** + * Reads a floating point value from input, without skipping initial whitespace + */ + bool Float_() { + bool retval = false; + std::string::const_iterator start = m_input_pos; - while (has_more_input() && ((*m_input_pos != '\"') || ((*m_input_pos == '\"') && (prev_char == '\\')))) { - if (!Eol_()) { - if (prev_char == '\\') { - prev_char = 0; + if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) { + while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { + ++m_input_pos; + ++m_col; + } + if (has_more_input() && (*m_input_pos == '.')) { + ++m_input_pos; + ++m_col; + if (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet)) { + retval = true; + while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { + ++m_input_pos; + ++m_col; + } } else { - prev_char = *m_input_pos; + --m_input_pos; + --m_col; } + } + } + return retval; + } + + /** + * Reads a floating point value from input, without skipping initial whitespace + */ + bool Hex_() { + bool retval = false; + if (has_more_input() && (*m_input_pos == '0')) { + ++m_input_pos; + ++m_col; + + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::x_alphabet) ) { + ++m_input_pos; + ++m_col; + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet)) { + retval = true; + while (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet) ) { + ++m_input_pos; + ++m_col; + } + } + else { + --m_input_pos; + --m_col; + } + } + else { + --m_input_pos; + --m_col; + } + } + + return retval; + } + + /** + * Reads a floating point value from input, without skipping initial whitespace + */ + bool Binary_() { + bool retval = false; + if (has_more_input() && (*m_input_pos == '0')) { + ++m_input_pos; + ++m_col; + + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::b_alphabet) ) { + ++m_input_pos; + ++m_col; + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { + retval = true; + while (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { + ++m_input_pos; + ++m_col; + } + } + else { + --m_input_pos; + --m_col; + } + } + else { + --m_input_pos; + --m_col; + } + } + + return retval; + } + + /** + * Reads a number from the input, detecting if it's an integer or floating point + */ + bool Num(bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Hex_() || Float_(); + } + else { + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_alphabet) ) { + if (Hex_()) { + std::string match(start, m_input_pos); + std::stringstream ss(match); + unsigned int temp_int; + ss >> std::hex >> temp_int; + + std::ostringstream out_int; + out_int << static_cast(temp_int); + AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + if (Binary_()) { + std::string match(start, m_input_pos); + int temp_int = 0; + size_t pos = 0, end = match.length(); + + while ((pos < end) && (pos < (2 + sizeof(int) * 8))) { + temp_int <<= 1; + if (match[pos] == '1') { + temp_int += 1; + } + ++pos; + } + + std::ostringstream out_int; + out_int << temp_int; + AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + if (Float_()) { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Float_AST_Node(match, AST_Node_Type::Float, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + std::string match(start, m_input_pos); + if ((match.size() > 0) && (match[0] == '0')) { + std::stringstream ss(match); + unsigned int temp_int; + ss >> std::oct >> temp_int; + + std::ostringstream out_int; + out_int << int(temp_int); + AST_NodePtr t(new eval::Int_AST_Node(out_int.str(), AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + } + else { + AST_NodePtr t(new eval::Int_AST_Node(match, AST_Node_Type::Int, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + } + return true; + } + } + else { + return false; + } + } + } + + /** + * Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace + */ + bool Id_() { + bool retval = false; + if (has_more_input() && char_in_alphabet(*m_input_pos, detail::id_alphabet)) { + retval = true; + while (has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { ++m_input_pos; ++m_col; } } - - if (has_more_input()) { - ++m_input_pos; + else if (has_more_input() && (*m_input_pos == '`')) { + retval = true; ++m_col; + ++m_input_pos; + std::string::const_iterator start = m_input_pos; + + while (has_more_input() && (*m_input_pos != '`')) { + if (Eol()) { + throw exception::eval_error("Carriage return in identifier literal", File_Position(m_line, m_col), *m_filename); + } + else { + ++m_input_pos; + ++m_col; + } + } + + if (start == m_input_pos) { + throw exception::eval_error("Missing contents of identifier literal", File_Position(m_line, m_col), *m_filename); + } + else if (m_input_pos == m_input_end) { + throw exception::eval_error("Incomplete identifier literal", File_Position(m_line, m_col), *m_filename); + } + + ++m_col; + ++m_input_pos; + } + return retval; + } + + /** + * Reads (and potentially captures) an identifier from input + */ + bool Id(bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Id_(); } else { - throw Eval_Error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename); + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (Id_()) { + if (*start == '`') { + //Id Literal + std::string match(start+1, m_input_pos-1); + AST_NodePtr t(new eval::Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Id_AST_Node(match, AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + } + else { + return false; + } } } - return retval; - } - /** - * Reads (and potentially captures) a quoted string from input. Translates escaped sequences. - */ - bool Quoted_String(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Quoted_String_(); - } - else { + /** + * Checks for a node annotation of the form "#" + */ + bool Annotation() { + SkipWS(); std::string::const_iterator start = m_input_pos; int prev_col = m_col; int prev_line = m_line; - if (Quoted_String_()) { - std::string match; - bool is_escaped = false; - bool is_interpolated = false; - bool saw_interpolation_marker = false; - size_t prev_stack_top = m_match_stack.size(); + if (Symbol_("#")) { + do { + while (m_input_pos != m_input_end) { + if (Eol_()) { + break; + } + else { + ++m_col; + ++m_input_pos; + } + } + } while (Symbol("#")); - //for (std::string::iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { - std::string::const_iterator s = start + 1, end = m_input_pos - 1; + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Annotation_AST_Node(match, AST_Node_Type::Annotation, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + return false; + } + } - while (s != end) { - if (saw_interpolation_marker) { - if (*s == '{') { - //We've found an interpolation point + /** + * Reads a quoted string from input, without skipping initial whitespace + */ + bool Quoted_String_() { + bool retval = false; + char prev_char = 0; + if (has_more_input() && (*m_input_pos == '\"')) { + retval = true; + prev_char = *m_input_pos; + ++m_input_pos; + ++m_col; + + while (has_more_input() && ((*m_input_pos != '\"') || ((*m_input_pos == '\"') && (prev_char == '\\')))) { + if (!Eol_()) { + if (prev_char == '\\') { + prev_char = 0; + } + else { + prev_char = *m_input_pos; + } + ++m_input_pos; + ++m_col; + } + } + + if (has_more_input()) { + ++m_input_pos; + ++m_col; + } + else { + throw exception::eval_error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename); + } + } + return retval; + } + + /** + * Reads (and potentially captures) a quoted string from input. Translates escaped sequences. + */ + bool Quoted_String(bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Quoted_String_(); + } + else { + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (Quoted_String_()) { + std::string match; + bool is_escaped = false; + bool is_interpolated = false; + bool saw_interpolation_marker = false; + size_t prev_stack_top = m_match_stack.size(); + + //for (std::string::iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { + std::string::const_iterator s = start + 1, end = m_input_pos - 1; + + while (s != end) { + if (saw_interpolation_marker) { + if (*s == '{') { + //We've found an interpolation point + + if (is_interpolated) { + //If we've seen previous interpolation, add on instead of making a new one + AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(plus); + + AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + + build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + } + else { + AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + } + + //We've finished with the part of the string up to this point, so clear it + match = ""; - if (is_interpolated) { - //If we've seen previous interpolation, add on instead of making a new one AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); m_match_stack.push_back(plus); - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + std::string eval_match; - build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); - } - else { - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - - //We've finished with the part of the string up to this point, so clear it - match = ""; - - AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(plus); - - std::string eval_match; - - ++s; - while ((*s != '}') && (s != end)) { - eval_match.push_back(*s); - ++s; - } - if (*s == '}') { - is_interpolated = true; ++s; + while ((*s != '}') && (s != end)) { + eval_match.push_back(*s); + ++s; + } + if (*s == '}') { + is_interpolated = true; + ++s; - size_t tostr_stack_top = m_match_stack.size(); + size_t tostr_stack_top = m_match_stack.size(); - AST_NodePtr tostr(new eval::Id_AST_Node("to_string", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(tostr); + AST_NodePtr tostr(new eval::Id_AST_Node("to_string", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(tostr); - size_t ev_stack_top = m_match_stack.size(); + size_t ev_stack_top = m_match_stack.size(); - AST_NodePtr ev(new eval::Id_AST_Node("eval", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(ev); + AST_NodePtr ev(new eval::Id_AST_Node("eval", AST_Node_Type::Id, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(ev); - size_t arg_stack_top = m_match_stack.size(); + size_t arg_stack_top = m_match_stack.size(); - AST_NodePtr t(new eval::Quoted_String_AST_Node(eval_match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + AST_NodePtr t(new eval::Quoted_String_AST_Node(eval_match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), arg_stack_top); + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), arg_stack_top); - build_match(AST_NodePtr(new eval::Inplace_Fun_Call_AST_Node()), ev_stack_top); + build_match(AST_NodePtr(new eval::Inplace_Fun_Call_AST_Node()), ev_stack_top); - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), ev_stack_top); + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), ev_stack_top); - build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), tostr_stack_top); + build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), tostr_stack_top); - build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); - } - else { - throw Eval_Error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename); - } - } - else { - match.push_back('$'); - } - saw_interpolation_marker = false; - } - else { - if (*s == '\\') { - if (is_escaped) { - match.push_back('\\'); - is_escaped = false; - } - else { - is_escaped = true; - } - } - else { - if (is_escaped) { - switch (*s) { - case ('b') : match.push_back('\b'); break; - case ('f') : match.push_back('\f'); break; - case ('n') : match.push_back('\n'); break; - case ('r') : match.push_back('\r'); break; - case ('t') : match.push_back('\t'); break; - case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; - case ('$') : match.push_back('$'); break; - default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); + build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + } + else { + throw exception::eval_error("Unclosed in-string eval", File_Position(prev_line, prev_col), *m_filename); } } - else if (*s == '$') { - saw_interpolation_marker = true; + else { + match.push_back('$'); + } + saw_interpolation_marker = false; + } + else { + if (*s == '\\') { + if (is_escaped) { + match.push_back('\\'); + is_escaped = false; + } + else { + is_escaped = true; + } } else { - match.push_back(*s); + if (is_escaped) { + switch (*s) { + case ('b') : match.push_back('\b'); break; + case ('f') : match.push_back('\f'); break; + case ('n') : match.push_back('\n'); break; + case ('r') : match.push_back('\r'); break; + case ('t') : match.push_back('\t'); break; + case ('\'') : match.push_back('\''); break; + case ('\"') : match.push_back('\"'); break; + case ('$') : match.push_back('$'); break; + default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); + } + } + else if (*s == '$') { + saw_interpolation_marker = true; + } + else { + match.push_back(*s); + } + is_escaped = false; } - is_escaped = false; + ++s; } - ++s; } - } - if (is_interpolated) { - AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(plus); + if (is_interpolated) { + AST_NodePtr plus(new eval::Str_AST_Node("+", AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(plus); - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); + AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); - build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + } + else { + AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + } + return true; } else { - AST_NodePtr t(new eval::Quoted_String_AST_Node(match, AST_Node_Type::Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - return true; - } - else { - return false; - } - } - } - - /** - * Reads a character group from input, without skipping initial whitespace - */ - bool Single_Quoted_String_() { - bool retval = false; - char prev_char = 0; - if (has_more_input() && (*m_input_pos == '\'')) { - retval = true; - prev_char = *m_input_pos; - ++m_input_pos; - ++m_col; - - while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { - if (!Eol_()) { - if (prev_char == '\\') { - prev_char = 0; - } - else { - prev_char = *m_input_pos; - } - ++m_input_pos; - ++m_col; - } - } - - if (m_input_pos != m_input_end) { - ++m_input_pos; - ++m_col; - } - else { - throw Eval_Error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); - } - } - return retval; - } - - /** - * Reads (and potentially captures) a char group from input. Translates escaped sequences. - */ - bool Single_Quoted_String(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Single_Quoted_String_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Single_Quoted_String_()) { - std::string match; - bool is_escaped = false; - for (std::string::const_iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { - if (*s == '\\') { - if (is_escaped) { - match.push_back('\\'); - is_escaped = false; - } - else { - is_escaped = true; - } - } - else { - if (is_escaped) { - switch (*s) { - case ('b') : match.push_back('\b'); break; - case ('f') : match.push_back('\f'); break; - case ('n') : match.push_back('\n'); break; - case ('r') : match.push_back('\r'); break; - case ('t') : match.push_back('\t'); break; - case ('\'') : match.push_back('\''); break; - case ('\"') : match.push_back('\"'); break; - default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); - } - } - else { - match.push_back(*s); - } - is_escaped = false; - } - } - AST_NodePtr t(new eval::Single_Quoted_String_AST_Node(match, AST_Node_Type::Single_Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - return false; - } - } - } - - /** - * Reads a char from input if it matches the parameter, without skipping initial whitespace - */ - bool Char_(char c) { - bool retval = false; - if (has_more_input() && (*m_input_pos == c)) { - ++m_input_pos; - ++m_col; - retval = true; - } - - return retval; - } - - /** - * Reads (and potentially captures) a char from input if it matches the parameter - */ - bool Char(char t_c, bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Char_(t_c); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Char_(t_c)) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Char_AST_Node(match, AST_Node_Type::Char, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - return false; - } - } - } - - /** - * Reads a string from input if it matches the parameter, without skipping initial whitespace - */ - bool Keyword_(const char *t_s) { - bool retval = false; - int len = static_cast(strlen(t_s)); - - if ((m_input_end - m_input_pos) >= len) { - std::string::const_iterator tmp = m_input_pos; - for (int i = 0; i < len; ++i) { - if (*tmp != t_s[i]) { return false; } - ++tmp; + } } - retval = true; - m_input_pos = tmp; - m_col += len; - } - return retval; - } + /** + * Reads a character group from input, without skipping initial whitespace + */ + bool Single_Quoted_String_() { + bool retval = false; + char prev_char = 0; + if (has_more_input() && (*m_input_pos == '\'')) { + retval = true; + prev_char = *m_input_pos; + ++m_input_pos; + ++m_col; - /** - * Reads (and potentially captures) a string from input if it matches the parameter - */ - bool Keyword(const char *t_s, bool t_capture = false) { - SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - bool retval = Keyword_(t_s); - // ignore substring matches - if ( retval && has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { + while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { + if (!Eol_()) { + if (prev_char == '\\') { + prev_char = 0; + } + else { + prev_char = *m_input_pos; + } + ++m_input_pos; + ++m_col; + } + } + + if (m_input_pos != m_input_end) { + ++m_input_pos; + ++m_col; + } + else { + throw exception::eval_error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); + } + } + return retval; + } + + /** + * Reads (and potentially captures) a char group from input. Translates escaped sequences. + */ + bool Single_Quoted_String(bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Single_Quoted_String_(); + } + else { + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (Single_Quoted_String_()) { + std::string match; + bool is_escaped = false; + for (std::string::const_iterator s = start + 1, end = m_input_pos - 1; s != end; ++s) { + if (*s == '\\') { + if (is_escaped) { + match.push_back('\\'); + is_escaped = false; + } + else { + is_escaped = true; + } + } + else { + if (is_escaped) { + switch (*s) { + case ('b') : match.push_back('\b'); break; + case ('f') : match.push_back('\f'); break; + case ('n') : match.push_back('\n'); break; + case ('r') : match.push_back('\r'); break; + case ('t') : match.push_back('\t'); break; + case ('\'') : match.push_back('\''); break; + case ('\"') : match.push_back('\"'); break; + default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), *m_filename); + } + } + else { + match.push_back(*s); + } + is_escaped = false; + } + } + AST_NodePtr t(new eval::Single_Quoted_String_AST_Node(match, AST_Node_Type::Single_Quoted_String, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + /** + * Reads a char from input if it matches the parameter, without skipping initial whitespace + */ + bool Char_(char c) { + bool retval = false; + if (has_more_input() && (*m_input_pos == c)) { + ++m_input_pos; + ++m_col; + retval = true; + } + + return retval; + } + + /** + * Reads (and potentially captures) a char from input if it matches the parameter + */ + bool Char(char t_c, bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Char_(t_c); + } + else { + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (Char_(t_c)) { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Char_AST_Node(match, AST_Node_Type::Char, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + /** + * Reads a string from input if it matches the parameter, without skipping initial whitespace + */ + bool Keyword_(const char *t_s) { + bool retval = false; + int len = static_cast(strlen(t_s)); + + if ((m_input_end - m_input_pos) >= len) { + std::string::const_iterator tmp = m_input_pos; + for (int i = 0; i < len; ++i) { + if (*tmp != t_s[i]) { + return false; + } + ++tmp; + } + retval = true; + m_input_pos = tmp; + m_col += len; + } + + return retval; + } + + /** + * Reads (and potentially captures) a string from input if it matches the parameter + */ + bool Keyword(const char *t_s, bool t_capture = false) { + SkipWS(); + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + bool retval = Keyword_(t_s); + // ignore substring matches + if ( retval && has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { m_input_pos = start; m_col = prev_col; m_line = prev_line; retval = false; - } - - if ( t_capture && retval ) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Str_AST_Node(match, AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - return retval; - } - - /** - * Reads a symbol group from input if it matches the parameter, without skipping initial whitespace - */ - bool Symbol_(const char *t_s) { - bool retval = false; - int len = static_cast(strlen(t_s)); - - if ((m_input_end - m_input_pos) >= len) { - std::string::const_iterator tmp = m_input_pos; - for (int i = 0; i < len; ++i) { - if (*tmp != t_s[i]) { - return false; } - ++tmp; - } - retval = true; - m_input_pos = tmp; - m_col += len; - } - return retval; - } - - /** - * Reads (and potentially captures) a symbol group from input if it matches the parameter - */ - bool Symbol(const char *t_s, bool t_capture = false, bool t_disallow_prevention=false) { - SkipWS(); - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - bool retval = Symbol_(t_s); - // ignore substring matches - if (retval && has_more_input() && (t_disallow_prevention == false) && char_in_alphabet(*m_input_pos,detail::symbol_alphabet)) { - m_input_pos = start; - m_col = prev_col; - m_line = prev_line; - retval = false; - } - - if ( t_capture && retval ) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Str_AST_Node(match, AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - } - - return retval; - } - - /** - * Reads an end-of-line group from input, without skipping initial whitespace - */ - bool Eol_() { - bool retval = false; - - if (has_more_input() && (Symbol_("\r\n") || Char_('\n'))) { - retval = true; - ++m_line; - m_col = 1; - } - else if (has_more_input() && Char_(';')) { - retval = true; - } - - return retval; - } - - /** - * Reads (and potentially captures) an end-of-line group from input - */ - bool Eol(bool t_capture = false) { - SkipWS(); - - if (!t_capture) { - return Eol_(); - } - else { - std::string::const_iterator start = m_input_pos; - int prev_col = m_col; - int prev_line = m_line; - if (Eol_()) { - std::string match(start, m_input_pos); - AST_NodePtr t(new eval::Eol_AST_Node(match, AST_Node_Type::Eol, m_filename, prev_line, prev_col, m_line, m_col)); - m_match_stack.push_back(t); - return true; - } - else { - return false; - } - } - } - - /** - * Reads a comma-separated list of values from input - */ - bool Arg_List() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Equation()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Equation()) { - throw Eval_Error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); - } - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads possible special container values, including ranges and map_pairs - */ - bool Container_Arg_List() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Value_Range()) { - retval = true; - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); - } - else if (Map_Pair()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Map_Pair()) { - throw Eval_Error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); - } - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); - } - else if (Operator()) { - retval = true; - while (Eol()) {} - if (Char(',')) { - do { - while (Eol()) {} - if (!Operator()) { - throw Eval_Error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); - } - } while (retval && Char(',')); - } - build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); - } - - return retval; - - } - - /** - * Reads a lambda (anonymous function) from input - */ - bool Lambda() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("fun")) { - retval = true; - - if (Char('(')) { - Arg_List(); - if (!Char(')')) { - throw Eval_Error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); + if ( t_capture && retval ) { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Str_AST_Node(match, AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); } + return retval; } - while (Eol()) {} + /** + * Reads a symbol group from input if it matches the parameter, without skipping initial whitespace + */ + bool Symbol_(const char *t_s) { + bool retval = false; + int len = static_cast(strlen(t_s)); - if (!Block()) { - throw Eval_Error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Lambda_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a function definition from input - */ - bool Def() { - bool retval = false; - bool is_annotated = false; - bool is_method = false; - AST_NodePtr annotation; - - if (Annotation()) { - while (Eol_()) {} - annotation = m_match_stack.back(); - m_match_stack.pop_back(); - is_annotated = true; - } - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("def")) { - retval = true; - - if (!Id(true)) { - throw Eval_Error("Missing function name in definition", File_Position(m_line, m_col), *m_filename); - } - - if (Symbol("::", false)) { - //We're now a method - is_method = true; - - if (!Id(true)) { - throw Eval_Error("Missing method name in definition", File_Position(m_line, m_col), *m_filename); - } - } - - if (Char('(')) { - Arg_List(); - if (!Char(')')) { - throw Eval_Error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); - } - } - - while (Eol()) {} - - if (Char(':')) { - if (!Operator()) { - throw Eval_Error("Missing guard expression for function", File_Position(m_line, m_col), *m_filename); - } - } - - while (Eol()) {} - if (!Block()) { - throw Eval_Error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); - } - - if (is_method) { - build_match(AST_NodePtr(new eval::Method_AST_Node()), prev_stack_top); - } - else { - build_match(AST_NodePtr(new eval::Def_AST_Node()), prev_stack_top); - } - - if (is_annotated) { - m_match_stack.back()->annotation = annotation; - } - } - - return retval; - } - - /** - * Reads a function definition from input - */ - bool Try() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("try")) { - retval = true; - - while (Eol()) {} - - if (!Block()) { - throw Eval_Error("Incomplete 'try' block", File_Position(m_line, m_col), *m_filename); - } - - bool has_matches = true; - while (has_matches) { - while (Eol()) {} - has_matches = false; - if (Keyword("catch", false)) { - size_t catch_stack_top = m_match_stack.size(); - if (Char('(')) { - if (!(Id(true) && Char(')'))) { - throw Eval_Error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename); + if ((m_input_end - m_input_pos) >= len) { + std::string::const_iterator tmp = m_input_pos; + for (int i = 0; i < len; ++i) { + if (*tmp != t_s[i]) { + return false; } - if (Char(':')) { - if (!Operator()) { - throw Eval_Error("Missing guard expression for catch", File_Position(m_line, m_col), *m_filename); + ++tmp; + } + retval = true; + m_input_pos = tmp; + m_col += len; + } + + return retval; + } + + /** + * Reads (and potentially captures) a symbol group from input if it matches the parameter + */ + bool Symbol(const char *t_s, bool t_capture = false, bool t_disallow_prevention=false) { + SkipWS(); + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + bool retval = Symbol_(t_s); + // ignore substring matches + if (retval && has_more_input() && (t_disallow_prevention == false) && char_in_alphabet(*m_input_pos,detail::symbol_alphabet)) { + m_input_pos = start; + m_col = prev_col; + m_line = prev_line; + retval = false; + } + + if ( t_capture && retval ) { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Str_AST_Node(match, AST_Node_Type::Str, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + } + + return retval; + } + + /** + * Reads an end-of-line group from input, without skipping initial whitespace + */ + bool Eol_() { + bool retval = false; + + if (has_more_input() && (Symbol_("\r\n") || Char_('\n'))) { + retval = true; + ++m_line; + m_col = 1; + } + else if (has_more_input() && Char_(';')) { + retval = true; + } + + return retval; + } + + /** + * Reads (and potentially captures) an end-of-line group from input + */ + bool Eol(bool t_capture = false) { + SkipWS(); + + if (!t_capture) { + return Eol_(); + } + else { + std::string::const_iterator start = m_input_pos; + int prev_col = m_col; + int prev_line = m_line; + if (Eol_()) { + std::string match(start, m_input_pos); + AST_NodePtr t(new eval::Eol_AST_Node(match, AST_Node_Type::Eol, m_filename, prev_line, prev_col, m_line, m_col)); + m_match_stack.push_back(t); + return true; + } + else { + return false; + } + } + } + + /** + * Reads a comma-separated list of values from input + */ + bool Arg_List() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Equation()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Equation()) { + throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename); } + } while (retval && Char(',')); + } + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); + } + + return retval; + } + + /** + * Reads possible special container values, including ranges and map_pairs + */ + bool Container_Arg_List() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Value_Range()) { + retval = true; + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); + } + else if (Map_Pair()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Map_Pair()) { + throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); + } + } while (retval && Char(',')); + } + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); + } + else if (Operator()) { + retval = true; + while (Eol()) {} + if (Char(',')) { + do { + while (Eol()) {} + if (!Operator()) { + throw exception::eval_error("Unexpected value in container", File_Position(m_line, m_col), *m_filename); + } + } while (retval && Char(',')); + } + build_match(AST_NodePtr(new eval::Arg_List_AST_Node()), prev_stack_top); + } + + return retval; + + } + + /** + * Reads a lambda (anonymous function) from input + */ + bool Lambda() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("fun")) { + retval = true; + + if (Char('(')) { + Arg_List(); + if (!Char(')')) { + throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); } } while (Eol()) {} if (!Block()) { - throw Eval_Error("Incomplete 'catch' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new eval::Catch_AST_Node()), catch_stack_top); - has_matches = true; + + build_match(AST_NodePtr(new eval::Lambda_AST_Node()), prev_stack_top); } + + return retval; } - while (Eol()) {} - if (Keyword("finally", false)) { - size_t finally_stack_top = m_match_stack.size(); - while (Eol()) {} + /** + * Reads a function definition from input + */ + bool Def() { + bool retval = false; + bool is_annotated = false; + bool is_method = false; + AST_NodePtr annotation; - if (!Block()) { - throw Eval_Error("Incomplete 'finally' block", File_Position(m_line, m_col), *m_filename); + if (Annotation()) { + while (Eol_()) {} + annotation = m_match_stack.back(); + m_match_stack.pop_back(); + is_annotated = true; } - build_match(AST_NodePtr(new eval::Finally_AST_Node()), finally_stack_top); - } - build_match(AST_NodePtr(new eval::Try_AST_Node()), prev_stack_top); - } + size_t prev_stack_top = m_match_stack.size(); - return retval; - } + if (Keyword("def")) { + retval = true; - /** - * Reads an if/elseif/else block from input - */ - bool If() { - bool retval = false; + if (!Id(true)) { + throw exception::eval_error("Missing function name in definition", File_Position(m_line, m_col), *m_filename); + } - size_t prev_stack_top = m_match_stack.size(); + if (Symbol("::", false)) { + //We're now a method + is_method = true; - if (Keyword("if")) { - retval = true; - - if (!Char('(')) { - throw Eval_Error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(Operator() && Char(')'))) { - throw Eval_Error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw Eval_Error("Incomplete 'if' block", File_Position(m_line, m_col), *m_filename); - } - - bool has_matches = true; - while (has_matches) { - while (Eol()) {} - has_matches = false; - if (Keyword("else", true)) { - if (Keyword("if")) { - m_match_stack.back()->text = "else if"; - if (!Char('(')) { - throw Eval_Error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + if (!Id(true)) { + throw exception::eval_error("Missing method name in definition", File_Position(m_line, m_col), *m_filename); } + } - if (!(Operator() && Char(')'))) { - throw Eval_Error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + if (Char('(')) { + Arg_List(); + if (!Char(')')) { + throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); } + } - while (Eol()) {} + while (Eol()) {} - if (!Block()) { - throw Eval_Error("Incomplete 'else if' block", File_Position(m_line, m_col), *m_filename); + if (Char(':')) { + if (!Operator()) { + throw exception::eval_error("Missing guard expression for function", File_Position(m_line, m_col), *m_filename); } - has_matches = true; + } + + while (Eol()) {} + if (!Block()) { + throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename); + } + + if (is_method) { + build_match(AST_NodePtr(new eval::Method_AST_Node()), prev_stack_top); } else { + build_match(AST_NodePtr(new eval::Def_AST_Node()), prev_stack_top); + } + + if (is_annotated) { + m_match_stack.back()->annotation = annotation; + } + } + + return retval; + } + + /** + * Reads a function definition from input + */ + bool Try() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("try")) { + retval = true; + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'try' block", File_Position(m_line, m_col), *m_filename); + } + + bool has_matches = true; + while (has_matches) { + while (Eol()) {} + has_matches = false; + if (Keyword("catch", false)) { + size_t catch_stack_top = m_match_stack.size(); + if (Char('(')) { + if (!(Id(true) && Char(')'))) { + throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename); + } + if (Char(':')) { + if (!Operator()) { + throw exception::eval_error("Missing guard expression for catch", File_Position(m_line, m_col), *m_filename); + } + } + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'catch' block", File_Position(m_line, m_col), *m_filename); + } + build_match(AST_NodePtr(new eval::Catch_AST_Node()), catch_stack_top); + has_matches = true; + } + } + while (Eol()) {} + if (Keyword("finally", false)) { + size_t finally_stack_top = m_match_stack.size(); + while (Eol()) {} if (!Block()) { - throw Eval_Error("Incomplete 'else' block", File_Position(m_line, m_col), *m_filename); + throw exception::eval_error("Incomplete 'finally' block", File_Position(m_line, m_col), *m_filename); } - has_matches = true; - } - } - } - - build_match(AST_NodePtr(new eval::If_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a while block from input - */ - bool While() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("while")) { - retval = true; - - if (!Char('(')) { - throw Eval_Error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(Operator() && Char(')'))) { - throw Eval_Error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw Eval_Error("Incomplete 'while' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::While_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads the C-style for conditions from input - */ - bool For_Guards() { - Equation(); - - if (Char(';') && Operator() && Char(';') && Equation()) { - return true; - } - else { - throw Eval_Error("Incomplete conditions in 'for' loop", File_Position(m_line, m_col), *m_filename); - } - } - - /** - * Reads a for block from input - */ - bool For() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("for")) { - retval = true; - - if (!Char('(')) { - throw Eval_Error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); - } - - if (!(For_Guards() && Char(')'))) { - throw Eval_Error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); - } - - while (Eol()) {} - - if (!Block()) { - throw Eval_Error("Incomplete 'for' block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::For_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a curly-brace C-style block from input - */ - bool Block() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Char('{')) { - retval = true; - - Statements(); - if (!Char('}')) { - throw Eval_Error("Incomplete block", File_Position(m_line, m_col), *m_filename); - } - - build_match(AST_NodePtr(new eval::Block_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a return statement from input - */ - bool Return() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("return")) { - retval = true; - - Operator(); - build_match(AST_NodePtr(new eval::Return_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads a break statement from input - */ - bool Break() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("break")) { - retval = true; - - build_match(AST_NodePtr(new eval::Break_AST_Node()), prev_stack_top); - } - - return retval; - } - - /** - * Reads an identifier, then proceeds to check if it's a function or array call - */ - bool Id_Fun_Array() { - bool retval = false; - std::string::const_iterator prev_pos = m_input_pos; - - size_t prev_stack_top = m_match_stack.size(); - if (Id(true)) { - retval = true; - bool has_more = true; - - while (has_more) { - has_more = false; - - if (Char('(')) { - has_more = true; - - Arg_List(); - if (!Char(')')) { - throw Eval_Error("Incomplete function call", File_Position(m_line, m_col), *m_filename); + build_match(AST_NodePtr(new eval::Finally_AST_Node()), finally_stack_top); } - build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::Try_AST_Node()), prev_stack_top); } - else if (Char('[')) { - has_more = true; - if (!(Operator() && Char(']'))) { - throw Eval_Error("Incomplete array access", File_Position(m_line, m_col), *m_filename); + return retval; + } + + /** + * Reads an if/elseif/else block from input + */ + bool If() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("if")) { + retval = true; + + if (!Char('(')) { + throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); } - build_match(AST_NodePtr(new eval::Array_Call_AST_Node()), prev_stack_top); + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'if' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'if' block", File_Position(m_line, m_col), *m_filename); + } + + bool has_matches = true; + while (has_matches) { + while (Eol()) {} + has_matches = false; + if (Keyword("else", true)) { + if (Keyword("if")) { + m_match_stack.back()->text = "else if"; + if (!Char('(')) { + throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + } + + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'else if' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'else if' block", File_Position(m_line, m_col), *m_filename); + } + has_matches = true; + } + else { + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'else' block", File_Position(m_line, m_col), *m_filename); + } + has_matches = true; + } + } + } + + build_match(AST_NodePtr(new eval::If_AST_Node()), prev_stack_top); } - } - } - return retval; - } - - /** - * Reads a variable declaration from input - */ - bool Var_Decl() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Keyword("var")) { - retval = true; - - if (!Id(true)) { - throw Eval_Error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename); + return retval; } - build_match(AST_NodePtr(new eval::Var_Decl_AST_Node()), prev_stack_top); - } - else if (Keyword("attr")) { - retval = true; + /** + * Reads a while block from input + */ + bool While() { + bool retval = false; - if (!Id(true)) { - throw Eval_Error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); - } - if (!Symbol("::", false)) { - throw Eval_Error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); - } - if (!Id(true)) { - throw Eval_Error("Missing attribute name in definition", File_Position(m_line, m_col), *m_filename); - } + size_t prev_stack_top = m_match_stack.size(); + if (Keyword("while")) { + retval = true; - build_match(AST_NodePtr(new eval::Attr_Decl_AST_Node()), prev_stack_top); - } + if (!Char('(')) { + throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); + } - return retval; - } + if (!(Operator() && Char(')'))) { + throw exception::eval_error("Incomplete 'while' expression", File_Position(m_line, m_col), *m_filename); + } - /** - * Reads an expression surrounded by parentheses from input - */ - bool Paren_Expression() { - bool retval = false; + while (Eol()) {} - if (Char('(')) { - retval = true; - if (!Operator()) { - throw Eval_Error("Incomplete expression", File_Position(m_line, m_col), *m_filename); - } - if (!Char(')')) { - throw Eval_Error("Missing closing parenthesis", File_Position(m_line, m_col), *m_filename); - } - } - return retval; - } + if (!Block()) { + throw exception::eval_error("Incomplete 'while' block", File_Position(m_line, m_col), *m_filename); + } - /** - * Reads, and identifies, a short-form container initialization from input - */ - bool Inline_Container() { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (Char('[')) { - retval = true; - Container_Arg_List(); - if (!Char(']')) { - throw Eval_Error("Missing closing square bracket", File_Position(m_line, m_col), *m_filename); - } - if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { - if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { - build_match(AST_NodePtr(new eval::Inline_Range_AST_Node()), prev_stack_top); + build_match(AST_NodePtr(new eval::While_AST_Node()), prev_stack_top); } - else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { - build_match(AST_NodePtr(new eval::Inline_Map_AST_Node()), prev_stack_top); + + return retval; + } + + /** + * Reads the C-style for conditions from input + */ + bool For_Guards() { + Equation(); + + if (Char(';') && Operator() && Char(';') && Equation()) { + return true; } else { - build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); + throw exception::eval_error("Incomplete conditions in 'for' loop", File_Position(m_line, m_col), *m_filename); } } - else { - build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); - } - } - return retval; - } + /** + * Reads a for block from input + */ + bool For() { + bool retval = false; - /** - * Reads a unary prefixed expression from input - */ - bool Prefix() { - bool retval = false; + size_t prev_stack_top = m_match_stack.size(); - size_t prev_stack_top = m_match_stack.size(); + if (Keyword("for")) { + retval = true; - if (Symbol("++", true)) { - retval = true; + if (!Char('(')) { + throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); + } - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete '++' expression", File_Position(m_line, m_col), *m_filename); + if (!(For_Guards() && Char(')'))) { + throw exception::eval_error("Incomplete 'for' expression", File_Position(m_line, m_col), *m_filename); + } + + while (Eol()) {} + + if (!Block()) { + throw exception::eval_error("Incomplete 'for' block", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::For_AST_Node()), prev_stack_top); + } + + return retval; } - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Symbol("--", true)) { - retval = true; + /** + * Reads a curly-brace C-style block from input + */ + bool Block() { + bool retval = false; - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete '--' expression", File_Position(m_line, m_col), *m_filename); + size_t prev_stack_top = m_match_stack.size(); + + if (Char('{')) { + retval = true; + + Statements(); + if (!Char('}')) { + throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Block_AST_Node()), prev_stack_top); + } + + return retval; } - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('-', true)) { - retval = true; + /** + * Reads a return statement from input + */ + bool Return() { + bool retval = false; - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete unary '-' expression", File_Position(m_line, m_col), *m_filename); + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("return")) { + retval = true; + + Operator(); + build_match(AST_NodePtr(new eval::Return_AST_Node()), prev_stack_top); + } + + return retval; } - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('+', true)) { - retval = true; + /** + * Reads a break statement from input + */ + bool Break() { + bool retval = false; - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete unary '+' expression", File_Position(m_line, m_col), *m_filename); + size_t prev_stack_top = m_match_stack.size(); + + if (Keyword("break")) { + retval = true; + + build_match(AST_NodePtr(new eval::Break_AST_Node()), prev_stack_top); + } + + return retval; } - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('!', true)) { - retval = true; + /** + * Reads an identifier, then proceeds to check if it's a function or array call + */ + bool Id_Fun_Array() { + bool retval = false; + std::string::const_iterator prev_pos = m_input_pos; - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete '!' expression", File_Position(m_line, m_col), *m_filename); - } + size_t prev_stack_top = m_match_stack.size(); + if (Id(true)) { + retval = true; + bool has_more = true; - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } - else if (Char('~', true)) { - retval = true; + while (has_more) { + has_more = false; - if (!Operator(m_operators.size()-1)) { - throw Eval_Error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); - } + if (Char('(')) { + has_more = true; - build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); - } + Arg_List(); + if (!Char(')')) { + throw exception::eval_error("Incomplete function call", File_Position(m_line, m_col), *m_filename); + } - return retval; - } - - /** - * Parses any of a group of 'value' style ast_node groups from input - */ - bool Value() { - if (Var_Decl() || Lambda() || Id_Fun_Array() || Num(true) || Prefix() || Quoted_String(true) || Single_Quoted_String(true) || - Paren_Expression() || Inline_Container()) { - return true; - } - else { - return false; - } - } - - bool Operator_Helper(size_t t_precedence) { - for (size_t i = 0; i < m_operator_matches[t_precedence].size(); ++i) { - if (Symbol(m_operator_matches[t_precedence][i].c_str(), true)) { - return true; - } - } - return false; - } - - bool Operator(size_t t_precedence = 0) { - bool retval = false; - - size_t prev_stack_top = m_match_stack.size(); - - if (t_precedence < m_operators.size()) { - if (Operator(t_precedence+1)) { - retval = true; - if (Operator_Helper(t_precedence)) { - do { - if (!Operator(t_precedence+1)) { - throw Eval_Error("Incomplete " - + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", - File_Position(m_line, m_col), *m_filename); + build_match(AST_NodePtr(new eval::Fun_Call_AST_Node()), prev_stack_top); } - } while (Operator_Helper(t_precedence)); + else if (Char('[')) { + has_more = true; - switch (m_operators[t_precedence]) { - case(AST_Node_Type::Comparison) : - build_match(AST_NodePtr(new eval::Comparison_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Dot_Access) : - build_match(AST_NodePtr(new eval::Dot_Access_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Additive) : - build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Multiplicative) : - build_match(AST_NodePtr(new eval::Multiplicative_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Shift) : - build_match(AST_NodePtr(new eval::Shift_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Equality) : - build_match(AST_NodePtr(new eval::Equality_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_And) : - build_match(AST_NodePtr(new eval::Bitwise_And_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_Xor) : - build_match(AST_NodePtr(new eval::Bitwise_Xor_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Bitwise_Or) : - build_match(AST_NodePtr(new eval::Bitwise_Or_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Logical_And) : - build_match(AST_NodePtr(new eval::Logical_And_AST_Node()), prev_stack_top); - break; - case(AST_Node_Type::Logical_Or) : - build_match(AST_NodePtr(new eval::Logical_Or_AST_Node()), prev_stack_top); - break; - default: - throw Eval_Error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); + if (!(Operator() && Char(']'))) { + throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Array_Call_AST_Node()), prev_stack_top); + } } } + + return retval; } - } - else { - return Value(); - } - return retval; - } + /** + * Reads a variable declaration from input + */ + bool Var_Decl() { + bool retval = false; - /** - * Reads a pair of values used to create a map initialization from input - */ - bool Map_Pair() { - bool retval = false; + size_t prev_stack_top = m_match_stack.size(); - size_t prev_stack_top = m_match_stack.size(); - std::string::const_iterator prev_pos = m_input_pos; - int prev_col = m_col; + if (Keyword("var")) { + retval = true; - if (Operator()) { - if (Symbol(":")) { - retval = true; - if (!Operator()) { - throw Eval_Error("Incomplete map pair", File_Position(m_line, m_col), *m_filename); + if (!Id(true)) { + throw exception::eval_error("Incomplete variable declaration", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Var_Decl_AST_Node()), prev_stack_top); + } + else if (Keyword("attr")) { + retval = true; + + if (!Id(true)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + if (!Symbol("::", false)) { + throw exception::eval_error("Incomplete attribute declaration", File_Position(m_line, m_col), *m_filename); + } + if (!Id(true)) { + throw exception::eval_error("Missing attribute name in definition", File_Position(m_line, m_col), *m_filename); + } + + + build_match(AST_NodePtr(new eval::Attr_Decl_AST_Node()), prev_stack_top); } - build_match(AST_NodePtr(new eval::Map_Pair_AST_Node()), prev_stack_top); + return retval; } - else { - m_input_pos = prev_pos; - m_col = prev_col; - while (prev_stack_top != m_match_stack.size()) { - m_match_stack.pop_back(); + + /** + * Reads an expression surrounded by parentheses from input + */ + bool Paren_Expression() { + bool retval = false; + + if (Char('(')) { + retval = true; + if (!Operator()) { + throw exception::eval_error("Incomplete expression", File_Position(m_line, m_col), *m_filename); + } + if (!Char(')')) { + throw exception::eval_error("Missing closing parenthesis", File_Position(m_line, m_col), *m_filename); + } } + return retval; } - } - return retval; - } + /** + * Reads, and identifies, a short-form container initialization from input + */ + bool Inline_Container() { + bool retval = false; - /** - * Reads a pair of values used to create a range initialization from input - */ - bool Value_Range() { - bool retval = false; + size_t prev_stack_top = m_match_stack.size(); - size_t prev_stack_top = m_match_stack.size(); - std::string::const_iterator prev_pos = m_input_pos; - int prev_col = m_col; - - if (Operator()) { - if (Symbol("..")) { - retval = true; - if (!Operator()) { - throw Eval_Error("Incomplete value range", File_Position(m_line, m_col), *m_filename); + if (Char('[')) { + retval = true; + Container_Arg_List(); + if (!Char(']')) { + throw exception::eval_error("Missing closing square bracket", File_Position(m_line, m_col), *m_filename); + } + if ((prev_stack_top != m_match_stack.size()) && (m_match_stack.back()->children.size() > 0)) { + if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) { + build_match(AST_NodePtr(new eval::Inline_Range_AST_Node()), prev_stack_top); + } + else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) { + build_match(AST_NodePtr(new eval::Inline_Map_AST_Node()), prev_stack_top); + } + else { + build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); + } + } + else { + build_match(AST_NodePtr(new eval::Inline_Array_AST_Node()), prev_stack_top); + } } - build_match(AST_NodePtr(new eval::Value_Range_AST_Node()), prev_stack_top); + return retval; } - else { - m_input_pos = prev_pos; - m_col = prev_col; - while (prev_stack_top != m_match_stack.size()) { - m_match_stack.pop_back(); + + /** + * Reads a unary prefixed expression from input + */ + bool Prefix() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Symbol("++", true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '++' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); } - } - } + else if (Symbol("--", true)) { + retval = true; - return retval; - } + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '--' expression", File_Position(m_line, m_col), *m_filename); + } - /** - * Parses a string of binary equation operators - */ - bool Equation() { - bool retval = false; + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); + } + else if (Char('-', true)) { + retval = true; - size_t prev_stack_top = m_match_stack.size(); + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete unary '-' expression", File_Position(m_line, m_col), *m_filename); + } - if (Operator()) { - retval = true; - if (Symbol("=", true, true) || Symbol(":=", true, true) || Symbol("+=", true, true) || - Symbol("-=", true, true) || Symbol("*=", true, true) || Symbol("/=", true, true) || - Symbol("%=", true, true) || Symbol("<<=", true, true) || Symbol(">>=", true, true) || - Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) { - if (!Equation()) { - throw Eval_Error("Incomplete equation", File_Position(m_line, m_col), *m_filename); + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); + } + else if (Char('+', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete unary '+' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); + } + else if (Char('!', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '!' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); + } + else if (Char('~', true)) { + retval = true; + + if (!Operator(m_operators.size()-1)) { + throw exception::eval_error("Incomplete '~' expression", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Prefix_AST_Node()), prev_stack_top); } - build_match(AST_NodePtr(new eval::Equation_AST_Node()), prev_stack_top); + return retval; } - } - return retval; - } + /** + * Parses any of a group of 'value' style ast_node groups from input + */ + bool Value() { + if (Var_Decl() || Lambda() || Id_Fun_Array() || Num(true) || Prefix() || Quoted_String(true) || Single_Quoted_String(true) || + Paren_Expression() || Inline_Container()) { + return true; + } + else { + return false; + } + } - /** - * Top level parser, starts parsing of all known parses - */ - bool Statements() { - bool retval = false; + bool Operator_Helper(size_t t_precedence) { + for (size_t i = 0; i < m_operator_matches[t_precedence].size(); ++i) { + if (Symbol(m_operator_matches[t_precedence][i].c_str(), true)) { + return true; + } + } + return false; + } - bool has_more = true; - bool saw_eol = true; + bool Operator(size_t t_precedence = 0) { + bool retval = false; - while (has_more) { - has_more = false; - int prev_line = m_line; - int prev_col = m_col; - if (Def()) { - if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Try()) { - if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (If()) { - if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (While()) { - if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (For()) { - if (!saw_eol) { - throw Eval_Error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = true; - } - else if (Return()) { - if (!saw_eol) { - throw Eval_Error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Break()) { - if (!saw_eol) { - throw Eval_Error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Equation()) { - if (!saw_eol) { - throw Eval_Error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); - } - has_more = true; - retval = true; - saw_eol = false; - } - else if (Eol()) { - has_more = true; - retval = true; - saw_eol = true; - } - else if (Block()) { - has_more = true; - retval = true; - saw_eol = true; - } - else { - has_more = false; - } - } + size_t prev_stack_top = m_match_stack.size(); - return retval; - } + if (t_precedence < m_operators.size()) { + if (Operator(t_precedence+1)) { + retval = true; + if (Operator_Helper(t_precedence)) { + do { + if (!Operator(t_precedence+1)) { + throw exception::eval_error("Incomplete " + + std::string(ast_node_type_to_string(m_operators[t_precedence])) + " expression", + File_Position(m_line, m_col), *m_filename); + } + } while (Operator_Helper(t_precedence)); - /** - * Parses the given input string, tagging parsed ast_nodes with the given m_filename. - */ - bool parse(const std::string &t_input, const std::string &t_fname) { - m_input_pos = t_input.begin(); - m_input_end = t_input.end(); - m_line = 1; - m_col = 1; - m_filename = boost::shared_ptr(new std::string(t_fname)); + switch (m_operators[t_precedence]) { + case(AST_Node_Type::Comparison) : + build_match(AST_NodePtr(new eval::Comparison_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Dot_Access) : + build_match(AST_NodePtr(new eval::Dot_Access_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Additive) : + build_match(AST_NodePtr(new eval::Additive_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Multiplicative) : + build_match(AST_NodePtr(new eval::Multiplicative_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Shift) : + build_match(AST_NodePtr(new eval::Shift_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Equality) : + build_match(AST_NodePtr(new eval::Equality_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_And) : + build_match(AST_NodePtr(new eval::Bitwise_And_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_Xor) : + build_match(AST_NodePtr(new eval::Bitwise_Xor_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Bitwise_Or) : + build_match(AST_NodePtr(new eval::Bitwise_Or_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Logical_And) : + build_match(AST_NodePtr(new eval::Logical_And_AST_Node()), prev_stack_top); + break; + case(AST_Node_Type::Logical_Or) : + build_match(AST_NodePtr(new eval::Logical_Or_AST_Node()), prev_stack_top); + break; + default: + throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_line, m_col), *m_filename); + } + } + } + } + else { + return Value(); + } - if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { - while ((m_input_pos != m_input_end) && (!Eol())) { - ++m_input_pos; + return retval; } - // TODO: respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) - } - if (Statements()) { - if (m_input_pos != m_input_end) { - throw Eval_Error("Unparsed input", File_Position(m_line, m_col), t_fname); + /** + * Reads a pair of values used to create a map initialization from input + */ + bool Map_Pair() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + std::string::const_iterator prev_pos = m_input_pos; + int prev_col = m_col; + + if (Operator()) { + if (Symbol(":")) { + retval = true; + if (!Operator()) { + throw exception::eval_error("Incomplete map pair", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Map_Pair_AST_Node()), prev_stack_top); + } + else { + m_input_pos = prev_pos; + m_col = prev_col; + while (prev_stack_top != m_match_stack.size()) { + m_match_stack.pop_back(); + } + } + } + + return retval; } - else { - build_match(AST_NodePtr(new eval::File_AST_Node()), 0); - return true; + + /** + * Reads a pair of values used to create a range initialization from input + */ + bool Value_Range() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + std::string::const_iterator prev_pos = m_input_pos; + int prev_col = m_col; + + if (Operator()) { + if (Symbol("..")) { + retval = true; + if (!Operator()) { + throw exception::eval_error("Incomplete value range", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Value_Range_AST_Node()), prev_stack_top); + } + else { + m_input_pos = prev_pos; + m_col = prev_col; + while (prev_stack_top != m_match_stack.size()) { + m_match_stack.pop_back(); + } + } + } + + return retval; } - } - else { - return false; - } - } - }; + + /** + * Parses a string of binary equation operators + */ + bool Equation() { + bool retval = false; + + size_t prev_stack_top = m_match_stack.size(); + + if (Operator()) { + retval = true; + if (Symbol("=", true, true) || Symbol(":=", true, true) || Symbol("+=", true, true) || + Symbol("-=", true, true) || Symbol("*=", true, true) || Symbol("/=", true, true) || + Symbol("%=", true, true) || Symbol("<<=", true, true) || Symbol(">>=", true, true) || + Symbol("&=", true, true) || Symbol("^=", true, true) || Symbol("|=", true, true)) { + if (!Equation()) { + throw exception::eval_error("Incomplete equation", File_Position(m_line, m_col), *m_filename); + } + + build_match(AST_NodePtr(new eval::Equation_AST_Node()), prev_stack_top); + } + } + + return retval; + } + + /** + * Top level parser, starts parsing of all known parses + */ + bool Statements() { + bool retval = false; + + bool has_more = true; + bool saw_eol = true; + + while (has_more) { + has_more = false; + int prev_line = m_line; + int prev_col = m_col; + if (Def()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Try()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (If()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (While()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (For()) { + if (!saw_eol) { + throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = true; + } + else if (Return()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Break()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Equation()) { + if (!saw_eol) { + throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename); + } + has_more = true; + retval = true; + saw_eol = false; + } + else if (Eol()) { + has_more = true; + retval = true; + saw_eol = true; + } + else if (Block()) { + has_more = true; + retval = true; + saw_eol = true; + } + else { + has_more = false; + } + } + + return retval; + } + + /** + * Parses the given input string, tagging parsed ast_nodes with the given m_filename. + */ + bool parse(const std::string &t_input, const std::string &t_fname) { + m_input_pos = t_input.begin(); + m_input_end = t_input.end(); + m_line = 1; + m_col = 1; + m_filename = boost::shared_ptr(new std::string(t_fname)); + + if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { + while ((m_input_pos != m_input_end) && (!Eol())) { + ++m_input_pos; + } + // TODO: respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) + } + + if (Statements()) { + if (m_input_pos != m_input_end) { + throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname); + } + else { + build_match(AST_NodePtr(new eval::File_AST_Node()), 0); + return true; + } + } + else { + return false; + } + } + }; + } } #endif /* CHAISCRIPT_PARSER_HPP_ */ diff --git a/src/main.cpp b/src/main.cpp index dbffe03..53ea64e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -107,14 +107,14 @@ void interactive(chaiscript::ChaiScript& chai) catch (...) {} //If we can't, do nothing } } - catch (chaiscript::Eval_Error &ee) { + catch (const chaiscript::exception::eval_error &ee) { std::cout << ee.what(); if (ee.call_stack.size() > 0) { std::cout << "during evaluation at (" << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; } std::cout << std::endl; } - catch (std::exception &e) { + catch (const std::exception &e) { std::cout << e.what(); std::cout << std::endl; } @@ -205,7 +205,7 @@ int main(int argc, char *argv[]) case eFile : val = chai.eval_file(arg); break; } } - catch (chaiscript::Eval_Error &ee) { + catch (const chaiscript::exception::eval_error &ee) { std::cout << ee.what(); if (ee.call_stack.size() > 0) { std::cout << "during evaluation at (" << *(ee.call_stack[0]->filename) << " " << ee.call_stack[0]->start.line << ", " << ee.call_stack[0]->start.column << ")"; diff --git a/src/reflection.cpp b/src/reflection.cpp index d5fc6cb..f858863 100644 --- a/src/reflection.cpp +++ b/src/reflection.cpp @@ -71,8 +71,8 @@ CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_reflect ); CHAISCRIPT_CLASS( m, - chaiscript::ChaiScript_Parser, - (chaiscript::ChaiScript_Parser ()), + chaiscript::parser::ChaiScript_Parser, + (chaiscript::parser::ChaiScript_Parser ()), ((parse)) ((ast)) );