From 8a0ef143c943cab6ae5b63de52d1e39dcc3aeca2 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Sun, 17 Apr 2011 09:29:34 -0600 Subject: [PATCH] C++ API documentation is complete. ChaiScript keyword and language documentation about 75% complete (mostly ported from website.) --- include/chaiscript/chaiscript.hpp | 141 ++++++++++ include/chaiscript/dispatchkit/bootstrap.hpp | 2 +- include/chaiscript/dispatchkit/boxed_cast.hpp | 49 +++- .../chaiscript/dispatchkit/boxed_value.hpp | 103 ++++++-- .../dispatchkit/dynamic_cast_conversion.hpp | 12 + .../dispatchkit/proxy_constructors.hpp | 11 + .../dispatchkit/proxy_functions.hpp | 15 +- .../dispatchkit/register_function.hpp | 61 +++++ include/chaiscript/dispatchkit/type_info.hpp | 19 +- .../chaiscript/language/chaiscript_engine.hpp | 200 ++++++++++----- .../language/chaiscript_prelude_docs.hpp | 242 ++++++++++++++++++ 11 files changed, 751 insertions(+), 104 deletions(-) create mode 100644 include/chaiscript/language/chaiscript_prelude_docs.hpp diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index 5c5ff5a..91686db 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -25,6 +25,147 @@ /// \sa http://www.chaiscript.com /// \sa http://www.github.com/ChaiScript/ChaiScript +/// \page LangObjectSystemRef ChaiScript Language Object Model Reference +/// +/// +/// ChaiScript supports has an object system built in, for types defined within the ChaiScript system. +/// +/// \code +/// attr Rectangle::height +/// attr Rectangle::width +/// def Rectangle::Rectangle() { this.height = 10; this.width = 20 } +/// def Rectangle::area() { this.height * this.width } +/// +/// var rect = Rectangle() +/// rect.height = 30 +/// print(rect.area()) +/// \endcode +/// +/// \sa \ref keywordattr +/// \sa \ref keyworddef + + +/// \page LangKeywordRef ChaiScript Language Keyword Reference +/// +/// +///
+/// \section keywordattr attr +/// Defines a ChaiScript object attribute +/// +/// \code +/// Attribute Definition ::= "attr" class_name "::" attribute_name +/// \endcode +/// +/// \sa \ref LangObjectSystemRef +/// +///
+/// \section keywordbreak break +/// Stops execution of a looping block. +/// +/// \code +/// Break Statement ::= "break" +/// \endcode +/// +/// \sa \ref keywordfor +/// \sa \ref keywordwhile +/// +/// +///
+/// \section keyworddef def +/// Begins a function or method definition +/// +/// \code +/// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [arg ("," arg)*] ")" [":" guard] block +/// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [arg ("," arg)*] ")" [":" guard] block +/// \endcode +/// +/// annotation: meta-annotation on function, currently used as documentation. Optional. +/// identifier: name of function. Required. +/// args: comma-delimited list of parameter names. Optional. +/// guards: guarding statement that act as a prerequisite for the function. Optional. +/// { }: scoped block as function body. Required. +/// +/// Functions return values in one of two ways: +/// +/// By using an explicit return call, optionally passing the value to be returned. +/// By implicitly returning the value of the last expression (if it is not a while or for loop). +/// +/// Method definitions for known types extend those types with new methods. This includes C++ and ChaiScript defined types. +/// Method definitions for unknown types implicitly define the named type. +/// +/// \sa \ref LangObjectSystemRef +/// +/// +///
+/// \section keywordelse else +/// \sa \ref keywordif +/// +/// +///
+/// \section keywordfor for +/// \code +/// For Block ::= "for" "(" [initial] ";" stop_condition ";" loop_expression ")" block +/// \endcode +/// This loop can be broken using the \ref keywordbreak command. +/// +/// +///
+/// \section keywordfun fun +/// Begins an anonymous function declaration (sometimes called a lambda). +/// +/// \code +/// Lambda ::= "fun" "(" [variable] ("," variable)* ")" block +/// \endcode +/// +/// \b Examples: +/// +/// \code +/// // Generate an anonymous function object that adds 2 to its parameter +/// var f = fun(x) { x + 2; } +/// \endcode +/// +/// \sa \ref keyworddef for more details on ChaiScript functions +/// +/// +///
+/// \section keywordif if +/// Begins a conditional block of code that only executes if the condition evaluates as true. +/// \code +/// If Block ::= "if" "(" condition ")" block +/// Else If Block ::= "else if" "(" condition ")" block +/// Else Block ::= "else" block +/// \endcode +/// \b Example: +/// \code +/// if (true) { +/// // do something +/// } else if (false) { +/// // do something else +/// } else { +/// // otherwise do this +/// } +/// \endcode +/// +/// +///
+/// \section keywordtry try +/// \code +/// Try Block ::= "try" block +/// ("catch" ["(" variable ")"] [":" guards] block)+ +/// ["finally" block] +/// \endcode +/// +/// +///
+/// \section keywordwhile while +/// +/// Begins a conditional block of code that loops 0 or more times, as long as the condition is true +/// +/// \code +/// While Block ::= "while" "(" condition ")" block +/// \endcode +/// This loop can be broken using the \ref keywordbreak command. + /// \namespace chaiscript /// \brief Namespace chaiscript contains every API call that the average user will be concerned with. diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 7bd30d0..757f989 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -311,7 +311,7 @@ namespace chaiscript /// \brief Adds a constructor for a POD type /// \tparam T The type to add the constructor for - /// \param[in] T The name of the type + /// \param[in] type The name of the type /// \param[in,out] m The Module to add the constructor to template ModulePtr construct_pod(const std::string &type, ModulePtr m = ModulePtr(new Module())) diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp index 242771b..e082ce3 100644 --- a/include/chaiscript/dispatchkit/boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -24,12 +24,49 @@ namespace chaiscript { - - /** - * boxed_cast function for casting a Boxed_Value into a given type - * example: - * int &i = boxed_cast(boxedvalue); - */ + + /// \brief Function for extracting a value stored in a Boxed_Value object + /// \tparam Type The type to extract from the Boxed_Value + /// \param[in] bv The Boxed_Value to extract a typed value from + /// \returns Type equivalent to the requested type + /// \throws exception::bad_boxed_cast If the requested conversion is not possible + /// + /// boxed_cast will attempt to make conversions between value, &, *, boost::shared_ptr, boost::reference_wrapper, + /// and boost::function (const and non-const) where possible. boxed_cast is used internally during function + /// dispatch. This means that all of these conversions will be attempted automatically for you during + /// ChaiScript function calls. + /// + /// \li non-const values can be extracted as const or non-const + /// \li const values can be extracted only as const + /// \li Boxed_Value constructed from pointer or boost::reference_wrapper can be extracted as reference, + /// pointer or value types + /// \li Boxed_Value constructed from boost::shared_ptr or value types can be extracted as reference, + /// pointer, value, or boost::shared_ptr types + /// + /// Conversions to boost::function objects are attempted as well + /// + /// Example: + /// \code + /// // All of the following should succeed + /// chaiscript::Boxed_Value bv(1); + /// boost::shared_ptr spi = chaiscript::boxed_cast >(bv); + /// int i = chaiscript::boxed_cast(bv); + /// int *ip = chaiscript::boxed_cast(bv); + /// int &ir = chaiscript::boxed_cast(bv); + /// boost::shared_ptr cspi = chaiscript::boxed_cast >(bv); + /// const int ci = chaiscript::boxed_cast(bv); + /// const int *cip = chaiscript::boxed_cast(bv); + /// const int &cir = chaiscript::boxed_cast(bv); + /// \endcode + /// + /// boost::function conversion example + /// \code + /// chaiscript::ChaiScript chai; + /// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in + /// boost::function f = chaiscript::boxed_cast >(bv); + /// int i = f(2,3); + /// assert(i == 5); + /// \endcode template typename detail::Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv) { diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index dc2aff8..76070f1 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -270,50 +270,97 @@ namespace chaiscript boost::shared_ptr m_data; }; - /// Clean wrapper for providing the user with a Boxed_Value - /// Suggested use: chai.add(var(myvariable), "myvariable"); + /// \brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, boost::shared_ptr, or boost::reference_type + /// a copy is not made. /// \param t The value to box + /// + /// Example: + /// \code + /// int i; + /// chaiscript::ChaiScript chai; + /// chai.add(chaiscript::var(i), "i"); + /// chai.add(chaiscript::var(&i), "ip"); + /// \endcode template Boxed_Value var(T t) { return Boxed_Value(t); } - /// Wrapper for providing the user with a Boxed_Value that is const inside - /// of the ChaiScript engine. - /// Suggested use: chai.add(const_var(myvariable), "myvariable"); - /// \param t The value to box - template - Boxed_Value const_var(T *t) - { - return Boxed_Value( const_cast::type *>(t) ); - } + namespace detail { + /// \brief Takes a value, copies it and returns a Boxed_Value object that is immutable + /// \param[in] t Value to copy and make const + /// \returns Immutable Boxed_Value + /// \sa Boxed_Value::is_const + template + Boxed_Value const_var_impl(const T &t) + { + return Boxed_Value(boost::shared_ptr::type >(new T(t))); + } - /// boost::shared_ptr overload for const_var - template - Boxed_Value const_var(const boost::shared_ptr &t) - { - return Boxed_Value( boost::const_pointer_cast::type>(t) ); - } + /// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value. + /// Does not copy the pointed to value. + /// \param[in] t Pointer to make immutable + /// \returns Immutable Boxed_Value + /// \sa Boxed_Value::is_const + template + Boxed_Value const_var_impl(T *t) + { + return Boxed_Value( const_cast::type *>(t) ); + } - /// boost::reference_wrapper overload for const_var - template - Boxed_Value const_var(const boost::reference_wrapper &t) - { - return Boxed_Value( boost::cref(t.get()) ); - } + /// \brief Takes a boost::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value. + /// Does not copy the pointed to value. + /// \param[in] t Pointer to make immutable + /// \returns Immutable Boxed_Value + /// \sa Boxed_Value::is_const + template + Boxed_Value const_var_impl(const boost::shared_ptr &t) + { + return Boxed_Value( boost::const_pointer_cast::type>(t) ); + } - /// Generic overload for const_var + /// \brief Takes a boost::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value. + /// Does not copy the referenced value. + /// \param[in] t Reference object to make immutable + /// \returns Immutable Boxed_Value + /// \sa Boxed_Value::is_const + template + Boxed_Value const_var_impl(const boost::reference_wrapper &t) + { + return Boxed_Value( boost::cref(t.get()) ); + } + } + + /// \brief Takes an object and returns an immutable Boxed_Value. If the object is a boost::reference or pointer type + /// the value is not copied. If it is an object type, it is copied. + /// \param[in] t Object to make immutable + /// \returns Immutable Boxed_Value + /// \sa chaiscript::Boxed_Value::is_const + /// \sa chaiscript::var + /// + /// Example: + /// \code + /// enum Colors + /// { + /// Blue, + /// Green, + /// Red + /// }; + /// chaiscript::ChaiScript chai + /// chai.add(chaiscript::const_var(Blue), "Blue"); // add immutable constant + /// chai.add(chaiscript::const_var(Red), "Red"); + /// chai.add(chaiscript::const_var(Green), "Green"); + /// \endcode template Boxed_Value const_var(const T &t) { - return Boxed_Value(boost::shared_ptr::type >(new T(t))); + return detail::const_var_impl(t); } - /** - * Return true if the two Boxed_Values share the same internal type - */ + + /// \returns true if the two Boxed_Values share the same internal type static bool type_match(Boxed_Value l, Boxed_Value r) { return l.get_type_info() == r.get_type_info(); diff --git a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp index 1ee3c99..dd14ff8 100644 --- a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp +++ b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp @@ -230,6 +230,18 @@ namespace chaiscript /// (through a tertiary dll that is shared between the modules, static linking the new type /// into both loadable modules would not be portable), you need to register the base type /// relationship in all modules that use the newly added type in a polymorphic way. + /// + /// Example: + /// \code + /// class Base + /// {}; + /// class Derived : public Base + /// {}; + /// + /// chaiscript::ChaiScript chai; + /// chai.add(chaiscript::base_class()); + /// \endcode + /// /// \todo Move share static type registration code into a mechanism that allows it to be properly /// shared by all modules template diff --git a/include/chaiscript/dispatchkit/proxy_constructors.hpp b/include/chaiscript/dispatchkit/proxy_constructors.hpp index 73e0afe..fcd019b 100644 --- a/include/chaiscript/dispatchkit/proxy_constructors.hpp +++ b/include/chaiscript/dispatchkit/proxy_constructors.hpp @@ -22,6 +22,17 @@ namespace chaiscript { + /// \brief Generates a constructor function for use with ChaiScript + /// + /// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...) + /// + /// Example: + /// \code + /// chaiscript::ChaiScript chai; + /// // Create a new function that creates a MyClass object using the (int, float) constructor + /// // and call that function "MyClass" so that it appears as a normal constructor to the user. + /// chai.add(constructor(), "MyClass"); + /// \endcode template Proxy_Function constructor() { diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index a29a06c..b03e89f 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -184,9 +184,7 @@ namespace chaiscript namespace exception { - /** - * Exception thrown if a function's guard fails to execute - */ + /// \brief Exception thrown if a function's guard fails class guard_error : public std::runtime_error { public: @@ -581,12 +579,11 @@ namespace chaiscript namespace exception { - /** - * Exception thrown in the case that a multi method dispatch fails - * because no matching function was found - * at runtime due to either an arity_error, a guard_error or a bad_boxed_cast - * exception - */ + /// \brief Exception thrown in the case that a method dispatch fails + /// because no matching function was found + /// + /// May be thrown due to an arity_error, a guard_error or a bad_boxed_cast + /// exception class dispatch_error : public std::runtime_error { public: diff --git a/include/chaiscript/dispatchkit/register_function.hpp b/include/chaiscript/dispatchkit/register_function.hpp index 8db8113..766187f 100644 --- a/include/chaiscript/dispatchkit/register_function.hpp +++ b/include/chaiscript/dispatchkit/register_function.hpp @@ -65,24 +65,85 @@ namespace chaiscript } } + /// \brief Creates a new Proxy_Function object from a boost::function object + /// \param[in] f boost::function to expose to ChaiScript + /// + /// \b Example: + /// \code + /// boost::function f = get_some_function(); + /// chaiscript::ChaiScript chai; + /// chai.add(fun(f), "some_function"); + /// \endcode template Proxy_Function fun(const boost::function &f) { return Proxy_Function(new dispatch::Proxy_Function_Impl(f)); } + /// \brief Creates a new Proxy_Function object from a free function, member function or data member + /// \param[in] t Function / member to expose + /// + /// \b Example: + /// \code + /// int myfunction(const std::string &); + /// class MyClass + /// { + /// public: + /// void memberfunction(); + /// int memberdata; + /// }; + /// + /// chaiscript::ChaiScript chai; + /// chai.add(fun(&myfunction), "myfunction"); + /// chai.add(fun(&MyClass::memberfunction), "memberfunction"); + /// chai.add(fun(&MyClass::memberdata), "memberdata"); + /// \endcode template Proxy_Function fun(T t) { return dispatch::detail::Fun_Helper::value, boost::function_types::is_member_function_pointer::value>::go(t); } + /// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it + /// \param[in] t Function / member to expose + /// \param[in] q Value to bind to first parameter + /// + /// \b Example: + /// \code + /// struct MyClass + /// { + /// void memberfunction(int); + /// }; + /// + /// MyClass obj; + /// chaiscript::ChaiScript chai; + /// // Add function taking only one argument, an int, and permanently bound to "obj" + /// chai.add(fun(&MyClass::memberfunction, boost::ref(obj)), "memberfunction"); + /// \endcode template Proxy_Function fun(T t, const Q &q) { return fun(detail::bind_first(t, q)); } + /// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it + /// \param[in] t Function / member to expose + /// \param[in] q Value to bind to first parameter + /// \param[in] r Value to bind to second parameter + /// + /// \b Example: + /// \code + /// struct MyClass + /// { + /// void memberfunction(int); + /// }; + /// + /// MyClass obj; + /// chaiscript::ChaiScript chai; + /// // Add function taking only no arguments, and permanently bound to "obj" and "1" + /// // memberfunction() will be equivalent to obj.memberfunction(1) + /// chai.add(fun(&MyClass::memberfunction, boost::ref(obj), 1), "memberfunction"); + /// \endcode template Proxy_Function fun(T t, const Q &q, const R &r) { diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index da9a601..605fbb6 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -212,13 +212,30 @@ namespace chaiscript }; } + /// \brief Creates a Type_Info object representing the type passed in + /// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter + /// \return Type_Info for T + /// + /// \b Example: + /// \code + /// int i; + /// chaiscript::Type_Info ti = chaiscript::user_type(i); + /// \endcode template - Type_Info user_type(T) + Type_Info user_type(const T &/*t*/) { return detail::Get_Type_Info::get(); } + /// \brief Creates a Type_Info object representing the templated type + /// \tparam T Type of object to get a Type_Info for + /// \return Type_Info for T + /// + /// \b Example: + /// \code + /// chaiscript::Type_Info ti = chaiscript::user_type(); + /// \endcode template Type_Info user_type() { diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 16364bf..4efcec6 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -30,6 +30,7 @@ namespace chaiscript { namespace exception { + /// \brief Thrown if an error occurs while attempting to load a binary module struct load_module_error : std::runtime_error { load_module_error(const std::string &t_reason) throw() @@ -356,7 +357,35 @@ namespace chaiscript do_eval(chaiscript_prelude, "standard prelude"); } + /** + * Helper function for loading a file + */ + std::string load_file(const std::string &t_filename) { + std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary ); + + if (!infile.is_open()) { + throw exception::file_not_found_error(t_filename); + } + + std::streampos size = infile.tellg(); + infile.seekg(0, std::ios::beg); + + assert(size >= 0); + + if (size == std::streampos(0)) + { + return std::string(); + } else { + std::vector v(static_cast(size)); + infile.read(&v[0], size); + return std::string(v.begin(), v.end()); + } + } + public: + /// \brief Constructor for ChaiScript + /// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module + /// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file ChaiScript(const std::vector &t_modulepaths = std::vector(), const std::vector &t_usepaths = std::vector()) : m_modulepaths(t_modulepaths), m_usepaths(t_usepaths) @@ -374,15 +403,20 @@ namespace chaiscript build_eval_system(); } - /** - * Adds a shared object, that can be used by all threads, to the system - */ + /// \brief Adds a constant object that is available in all contexts and to all threads + /// \param[in] t_bv Boxed_Value to add as a global + /// \param[in] t_name Name of the value to add + /// \throw exception::global_non_const If t_bv is not a constant object + /// \sa Boxed_Value::is_const ChaiScript &add_global_const(const Boxed_Value &t_bv, const std::string &t_name) { m_engine.add_global_const(t_bv, t_name); return *this; } + /// \brief Represents the current state of the ChaiScript system. State and be saved and restored + /// \sa ChaiScript::get_state + /// \sa ChaiScript::set_state struct State { std::set used_files; @@ -390,11 +424,15 @@ namespace chaiscript std::set active_loaded_modules; }; - /** - * Returns a state object that represents the current - * set of loaded files, the set of global variables and - * the set of initialized functions - */ + /// \brief Returns a state object that represents the current state of the system + /// \return Current state of the system + /// + /// \b Example: + /// + /// \code + /// chaiscript::ChaiScript chai; + /// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state + /// \endcode State get_state() { chaiscript::detail::threading::lock_guard l(m_use_mutex); @@ -407,9 +445,16 @@ namespace chaiscript return s; } - /** - * Restores the state from a saved State object. - */ + /// \brief Sets the state of the system + /// \param[in] t_state New state to set + /// + /// \b Example: + /// \code + /// chaiscript::ChaiScript chai; + /// chaiscript::ChaiScript::State s = chai.get_state(); // get initial state + /// chai.add(chaiscript::fun(&somefunction), "somefunction"); + /// chai.set_state(s); // restore initial state, which does not have the recently added "somefunction" + /// \endcode void set_state(const State &t_state) { chaiscript::detail::threading::lock_guard l(m_use_mutex); @@ -420,9 +465,19 @@ namespace chaiscript m_engine.set_state(t_state.engine_state); } - /** - * Adds an object to the system: type, function, object - */ + /// \brief Adds a type, function or object to ChaiScript + /// \param[in] t_t Item to add + /// \param[in] t_name Name of item to add + /// \returns Reference to current ChaiScript object + /// + /// \b Examples: + /// \code + /// chaiscript::ChaiScript chai; + /// chai.add(chaiscript::user_type(), "MyClass"); // Add explicit type info (not strictly necessary) + /// chai.add(chaiscript::fun(&MyClass::function), "function"); // Add a class method + /// MyClass obj; + /// chai.add(chaiscript::var(&obj), "obj"); // Add a pointer to a locally defined object + /// \endcode template ChaiScript &add(const T &t_t, const std::string &t_name) { @@ -430,18 +485,42 @@ namespace chaiscript return *this; } - /** - * Adds a module object to the system - */ + /// \brief Add a new conversion for upcasting to a base class + /// \sa chaiscript::base_class + /// \param[in] d Base class / parent class + /// + /// \b Example: + /// \code + /// chaiscript::ChaiScript chai; + /// chai.add(chaiscript::base_class()); + /// \endcode + ChaiScript &add(const Dynamic_Cast_Conversion &d) + { + m_engine.add(d); + return *this; + } + + /// \brief Adds all elements of a module to ChaiScript runtime + /// \param[in] t_p The module to add. + /// \sa chaiscript::Module ChaiScript &add(const ModulePtr &t_p) { t_p->apply(*this, this->get_eval_engine()); return *this; } - /** - * Load a dynamic library containing a chaiscript module - */ + /// \brief Load a binary module from a dynamic library. Works on platforms that support + /// dynamic libraries. + /// \param[in] t_module_name Name of the module to load + /// + /// The module is searched for in the registered module path folders (chaiscript::ChaiScript::ChaiScript) + /// and with standard prefixes and postfixes: ("lib"|"")\(".dll"|".so"|""). + /// + /// Once the file is located, the system looks for the symbol "create_chaiscript_module_\". + /// If no file can be found matching the search criteria and containing the appropriate entry point + /// (the symbol mentioned above), an exception is thrown. + /// + /// \throw exception::load_module_error In the event that no matching module can be found. void load_module(const std::string &t_module_name) { std::vector errors; @@ -490,9 +569,13 @@ namespace chaiscript throw exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring); } - /** - * Load a dynamic library and provide the file name to load it from - */ + /// \brief Load a binary module from a dynamic library. Works on platforms that support + /// dynamic libraries. + /// + /// \param[in] t_module_name Module name to load + /// \param[in] t_filename Ignore normal filename search process and use specific filename + /// + /// \sa ChaiScript::load_module(const std::string &t_module_name) void load_module(const std::string &t_module_name, const std::string &t_filename) { chaiscript::detail::threading::lock_guard l(m_use_mutex); @@ -510,62 +593,61 @@ namespace chaiscript } - /** - * Evaluate a string via eval method - */ + /// \brief Evaluates a string. Equivalent to ChaiScript::eval. + /// + /// \param[in] t_script Script to execute + /// + /// \return result of the script execution + /// + /// \throw exception::eval_error In the case that evaluation fails. Boxed_Value operator()(const std::string &t_script) { return do_eval(t_script); } - - /** - * Helper function for loading a file - */ - std::string load_file(const std::string &t_filename) { - std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary ); - - if (!infile.is_open()) { - throw exception::file_not_found_error(t_filename); - } - - std::streampos size = infile.tellg(); - infile.seekg(0, std::ios::beg); - - assert(size >= 0); - - if (size == std::streampos(0)) - { - return std::string(); - } else { - std::vector v(static_cast(size)); - infile.read(&v[0], size); - return std::string(v.begin(), v.end()); - } - } - - + /// \brief Evaluates a string and returns a typesafe result. + /// + /// \tparam T Type to extract from the result value of the script execution + /// \param[in] t_input Script to execute + /// + /// \return result of the script execution + /// + /// \throw exception::eval_error In the case that evaluation fails. + /// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted + /// to the requested type. template T eval(const std::string &t_input) { return boxed_cast(do_eval(t_input)); } + /// \brief Evaluates a string. + /// + /// \param[in] t_input Script to execute + /// + /// \return result of the script execution + /// + /// \throw exception::eval_error In the case that evaluation fails. Boxed_Value eval(const std::string &t_input) { return do_eval(t_input); } - /** - * Loads the file specified by filename, evaluates it, and returns the result - */ + /// \brief Loads the file specified by filename, evaluates it, and returns the result. + /// \param[in] t_filename File to load and parse. + /// \return result of the script execution + /// \throw exception::eval_error In the case that evaluation fails. Boxed_Value eval_file(const std::string &t_filename) { return do_eval(load_file(t_filename), t_filename); } - /** - * Loads the file specified by filename, evaluates it, and returns the as the specified type - */ + /// \brief Loads the file specified by filename, evaluates it, and returns the typesafe result. + /// \tparam T Type to extract from the result value of the script execution + /// \param[in] t_filename File to load and parse. + /// \return result of the script execution + /// \throw exception::eval_error In the case that evaluation fails. + /// \throw exception::bad_boxed_cast In the case that evaluation succeeds but the result value cannot be converted + /// to the requested type. template T eval_file(const std::string &t_filename) { return boxed_cast(do_eval(load_file(t_filename), t_filename)); diff --git a/include/chaiscript/language/chaiscript_prelude_docs.hpp b/include/chaiscript/language/chaiscript_prelude_docs.hpp new file mode 100644 index 0000000..df1ca18 --- /dev/null +++ b/include/chaiscript/language/chaiscript_prelude_docs.hpp @@ -0,0 +1,242 @@ + +/// \brief Items in this namespace exist in the ChaiScript language runtime. They are not part of the C++ API +namespace ChaiScript_Language +{ + +/// \page LangStandardLibraryRef ChaiScript Language Standard Libary Reference +/// +/// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly +/// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available +/// to all standard ChaiScript applications, and provides a simple foundation for using numbers, strings, and ranges +/// (the general category of containers and their iteration). +/// +/// \section LibraryStrings Strings +/// + + +/// \brief Converts o into a string. +/// +/// \code +/// eval> to_string(3).is_type("string")
+/// true
+/// \endcode +string to_string(Object o); + + +/// \brief Prints o to the terminal, without a trailing carriage return. Applies conversions to string automatically. +/// \code +/// eval> puts("hi, "); puts("there") +/// hi, thereeval> +/// \endcode +/// \sa to_string +/// \sa print +void puts(Object o); + + +/// \brief Prints o to the terminal, with a trailing carriage return. Applies conversions to string automatically +/// \code +/// eval> print("hello") +/// hello +/// eval> +/// \endcode +/// \sa to_string +/// \sa puts +void print(Object o); + +/// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript. +/// +/// Because the ChaiScript string object is an std::string, it is directly convertable to and from std::string +/// using the chaiscript::boxed_cast and chaiscript::var functions. +/// +/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct passthroughs to the +/// std::string of the same name. +/// +/// \note Object and function notations are equivalent in ChaiScript. This means that +/// \c "bob".find("b") and \c find("bob", "b") are exactly the same. Most examples below follow the +/// second formation of the function calls. +/// \sa \ref keyworddef for extending existing C++ classes in ChaiScript +class string +{ + public: + /// \brief Finds the first instance of substr. + /// \code + /// eval> find("abab", "ab") + /// 0 + /// \endcode + int find(string s) const; + + + /// \brief Finds the last instance of substr. + /// \code + /// eval> rfind("abab", "ab") + /// 2 + /// \endcode + int rfind(string s) const; + + /// Finds the first of characters in list in the string. + /// + /// \code + /// eval> find_first_of("abab", "bec") + /// 1 + /// \endcode + int find_first_of(string list) const; + + /// Finds the last of characters in list in the string. + /// + /// \code + /// eval> find_last_of("abab", "bec") + /// 3 + /// \endcode + int find_last_of(string list) const; + + /// Finds the first non-matching character to list in the str string. + /// + /// \code + /// eval> find_first_not_of("abcd", "fec") + /// 0 + /// \endcode + int find_first_not_of(string list) const; + + ///find_last_not_of(str, list): Finds the last non-matching character to list in the str string. + /// + /// \code + /// eval> find_last_not_of("abcd", "fec") + /// 3 + /// \endcode + int find_last_not_of(string list) const; + + /// Removes whitespace from the front of the string, returning a new string + /// + /// \note This function is implemented as a ChaiScript function using the def member function notation. + /// + /// \code + /// eval> ltrim(" bob") + /// bob + /// \endcode + /// + /// \sa \ref keyworddef + string lstrim() const; + + /// Removes whitespace from the back of the string, returning a new string + /// + /// \note This function is implemented as a ChaiScript function using the def member function notation. + /// + /// \code + /// eval> rtrim("bob ") + "|" + /// bob| + /// \endcode + /// + /// \sa \ref keyworddef + string rtrim() const; + + /// Removes whitespace from the front and back of the string, returning a new string + /// + /// \note This function is implemented as a ChaiScript function using the def member function notation. + /// + /// \code + /// eval> trim(" bob ") + "|" + /// bob| + /// \endcode + /// + /// Equivalent to rtrim(ltrim(" bob ")); + /// + /// \sa \ref keyworddef + string trim() const; +}; + +///Numbers +/// +///max(a, b): Returns the maximum value of a or b. +/// +///eval> max(4, 10) +///10 +///min(a, b): Returns the minimum value of a or b. +/// +///eval> min(4, 10) +///4 +///even(x): Returns true if x is even, otherwise returns false. +/// +///eval> even(4) +///true +///odd(x): Returns true if x is odd, otherwise returns false. +/// +///eval> odd(4) +///false +///Containers +/// +///for_each(container, f): Applies the function f over each element in the container. +/// +///eval> for_each([1, 2, 3], print) +///1 +///2 +///3 +///map(container, f): Applies f over each element in the container, joining all the results. +/// +///eval> map([1, 2, 3], odd) +///[true, false, true] +///foldl(container, f, initial): Starts with the initial value and applies the function f to it and the first element of the container. The result is then applied to the second element, and so on until the elements are exhausted. +/// +///eval> foldl([1, 2, 3, 4], `+`, 0) +///10 +///sum(container): Returns the sum total of the values in the container. +/// +///eval> sum([1, 2, 3, 4]) +///10 +///product(container): Returns the product of the value in the container. +/// +///eval> product([1, 2, 3, 4]) +///24 +///take(container, num): Takes num elements from the container, returning them. +/// +///eval> take([1, 2, 3, 4], 2) +///[1, 2] +///take_while(container, f): Takes elements from the container that match function f, stopping at the first non-match, returning them as a new Vector. +/// +///eval> take_while([1, 2, 3], odd) +///[1] +///drop(container, num): Drops num elements from the container, returning the remainder. +/// +///eval> drop([1, 2, 3, 4], 2) +///[3, 4] +///drop_while(container, f): Drops elements from the container that match f, stopping at the first non-match, returning the remainder. +/// +///eval> drop_while([1, 2, 3], odd) +///[2, 3] +///reduce(container, f): Similar to foldl, this takes the first two elements as its starting values for f. This assumes container has at least 2 elements. +/// +///eval> reduce([1, 2, 3, 4], `+`) +///10 +///filter(container, f): Takes elements from container that match function f, return them. +/// +///eval> filter([1, 2, 3, 4], odd) +///[1, 3] +///join(container, delim): Joins the elements of the container into a string, delimiting each with the delim string. +/// +///eval> join([1, 2, 3], "*") +///1*2*3 +///reverse(container): Returns the contents of the container in reversed order. +/// +///eval> reverse([1, 2, 3, 4, 5, 6, 7]) +///[7, 6, 5, 4, 3, 2, 1] +///generate_range(x, y): Generates a new Vector filled with values starting at x and ending with y. +/// +///eval> generate_range(1, 10) +///[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +///concat(x, y): Returns a new Vector with x and y concatenated. +/// +///eval> concat([1, 2, 3], [4, 5, 6]) +///[1, 2, 3, 4, 5, 6] +///collate(x, y): Returns a new Vector with x and y as its values. +/// +///eval> collate(1, 2) +///[1, 2] +///zip_with(f, x, y): Applies f to elements of x and y, returning a new Vector with the result of each application. +/// +///eval> zip_with(`+`, [1, 2, 3], [4, 5, 6]) +///[5, 7, 9] +///zip(x, y): Collates elements of x and y, returning a new Vector with the result. +/// +///eval> zip([1, 2, 3], [4, 5, 6]) +///[[1, 4], [2, 5], [3, 6]] +} +