diff --git a/CMakeLists.txt b/CMakeLists.txt index 6984963..1a88594 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,9 +16,9 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt") set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.txt") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") -set(CPACK_PACKAGE_VERSION_MAJOR 2) -set(CPACK_PACKAGE_VERSION_MINOR 3) -set(CPACK_PACKAGE_VERSION_PATCH 3) +set(CPACK_PACKAGE_VERSION_MAJOR 3) +set(CPACK_PACKAGE_VERSION_MINOR 0) +set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") set(CPACK_PACKAGE_VENDOR "ChaiScript.com") set(CPACK_PACKAGE_CONTACT "contact@chaiscript.com") diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index 91686db..ebbab3d 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -155,6 +155,7 @@ /// ["finally" block] /// \endcode /// +/// \sa ChaiScript_Language::throw /// ///
/// \section keywordwhile while diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 69e80c7..cf567a2 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -741,7 +741,7 @@ namespace chaiscript /** * return true if the Boxed_Value matches the registered type by name */ - bool is_type(Boxed_Value r, const std::string &user_typename) const + bool is_type(const Boxed_Value &r, const std::string &user_typename) const { try { if (get_type(user_typename).bare_equal(r.get_type_info())) diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index b03e89f..a86a62c 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -213,9 +213,9 @@ namespace chaiscript const std::string &t_description = "", const Proxy_Function &t_guard = Proxy_Function()) : Proxy_Function_Base(build_param_type_list(t_arity)), - m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard), m_parsenode(t_parsenode) - { - } + m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard), m_parsenode(t_parsenode) + { + } virtual bool operator==(const Proxy_Function_Base &rhs) const { diff --git a/include/chaiscript/language/chaiscript_prelude.hpp b/include/chaiscript/language/chaiscript_prelude.hpp index 1fd5c68..c65b73c 100644 --- a/include/chaiscript/language/chaiscript_prelude.hpp +++ b/include/chaiscript/language/chaiscript_prelude.hpp @@ -131,11 +131,11 @@ def product(container) { foldl(container, `*`, 1.0) } \n\ # Returns a new container with the elements of the first value concatenated with the elements of the second value\n\ def concat(x, y) : call_exists(clone, x) { \n\ var retval = x; \n\ - var len = y.size(); \n\ - var i = 0; \n\ - while (i < len) { \n\ - retval.push_back(y[i]); \n\ - ++i; \n\ + var inserter = back_inserter(retval); \n\ + var range = range(y); \n\ + while (!range.empty()) { \n\ + inserter(range.front()); \n\ + range.pop_front(); \n\ } \n\ retval; \n\ } \n\ diff --git a/include/chaiscript/language/chaiscript_prelude_docs.hpp b/include/chaiscript/language/chaiscript_prelude_docs.hpp index ba3609e..5f9de26 100644 --- a/include/chaiscript/language/chaiscript_prelude_docs.hpp +++ b/include/chaiscript/language/chaiscript_prelude_docs.hpp @@ -10,10 +10,117 @@ namespace ChaiScript_Language /// 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 Container cs and their iteration). +/// (the general category of Range cs and their iteration). /// +/// \brief Generic concept of a value in ChaiScript. +/// +/// The Object type exists merely as a concept. All objects in ChaiScript support this concept +/// and have the following methods available to them. All objects are stored internally as chaiscript::Boxed_Value types. +/// +/// \sa chaiscript::Boxed_Value +class Object +{ + public: + /// \brief Returns the Type_Info value for this Object + Type_Info get_type_info() const; + + /// \brief Returns true if the Object is of the named type + bool is_type(string) const; + + /// \brief Returns true if the Object is of the Type_Info passed in + bool is_type(Type_Info) const; + + /// \brief Returns true if the Object is immutable + bool is_var_const() const; + + /// \brief Returns true if the Object is a pointer and the pointer is null + bool is_var_null() const; + + /// \brief Returns true if the Object is stored as a pointer + bool is_var_pointer() const; + + /// \brief Returns true if the Object is stored as a reference + bool is_var_reference() const; + + /// \brief Returns true if the Object does not contain a value is is undefined. + bool is_var_undef() const; + + /// \brief Returns the registered name of the type of the object. + /// + /// \sa Type_Info::name(); + string type_name() const; +}; + +/// \brief Item returned from a Range object from a Map +class Map_Pair +{ + public: + /// \brief Returns the key of the Map entry + const string first(); + + /// \brief Returns the value Object of the Map entry + Object second(); +}; + + +/// \brief Maps strings to Objects +/// +/// ChaiScript has a built in shortcut for generating Map objects: +/// +/// Example: +/// \code +/// eval> var m = ["a":1, "b":2]; +/// [, ] +/// eval> m.count("a"); +/// 1 +/// eval> m.count("c"); +/// 0 +/// eval> m.size(); +/// 2 +/// \endcode +/// +/// Implemented as std::map +/// +/// \sa Map_Pair +/// \sa chaiscript::bootstrap::standard_library::map_type +class Map +{ + public: + /// \brief Returns an object that implements the Range concept for the Map_Pair's in this Map + Range range(); + + /// \brief Returns an object that implements the Const_Range concept for the Map_Pair's in this Map + Const_Range range() const; + + /// \brief Returns the number of elements in the Map + int size() const; + + /// \brief Returns the item at the given key, creating an undefined Object if the key does not yet exist in the map + Object operator[](string); + + /// \brief Clears the map of all items + void clear(); + + /// \brief Returns the number of items in the Map with the given key. Returns 0 or 1 since this is not an std::multimap. + int count(string) const; + + /// \brief Returns true if the map contains no items + bool empty() const; + +}; + + +/// \brief A concept implemented by string, Vector and Map. It is convertable to Range, default constructable and back_insertable +class Container +{ + public: + void push_back(Object); + Range range(); + Const_Range range() const; +}; + /// \brief Converts o into a string. /// @@ -56,6 +163,7 @@ void print(Object o); /// \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 +/// \sa chaiscript::bootstrap::standard_library::string_type class string { public: @@ -143,22 +251,304 @@ class string /// /// \sa \ref keyworddef string trim() const; + + /// \brief Returns the character at the given index in the string, const version + const char &operator[](int t_index) const; + + /// \brief Returns the character at the given index in the string + char &operator[](int t_index); + + /// \brief Returns underlying const char * for C api compatibility + const char *c_str() const; + + /// \brief Returns a pointer to the raw data in the string + const char *data() const; + + /// \brief Resets the string to empty + void clear(); + + /// \brief Returns true if the string is empty + bool empty() const; + + /// \brief Returns the size of the string in bytes. + /// + /// This function normally returns size_t in C++. In ChaiScript the return value is cast to int + /// for ease of use. + int size() const; + + /// \brief Returns an object that implements the Range concept for the characters of this string + Range range(); + + /// \brief Returns an object that implements the Const_Range concept for the characters of this string + Const_Range range() const; }; +/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides +/// easy iteration over the elements in a container. +/// +/// Implemented by the template chaiscript::bootstrap::standard_library::Bidir_Range +/// +/// \sa Const_Range +class Range +{ + public: + /// \brief Returns the last item of the range + Object back(); + + /// \brief Returns true if the front and back pointers have passed each other, if no items + /// are left in the Range + bool empty() const; + + /// \brief Returns the first item of the range + Object front(); + + /// \brief Moves the back pointer back one. + /// + /// \post back() returns the element at back() - 1; + void pop_back(); + + /// \brief Moves the front pointer forward one + /// + /// \post front() returne the element at front() + 1; + void pop_front(); + +}; + +/// \brief A concept in ChaiScript that is implemented by \ref string, Vector and Map. It provides +/// easy iteration over the elements in a container. Contained values are const. +/// +/// Implemented by the template chaiscript::bootstrap::standard_library::Const_Bidir_Range +/// +/// \sa Range +class Const_Range +{ + public: + /// \brief Returns the last item of the range + const Object back(); + + /// \brief Returns true if the front and back pointers have passed each other, if no items + /// are left in the Range + bool empty() const; + + /// \brief Returns the first item of the range + const Object front(); + + /// \brief Moves the back pointer back one. + /// + /// \post back() returns the element at back() - 1; + void pop_back(); + + /// \brief Moves the front pointer forward one + /// + /// \post front() returne the element at front() + 1; + void pop_front(); + +}; + +/// \brief A vector of Objects +/// +/// ChaiScript includes a shortcut for creating a Vector of Objects +/// +/// Example: +/// \code +/// eval> var v = [1,2,3,4] +/// [1, 2, 3, 4] +/// eval> v[0]; +/// 1 +/// eval> v.size(); +/// 4 +/// \endcode +/// +/// Implemented with std::vector +/// +/// \sa chaiscript::bootstrap::standard_library::vector_type +class Vector +{ + public: + /// \brief returns the Object at the given index. Throws an exception if the index does not exist + Object operator[](int t_index); + + /// \brief returns a const Object at the given index. Throws an exception if the index does not exist. + const Object operator[](int t_index) const; + + /// \brief returns the last item in the Vector + Object back(); + + /// \brief Clears the Vector of all items + void clear(); + + /// \brief Returns true if the Vector is contains 0 items + bool empty(); + + /// \brief Erases the element at the given index + void erase_at(int t_index); + + /// \brief Returns the first item in the Vector + Object front(); + + /// \brief Inserts a new item in the Vector at the given index. The item is not cloned on insert + /// + /// \sa insert_ref + void insert_ref_at(int, Object); + + /// \brief Inserts a new item in the Vector at the given index. The item is cloned on insert + /// + /// \sa insert_ref + void insert_at(int, Object); + + /// \brief Removes the last item from the Vector + void pop_back(); + + /// \brief Adds an item to the end of the Vector. The item is not cloned. + /// + /// \sa push_back + void push_back_ref(Object); + + /// \brief Adds an item to the end of the Vector. The item is cloned. + /// + /// \sa push_back_ref + void push_back(Object); + + /// \brief Returns a Range object for the entire vector + Range range(); + + /// \brief Returns a Const_Range object for the entire vector + Const_Range range() const; + + /// \brief Returns the number of elements in the Vector + int size() const; + +}; + +class Type_Info +{ + public: + /// \brief Compares this Type_Info object with another one and returns true if the two types are the same + /// after const, pointer, reference are removed. + bool bare_equal(Type_Info t_ti) const; + + /// \brief Returns the mangled C++ name for the type given by the compiler after const, pointer, reference is removed. + string cpp_bare_name() const; + + /// \brief Returns the mangled C++ name for the type given by the compiler. + string cpp_name() const; + + /// \brief Returns true if the type is const + bool is_type_const() const; + + /// \brief Returns true if the type is a pointer + bool is_type_pointer() const; + + /// \brief Returns true if the type is a reference + bool is_type_reference() const; + + /// \brief Returns true if the type is undefined + bool is_type_undef() const; + + /// \brief Returns true if the type is "void" + bool is_type_void() const; + + /// \brief Returns the ChaiScript registered name for the type if one exists. + string name() const; + +}; + + +/// \brief Represents a function object in ChaiScript +/// +/// A function object may be one function, such as: +/// \code +/// var f = fun(x) { return x; } +/// \endcode +/// +/// Or it may represent multiple functions +/// \code +/// var f2 = `-`; // represents the unary - as well as the set of binary - operators +/// \endcode +/// +/// Guarded function example +/// \code +/// def f3(x) : x > 2 { +/// return x; +/// } +/// \endcode +/// +/// Examples in the function definitions below will reference these examples class Function { public: -}; + /// \brief Returns the annotation description of the function + string get_annotation() const; -/// \brief Generic concept of a value in ChaiScript. -/// -/// The Object type exists merely as a concept. All objects in ChaiScript support this concept -/// and have the following methods available to them. All objects are stored internally as chaiscript::Boxed_Value types. -class Object -{ - public: + /// \brief Returns the arity of the function, -1 if the function takes a variable number of parameters + /// + /// Example: + /// \code + /// eval> f.get_arity() + /// 1 + /// eval> f2.get_arity() + /// -1 + /// \endcode + int get_arity() const; + + /// \brief Returns a vector of the contained functions + /// + /// Example: + /// \code + /// eval> f.get_contained_functions().size() + /// 0 + /// eval> f2.get_contained_functions().size() + /// 11 + /// eval> var v = f2.get_contained_functions(); + /// v[0].get_arity() + /// 2 + /// \endcode + Vector get_contained_functions() const; + + /// \brief Returns a vector of the contained functions + /// + /// Example: + /// \code + /// eval> f.get_guard() // Throws exception + /// Function does not have a guard + /// eval> f3.get_guard().get_arity() + /// 1 + /// \endcode + Function get_guard() const; + + /// \brief Returns a vector of Type_Info objects that represent the param types for this function. + /// The first value in the list is the return type. + /// + /// If this function is a conglomeration of several functions (get_contained_values().size() > 0) + /// then the function returns as many Type_Info objects as it can. If the functions contained all have + /// the same arity, then it represents the arity. If they have different arities, it returns only + /// one value - the return type. + /// + /// For each parameter that is the same type, the type is returned. If the types are different + /// then a Type_Info for Object is returned. + /// + /// Example: + /// \code + /// eval> f2.get_param_types().size(); // Returns a Type_Info for Object for the return type + /// 1 + /// \endcode + Vector get_param_types() const; + + /// \brief Returns true if the function has a guard to it. Always returns falls for a conglomerate function + bool has_guard() const; + + /// \brief Calls the function with the given set of parameters and returns the value; + /// + /// Example: + /// \code + /// eval> `-`.call([2,1]); + /// 1 + /// \endcode + Object call(Vector t_params) const; } + + /// \brief Returns the max of a or b. Requires that operator>(a, b) exists /// Equivalent to /// \code @@ -209,7 +599,7 @@ bool even(Object x); bool even(Object x); -/// \brief Applies the function f over each element in the Container c. +/// \brief Applies the function f over each element in the Range c. /// /// Example: /// \code @@ -218,20 +608,20 @@ bool even(Object x); /// 2 /// 3 /// \endcode -void for_each(Container c, Function f) +void for_each(Range c, Function f); -/// \brief Applies f over each element in the Container c, joining all the results. +/// \brief Applies f over each element in the Range c, joining all the results. /// /// Example: /// \code /// eval> map([1, 2, 3], odd) /// [true, false, true] /// \endcode -Container map(Container c, Function f) +Object map(Range c, Function f); -/// \brief Starts with the initial value and applies the function f to it and the first element of the Container c. +/// \brief Starts with the initial value and applies the function f to it and the first element of the Range c. /// The result is then applied to the second element, and so on until the elements are exhausted. /// /// Example: @@ -239,10 +629,10 @@ Container map(Container c, Function f) /// eval> foldl([1, 2, 3, 4], `+`, 0) /// 10 /// \endcode -Object foldl(Container c, Function f, Object initial) +Object foldl(Range c, Function f, Object initial); -/// \brief Returns the sum total of the values in the Container c. +/// \brief Returns the sum total of the values in the Range c. /// /// Example: /// \code @@ -254,10 +644,10 @@ Object foldl(Container c, Function f, Object initial) /// \code /// foldl(c, `+`, 0.0); /// \endcode -Numeric sum(Container c) +Numeric sum(Range c); -/// \brief Returns the product of the value in the Container c. +/// \brief Returns the product of the value in the Range c. /// /// Example: /// \code @@ -269,10 +659,10 @@ Numeric sum(Container c) /// \code /// foldl(c, `*`, 1.0); /// \endcode -Numeric product(Container c) +Numeric product(Range c); -/// \brief Takes num elements from the Container c, returning them. +/// \brief Takes num elements from the Range c, returning them. /// /// Example: /// \code @@ -281,10 +671,10 @@ Numeric product(Container c) /// \endcode /// /// \returns A container of the same type that was passed in -Object take(Container c, int num) +Object take(Range c, int num); -/// \brief Takes elements from the Container c that match function f, stopping at the first non-match, returning them as a new Vector. +/// \brief Takes elements from the Range c that match function f, stopping at the first non-match, returning them as a new Vector. /// /// Example: /// \code @@ -293,10 +683,10 @@ Object take(Container c, int num) /// \endcode /// /// \returns A container of the same type that was passed in -Object take_while(Container c, Function f) +Object take_while(Range c, Function f); -/// \brief Drops num elements from the Container c, returning the remainder. +/// \brief Drops num elements from the Range c, returning the remainder. /// /// Example: /// \code @@ -305,47 +695,47 @@ Object take_while(Container c, Function f) /// \endcode /// /// \returns A container of the same type that was passed in -Object drop(Container c, int num) +Object drop(Range c, int num); -/// \brief Drops elements from the Container c that match f, stopping at the first non-match, returning the remainder. +/// \brief Drops elements from the Range c that match f, stopping at the first non-match, returning the remainder. /// /// Example: /// \code /// eval> drop_while([1, 2, 3], odd) /// [2, 3] /// \endcode -Object drop_while(Container c, Function f) +Object drop_while(Range c, Function f); -/// \brief Similar to foldl, this takes the first two elements as its starting values for f. This assumes Container c has at least 2 elements. +/// \brief Similar to foldl, this takes the first two elements as its starting values for f. This assumes Range c has at least 2 elements. /// /// Example: /// \code /// eval> reduce([1, 2, 3, 4], `+`) /// 10 /// \endcode -Object reduce(Container c, Function f) +Object reduce(Range c, Function f); -/// \brief Takes elements from Container c that match function f, return them. +/// \brief Takes elements from Range c that match function f, return them. /// /// Example: /// \code /// eval> filter([1, 2, 3, 4], odd) /// [1, 3] /// \endcode -Object filter(Container c, Function f) +Object filter(Range c, Function f); -/// \brief Joins the elements of the Container c into a string, delimiting each with the delim string. +/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string. /// /// Example: /// \code /// eval> join([1, 2, 3], "*") /// 1*2*3 /// \endcode -string join(Container c, string delim) +string join(Range c, string delim); /// \brief Returns the contents of the Container c in reversed order. @@ -355,7 +745,7 @@ string join(Container c, string delim) /// eval> reverse([1, 2, 3, 4, 5, 6, 7]) /// [7, 6, 5, 4, 3, 2, 1] /// \endcode -Container reverse(Container c) +Container reverse(Container c); /// \brief Generates a new Vector filled with values starting at x and ending with y. @@ -367,17 +757,17 @@ Container reverse(Container c) /// eval> generate_range(1, 10) /// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] /// \endcode -Vector generate_range(Object x, Object y) +Vector generate_range(Object x, Object y); -/// \brief Returns a new Container with x and y concatenated. +/// \brief Returns a new Range with x and y concatenated. /// /// Example: /// \code /// eval> concat([1, 2, 3], [4, 5, 6]) /// [1, 2, 3, 4, 5, 6] /// \endcode -Object concat(Container x, Container y) +Object concat(Range x, Range y); /// \brief Returns a new Vector with x and y as its values. @@ -387,7 +777,7 @@ Object concat(Container x, Container y) /// eval> collate(1, 2) /// [1, 2] /// \endcode -Vector collate(x, y) +Vector collate(Object x, Object y); /// \brief Applies f to elements of x and y, returning a new Vector with the result of each application. @@ -397,7 +787,7 @@ Vector collate(x, y) /// eval> zip_with(`+`, [1, 2, 3], [4, 5, 6]) /// [5, 7, 9] /// \endcode -Vector zip_with(Function f, Container x, Container y) +Vector zip_with(Function f, Range x, Range y); /// \brief Collates elements of x and y, returning a new Vector with the result. @@ -407,8 +797,34 @@ Vector zip_with(Function f, Container x, Container y) /// eval> zip([1, 2, 3], [4, 5, 6]) /// [[1, 4], [2, 5], [3, 6]] /// \endcode -Vector zip(Container x, Container y) +Vector zip(Range x, Range y); +/// \brief returns true if there exists a call to the Function f that takes the given parameters +/// +/// Example: +/// \code +/// eval> call_exists(`+`, 1, 2) +/// true +/// \endcode +bool call_exists(Function f, ...); + +/// \brief Reverses a Range object so that the elements are accessed in reverse +Range retro(Range); + +/// \brief Reverses a Const_Range object so that the elements are accessed in reverse +Const_Range retro(Const_Range); + + +/// \brief Raises the given object as an exception. Any type of object can be thrown. +/// +/// Example: +/// \code +/// eval> try { throw(1); } catch (e) { print("Exception caught: " + to_string(e)); } +/// Exception caught: 1 +/// \endcode +/// +/// \sa \ref keywordtry +void throw(Object); }